Добавлены конфиги tmux и zsh

This commit is contained in:
eKa
2019-09-18 00:17:47 +05:00
commit 7d0a7691c6
882 changed files with 67305 additions and 0 deletions

View File

@@ -0,0 +1,19 @@
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.

View File

@@ -0,0 +1,142 @@
# Tmux copycat
[![Build Status](https://travis-ci.org/tmux-plugins/tmux-copycat.svg?branch=master)](https://travis-ci.org/tmux-plugins/tmux-copycat)
This plugin enables:
- regex searches
- search result highlighting
- predefined searches
Predefined searches are plugin killer feature. It speeds the workflow and
reduces mouse usage with Tmux.
It works even better when paired with
[tmux yank](https://github.com/tmux-plugins/tmux-yank). Tested and working on
Linux, OSX and Cygwin.
### Screencast
[![screencast screenshot](/video/screencast_img.png)](https://vimeo.com/101867689)
#### Search
- `prefix + /` - regex search (strings work too)
Example search entries:
- `foo` - searches for string `foo`
- `[0-9]+` - regex search for numbers
Grep is used for searching.<br/>
Searches are case insensitive.<br/>
#### Predefined searches
- `prefix + ctrl-f` - simple *f*ile search
- `prefix + ctrl-g` - jumping over *g*it status files (best used after `git status` command)
- `prefix + alt-h` - jumping over SHA-1/SHA-256 hashes (best used after `git log` command)
- `prefix + ctrl-u` - *u*rl search (http, ftp and git urls)
- `prefix + ctrl-d` - number search (mnemonic d, as digit)
- `prefix + alt-i` - *i*p address search
These start "copycat mode" and jump to first match.
#### "Copycat mode" bindings
These are enabled when you search with copycat:
- `n` - jumps to the next match
- `N` - jumps to the previous match
To copy a highlighted match:
- `Enter` - if you're using Tmux `vi` mode
- `ctrl-w` or `alt-w` - if you're using Tmux `emacs` mode
Copying a highlighted match will take you "out" of copycat mode. Paste with
`prefix + ]` (this is Tmux default paste).
Copying highlighted matches can be enhanced with
[tmux yank](https://github.com/tmux-plugins/tmux-yank).
### Installation with [Tmux Plugin Manager](https://github.com/tmux-plugins/tpm) (recommended)
Add plugin to the list of TPM plugins in `.tmux.conf`:
set -g @plugin 'tmux-plugins/tmux-copycat'
Hit `prefix + I` to fetch the plugin and source it. You should now be able to
use the plugin.
Optional (but recommended) install `gawk` via your package manager of choice
for better UTF-8 character support.
### Manual Installation
Clone the repo:
$ git clone https://github.com/tmux-plugins/tmux-copycat ~/clone/path
Add this line to the bottom of `.tmux.conf`:
run-shell ~/clone/path/copycat.tmux
Reload TMUX environment with: `$ tmux source-file ~/.tmux.conf`. You should now
be able to use the plugin.
Optional (but recommended) install `gawk` via your package manager of choice
for better UTF-8 character support.
### Installation for Tmux 2.3 and earlier
Due to the changes in tmux, the latest version of this plugin doesn't support
tmux 2.3 and earlier. It is recommended you upgrade to tmux version 2.4 or
later. If you must continue using older version, please follow
[these steps for installation](docs/installation_for_tmux_2.3.md).
### Limitations
This plugin has some known limitations. Please read about it
[here](docs/limitations.md).
### Docs
- Most of the behavior of tmux-copycat can be customized via tmux options.
[Check out the full options list](docs/customizations.md).
- To speed up the workflow you can define new bindings in `.tmux.conf` for
searches you use often, more info [here](docs/defining_new_stored_searches.md)
### Other goodies
`tmux-copycat` works great with:
- [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 a highlighted file or a url
- [tmux-continuum](https://github.com/tmux-plugins/tmux-continuum) - automatic
restoring and continuous saving of tmux env
### Test suite
This plugin has a pretty extensive integration test suite that runs on
[travis](https://travis-ci.org/tmux-plugins/tmux-copycat).
When run locally, it depends on `vagrant`. Run it with:
# within project top directory
$ ./run-tests
### Contributions and new features
Bug fixes and contributions are welcome.
Feel free to suggest new features, via github issues.
If you have a bigger idea you'd like to work on, please get in touch, also via
github issues.
### License
[MIT](LICENSE.md)

View File

@@ -0,0 +1,70 @@
#!/usr/bin/env bash
CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
source "$CURRENT_DIR/scripts/variables.sh"
source "$CURRENT_DIR/scripts/helpers.sh"
source "$CURRENT_DIR/scripts/stored_search_helpers.sh"
# this function defines default stored searches
set_default_stored_searches() {
local file_search="$(get_tmux_option "$copycat_file_search_option" "$default_file_search_key")"
local url_search="$(get_tmux_option "$copycat_url_search_option" "$default_url_search_key")"
local digit_search="$(get_tmux_option "$copycat_digit_search_option" "$default_digit_search_key")"
local hash_search="$(get_tmux_option "$copycat_hash_search_option" "$default_hash_search_key")"
local ip_search="$(get_tmux_option "$copycat_ip_search_option" "$default_ip_search_key")"
if stored_search_not_defined "$url_search"; then
tmux set-option -g "${COPYCAT_VAR_PREFIX}_${url_search}" "(https?://|git@|git://|ssh://|ftp://|file:///)[[:alnum:]?=%/_.:,;~@!#$&()*+-]*"
fi
if stored_search_not_defined "$file_search"; then
tmux set-option -g "${COPYCAT_VAR_PREFIX}_${file_search}" "(^|^\.|[[:space:]]|[[:space:]]\.|[[:space:]]\.\.|^\.\.)[[:alnum:]~_-]*/[][[:alnum:]_.#$%&+=/@-]*"
fi
if stored_search_not_defined "$digit_search"; then
tmux set-option -g "${COPYCAT_VAR_PREFIX}_${digit_search}" "[[:digit:]]+"
fi
if stored_search_not_defined "$hash_search"; then
tmux set-option -g "${COPYCAT_VAR_PREFIX}_${hash_search}" "\b([0-9a-f]{7,40}|[[:alnum:]]{52}|[0-9a-f]{62})\b"
fi
if stored_search_not_defined "$ip_search"; then
tmux set-option -g "${COPYCAT_VAR_PREFIX}_${ip_search}" "[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}"
fi
}
set_start_bindings() {
set_default_stored_searches
local stored_search_vars="$(stored_search_vars)"
local search_var
local key
local pattern
for search_var in $stored_search_vars; do
key="$(get_stored_search_key "$search_var")"
pattern="$(get_stored_search_pattern "$search_var")"
tmux bind-key "$key" run-shell "$CURRENT_DIR/scripts/copycat_mode_start.sh '$pattern'"
done
}
set_copycat_search_binding() {
local key_bindings
read -r -d '' -a key_bindings <<<"$(get_tmux_option "$copycat_search_option" "$default_copycat_search_key")"
local key
for key in "${key_bindings[@]}"; do
tmux bind-key "$key" run-shell "$CURRENT_DIR/scripts/copycat_search.sh"
done
}
set_copycat_git_special_binding() {
local key_bindings
read -r -d '' -a key_bindings <<<"$(get_tmux_option "$copycat_git_search_option" "$default_git_search_key")"
local key
for key in "${key_bindings[@]}"; do
tmux bind-key "$key" run-shell "$CURRENT_DIR/scripts/copycat_git_special.sh #{pane_current_path}"
done
}
main() {
set_start_bindings
set_copycat_search_binding
set_copycat_git_special_binding
}
main

View File

@@ -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

View File

@@ -0,0 +1,58 @@
#!/usr/bin/env bash
CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
source "$CURRENT_DIR/helpers.sh"
search_pattern="$1"
capture_pane() {
local file=$1
# copying 9M lines back will hopefully fetch the whole scrollback
tmux capture-pane -S -9000000 -p > "$file"
}
# doing 2 things in 1 step so that we don't write to disk too much
reverse_and_create_copycat_file() {
local file=$1
local copycat_file=$2
local grep_pattern=$3
(tac 2>/dev/null || tail -r) < "$file" | grep -oniE "$grep_pattern" > "$copycat_file"
}
delete_old_files() {
local scrollback_filename="$(get_scrollback_filename)"
local copycat_filename="$(get_copycat_filename)"
rm -f "$scrollback_filename" "$copycat_filename"
}
generate_copycat_file() {
local grep_pattern="$1"
local scrollback_filename="$(get_scrollback_filename)"
local copycat_filename="$(get_copycat_filename)"
mkdir -p "$(_get_tmp_dir)"
chmod 0700 "$(_get_tmp_dir)"
capture_pane "$scrollback_filename"
reverse_and_create_copycat_file "$scrollback_filename" "$copycat_filename" "$grep_pattern"
}
if_no_results_exit_with_message() {
local copycat_filename="$(get_copycat_filename)"
# check for empty filename
if ! [ -s "$copycat_filename" ]; then
display_message "No results!"
exit 0
fi
}
main() {
local grep_pattern="$1"
if not_in_copycat_mode; then
delete_old_files
generate_copycat_file "$grep_pattern"
if_no_results_exit_with_message
set_copycat_mode
copycat_increase_counter
fi
}
main "$search_pattern"

View File

@@ -0,0 +1,58 @@
#!/usr/bin/env bash
CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
PANE_CURRENT_PATH="$1"
source "$CURRENT_DIR/helpers.sh"
git_status_files() {
local git_working_dir="$PANE_CURRENT_PATH"
local git_dir="$PANE_CURRENT_PATH/.git"
echo "$(git --git-dir="$git_dir" --work-tree="$git_working_dir" status --porcelain)"
}
formatted_git_status() {
local raw_gist_status="$(git_status_files)"
echo "$(echo "$raw_gist_status" | cut -c 4-)"
}
exit_if_no_results() {
local results="$1"
if [ -z "$results" ]; then
display_message "No results!"
exit 0
fi
}
concatenate_files() {
local git_status_files="$(formatted_git_status)"
exit_if_no_results "$git_status_files"
local result=""
# Undefined until later within a while loop.
local file_separator
while read -r line; do
result="${result}${file_separator}${line}"
file_separator="|"
done <<< "$git_status_files"
echo "$result"
}
# Creates one, big regex out of git status files.
# Example:
# `git status` shows files `foo.txt` and `bar.txt`
# output regex will be:
# `(foo.txt|bar.txt)
git_status_files_regex() {
local concatenated_files="$(concatenate_files)"
local regex_result="(${concatenated_files})"
echo "$regex_result"
}
main() {
local search_regex="$(git_status_files_regex)"
# starts copycat mode
$CURRENT_DIR/copycat_mode_start.sh "$search_regex"
}
main

View File

@@ -0,0 +1,289 @@
#!/usr/bin/env bash
CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
source "$CURRENT_DIR/helpers.sh"
MAXIMUM_PADDING="25" # maximum padding below the result when it can't be centered
# jump to 'next' or 'prev' match
# global var for this file
NEXT_PREV="$1"
# 'vi' or 'emacs', this variable used as a global file constant
TMUX_COPY_MODE="$(tmux_copy_mode)"
_file_number_of_lines() {
local file="$1"
echo "$(wc -l $file | $AWK_CMD '{print $1}')"
}
_get_result_line() {
local file="$1"
local number="$2"
echo "$(head -"$number" "$file" | tail -1)"
}
_string_starts_with_digit() {
local string="$1"
echo "$string" |
\grep -q '^[[:digit:]]\+:'
}
_get_line_number() {
local string="$1"
local copycat_file="$2" # args 2 & 3 used to handle bug in OSX grep
local position_number="$3"
if _string_starts_with_digit "$string"; then
# we have a number!
local grep_line_number="$(echo "$string" | cut -f1 -d:)"
# grep line number index starts from 1, tmux line number index starts from 0
local tmux_line_number="$((grep_line_number - 1))"
else
# no number in the results line This is a bug in OSX grep.
# Fetching a number from a previous line.
local previous_line_num="$((position_number - 1))"
local result_line="$(_get_result_line "$copycat_file" "$previous_line_num")"
# recursively invoke this same function
tmux_line_number="$(_get_line_number "$result_line" "$copycat_file" "$previous_line_num")"
fi
echo "$tmux_line_number"
}
_get_match() {
local string="$1"
local full_match
if _string_starts_with_digit "$string"; then
full_match="$(echo "$string" | cut -f2- -d:)"
else
# This scenario handles OS X grep bug "no number in the results line".
# When there's no number at the beginning of the line, we're taking the
# whole line as a match. This handles the result line like this:
# `http://www.example.com` (the `http` would otherwise get cut off)
full_match="$string"
fi
echo -n "$full_match"
}
_escape_backslash() {
local string="$1"
echo "$(echo "$string" | sed 's/\\/\\\\/g')"
}
_get_match_line_position() {
local file="$1"
local line_number="$2"
local match="$3"
local adjusted_line_num=$((line_number + 1))
local result_line=$(tail -"$adjusted_line_num" "$file" | head -1)
# OS X awk cannot have `=` as the first char in the variable (bug in awk).
# If exists, changing the `=` character with `.` to avoid error.
local platform="$(uname)"
if [ "$platform" == "Darwin" ]; then
result_line="$(echo "$result_line" | sed 's/^=/./')"
match="$(echo "$match" | sed 's/^=/./')"
fi
# awk treats \r, \n, \t etc as single characters and that messes up match
# highlighting. For that reason, we're escaping backslashes so above chars
# are treated literally.
result_line="$(_escape_backslash "$result_line")"
match="$(_escape_backslash "$match")"
local index=$($AWK_CMD -v a="$result_line" -v b="$match" 'BEGIN{print index(a,b)}')
local zero_index=$((index - 1))
echo "$zero_index"
}
_copycat_jump() {
local line_number="$1"
local match_line_position="$2"
local match="$3"
local scrollback_line_number="$4"
_copycat_enter_mode
_copycat_exit_select_mode
_copycat_jump_to_line "$line_number" "$scrollback_line_number"
_copycat_position_to_match_start "$match_line_position"
_copycat_select "$match"
}
_copycat_enter_mode() {
tmux copy-mode
}
# clears selection from a previous match
_copycat_exit_select_mode() {
tmux send-keys -X clear-selection
}
# "manually" go up in the scrollback for a number of lines
_copycat_manually_go_up() {
local line_number="$1"
tmux send-keys -X -N "$line_number" cursor-up
tmux send-keys -X start-of-line
}
_copycat_create_padding_below_result() {
local number_of_lines="$1"
local maximum_padding="$2"
local padding
# Padding should not be greater than half pane height
# (it wouldn't be centered then).
if [ "$number_of_lines" -gt "$maximum_padding" ]; then
padding="$maximum_padding"
else
padding="$number_of_lines"
fi
# cannot create padding, exit function
if [ "$padding" -eq "0" ]; then
return
fi
tmux send-keys -X -N "$padding" cursor-down
tmux send-keys -X -N "$padding" cursor-up
}
# performs a jump to go to line
_copycat_go_to_line_with_jump() {
local line_number="$1"
# first jumps to the "bottom" in copy mode so that jumps are consistent
tmux send-keys -X history-bottom
tmux send-keys -X start-of-line
tmux send-keys -X goto-line $line_number
}
# maximum line number that can be reached via tmux 'jump'
_get_max_jump() {
local scrollback_line_number="$1"
local window_height="$2"
local max_jump=$((scrollback_line_number - $window_height))
# max jump can't be lower than zero
if [ "$max_jump" -lt "0" ]; then
max_jump="0"
fi
echo "$max_jump"
}
_copycat_jump_to_line() {
local line_number="$1"
local scrollback_line_number="$2"
local window_height="$(tmux display-message -p '#{pane_height}')"
local correct_line_number
local max_jump=$(_get_max_jump "$scrollback_line_number" "$window_height")
local correction="0"
if [ "$line_number" -gt "$max_jump" ]; then
# We need to 'reach' a line number that is not accessible via 'jump'.
# Introducing 'correction'
correct_line_number="$max_jump"
correction=$((line_number - $correct_line_number))
else
# we can reach the desired line number via 'jump'. Correction not needed.
correct_line_number="$line_number"
fi
_copycat_go_to_line_with_jump "$correct_line_number"
if [ "$correction" -gt "0" ]; then
_copycat_manually_go_up "$correction"
fi
# If no corrections (meaning result is not at the top of scrollback)
# we can then 'center' the result within a pane.
if [ "$correction" -eq "0" ]; then
local half_window_height="$((window_height / 2))"
# creating as much padding as possible, up to half pane height
_copycat_create_padding_below_result "$line_number" "$half_window_height"
fi
}
_copycat_position_to_match_start() {
local match_line_position="$1"
[ "$match_line_position" -eq "0" ] && return 0
tmux send-keys -X -N "$match_line_position" cursor-right
}
_copycat_select() {
local match="$1"
local length="${#match}"
tmux send-keys -X begin-selection
tmux send-keys -X -N "$length" cursor-right
if [ "$TMUX_COPY_MODE" == "vi" ]; then
tmux send-keys -X cursor-left # selection correction for 1 char
fi
}
# all functions above are "private", called from `do_next_jump` function
get_new_position_number() {
local copycat_file="$1"
local current_position="$2"
local new_position
# doing a forward/up jump
if [ "$NEXT_PREV" == "next" ]; then
local number_of_results=$(wc -l "$copycat_file" | $AWK_CMD '{ print $1 }')
if [ "$current_position" -eq "$number_of_results" ]; then
# position can't go beyond the last result
new_position="$current_position"
else
new_position="$((current_position + 1))"
fi
# doing a backward/down jump
elif [ "$NEXT_PREV" == "prev" ]; then
if [ "$current_position" -eq "1" ]; then
# position can't go below 1
new_position="1"
else
new_position="$((current_position - 1))"
fi
fi
echo "$new_position"
}
do_next_jump() {
local position_number="$1"
local copycat_file="$2"
local scrollback_file="$3"
local scrollback_line_number=$(_file_number_of_lines "$scrollback_file")
local result_line="$(_get_result_line "$copycat_file" "$position_number")"
local line_number=$(_get_line_number "$result_line" "$copycat_file" "$position_number")
local match=$(_get_match "$result_line")
local match_line_position=$(_get_match_line_position "$scrollback_file" "$line_number" "$match")
_copycat_jump "$line_number" "$match_line_position" "$match" "$scrollback_line_number"
}
notify_about_first_last_match() {
local current_position="$1"
local next_position="$2"
local message_duration="1500"
# if position didn't change, we are either on a 'first' or 'last' match
if [ "$current_position" -eq "$next_position" ]; then
if [ "$NEXT_PREV" == "next" ]; then
display_message "Last match!" "$message_duration"
elif [ "$NEXT_PREV" == "prev" ]; then
display_message "First match!" "$message_duration"
fi
fi
}
main() {
if in_copycat_mode; then
local copycat_file="$(get_copycat_filename)"
local scrollback_file="$(get_scrollback_filename)"
local current_position="$(get_copycat_position)"
local next_position="$(get_new_position_number "$copycat_file" "$current_position")"
do_next_jump "$next_position" "$copycat_file" "$scrollback_file"
notify_about_first_last_match "$current_position" "$next_position"
set_copycat_position "$next_position"
fi
}
main

View File

@@ -0,0 +1,55 @@
#!/usr/bin/env bash
CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
source "$CURRENT_DIR/helpers.sh"
AWK_CMD='awk'
if command_exists gawk; then
AWK_CMD='gawk'
fi
# Extends a keyboard key.
# Benefits: tmux won't report errors and everything will work fine even if the
# script is deleted.
extend_key() {
local key="$1"
local script="$2"
local cmd
# 1. 'cmd' or 'key' is sent to tmux. This ensures the default key action is done.
# 2. Script is executed.
# 3. `true` command ensures an exit status 0 is returned. This ensures a
# user never gets an error msg - even if the script file from step 2 is
# deleted.
# We fetch the current behavior of the 'key' mapping in
# variable 'cmd'
cmd=$(tmux list-keys -T $(tmux_copy_mode_string) | $AWK_CMD '$4 == "'$key'"' | $AWK_CMD '{ $1=""; $2=""; $3=""; $4=""; sub(" ", " "); print }')
# If 'cmd' is already a copycat command, we do nothing
if echo "$cmd" | grep -q copycat; then
return
fi
# We save the previous mapping to a file in order to be able to recover
# the previous mapping when we unbind
tmux list-keys -T $(tmux_copy_mode_string) | $AWK_CMD '$4 == "'$key'"' >> "${TMPDIR:-/tmp}/copycat_$(whoami)_recover_keys"
tmux bind-key -T $(tmux_copy_mode_string) "$key" run-shell "tmux $cmd; $script; true"
}
copycat_cancel_bindings() {
# keys that quit copy mode are enhanced to quit copycat mode as well.
local cancel_mode_bindings=$(copycat_quit_copy_mode_keys)
local key
for key in $cancel_mode_bindings; do
extend_key "$key" "$CURRENT_DIR/copycat_mode_quit.sh"
done
}
copycat_mode_bindings() {
extend_key "$(copycat_next_key)" "$CURRENT_DIR/copycat_jump.sh 'next'"
extend_key "$(copycat_prev_key)" "$CURRENT_DIR/copycat_jump.sh 'prev'"
}
main() {
copycat_mode_bindings
copycat_cancel_bindings
}
main

View File

@@ -0,0 +1,38 @@
#!/usr/bin/env bash
CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
source "$CURRENT_DIR/helpers.sh"
unbind_cancel_bindings() {
local cancel_mode_bindings=$(copycat_quit_copy_mode_keys)
local key
for key in $cancel_mode_bindings; do
tmux unbind-key -n "$key"
done
}
unbind_prev_next_bindings() {
tmux unbind-key -n "$(copycat_next_key)"
tmux unbind-key -n "$(copycat_prev_key)"
}
unbind_all_bindings() {
grep -v copycat <"${TMPDIR:-/tmp}/copycat_$(whoami)_recover_keys" | while read -r key_cmd; do
sh -c "tmux $key_cmd"
done < /dev/stdin
rm "${TMPDIR:-/tmp}/copycat_$(whoami)_recover_keys"
}
main() {
if in_copycat_mode; then
reset_copycat_position
unset_copycat_mode
copycat_decrease_counter
# removing all bindings only if no panes are in copycat mode
if copycat_counter_zero; then
unbind_all_bindings
fi
fi
}
main

View File

@@ -0,0 +1,21 @@
#!/usr/bin/env bash
CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
SUPPORTED_VERSION="1.9"
PATTERN="$1"
supported_tmux_version_ok() {
$CURRENT_DIR/check_tmux_version.sh "$SUPPORTED_VERSION"
}
main() {
local pattern="$1"
if supported_tmux_version_ok; then
$CURRENT_DIR/copycat_generate_results.sh "$pattern" # will `exit 0` if no results
$CURRENT_DIR/copycat_mode_bindings.sh
$CURRENT_DIR/copycat_jump.sh 'next'
fi
}
main "$PATTERN"

View File

@@ -0,0 +1,8 @@
#!/usr/bin/env bash
CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
main() {
tmux command-prompt -p "copycat search:" "run-shell \"$CURRENT_DIR/copycat_mode_start.sh '%1'\""
}
main

View File

@@ -0,0 +1,192 @@
# config options
default_next_key="n"
tmux_option_next="@copycat_next"
default_prev_key="N"
tmux_option_prev="@copycat_prev"
# keeps track of number of panes in copycat mode
tmux_option_counter="@copycat_counter"
# === awk vs gawk ===
command_exists() {
command -v "$@" > /dev/null 2>&1
}
AWK_CMD='awk'
if command_exists gawk; then
AWK_CMD='gawk'
fi
# === general helpers ===
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
}
set_tmux_option() {
local option=$1
local value=$2
tmux set-option -gq "$option" "$value"
}
tmux_copy_mode() {
tmux show-option -gwv mode-keys
}
tmux_copy_mode_string() {
if [ $(tmux_copy_mode) == 'vi' ]; then
echo copy-mode-vi
else
echo copy-mode
fi
}
# === copycat mode specific helpers ===
set_copycat_mode() {
set_tmux_option "$(_copycat_mode_var)" "true"
}
unset_copycat_mode() {
set_tmux_option "$(_copycat_mode_var)" "false"
}
in_copycat_mode() {
local copycat_mode=$(get_tmux_option "$(_copycat_mode_var)" "false")
[ "$copycat_mode" == "true" ]
}
not_in_copycat_mode() {
if in_copycat_mode; then
return 1
else
return 0
fi
}
# === copycat mode position ===
get_copycat_position() {
local copycat_position_variable=$(_copycat_position_var)
echo $(get_tmux_option "$copycat_position_variable" "0")
}
set_copycat_position() {
local position="$1"
local copycat_position_variable=$(_copycat_position_var)
set_tmux_option "$copycat_position_variable" "$position"
}
reset_copycat_position() {
set_copycat_position "0"
}
# === scrollback and results position ===
get_scrollback_filename() {
echo "$(_get_tmp_dir)/scrollback-$(_pane_unique_id)"
}
get_copycat_filename() {
echo "$(_get_tmp_dir)/results-$(_pane_unique_id)"
}
# 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"
}
# === counter functions ===
copycat_increase_counter() {
local count=$(get_tmux_option "$tmux_option_counter" "0")
local new_count="$((count + 1))"
set_tmux_option "$tmux_option_counter" "$new_count"
}
copycat_decrease_counter() {
local count="$(get_tmux_option "$tmux_option_counter" "0")"
if [ "$count" -gt "0" ]; then
# decreasing the counter only if it won't go below 0
local new_count="$((count - 1))"
set_tmux_option "$tmux_option_counter" "$new_count"
fi
}
copycat_counter_zero() {
local count="$(get_tmux_option "$tmux_option_counter" "0")"
[ "$count" -eq "0" ]
}
# === key binding functions ===
copycat_next_key() {
echo "$(get_tmux_option "$tmux_option_next" "$default_next_key")"
}
copycat_prev_key() {
echo "$(get_tmux_option "$tmux_option_prev" "$default_prev_key")"
}
# function expected output: 'C-c Enter q'
copycat_quit_copy_mode_keys() {
local commands_that_quit_copy_mode="cancel"
local copy_mode="$(tmux_copy_mode_string)"
tmux list-keys -T "$copy_mode" |
\grep "$commands_that_quit_copy_mode" |
$AWK_CMD '{ print $4 }' |
sort -u |
sed 's/C-j//g' |
xargs echo
}
# === 'private' functions ===
_copycat_mode_var() {
local pane_id="$(_pane_unique_id)"
echo "@copycat_mode_$pane_id"
}
_copycat_position_var() {
local pane_id="$(_pane_unique_id)"
echo "@copycat_position_$pane_id"
}
_get_tmp_dir() {
echo "${TMPDIR:-/tmp}/tmux-$EUID-copycat"
}
# returns a string unique to current pane
# sed removes `$` sign because `session_id` contains is
_pane_unique_id() {
tmux display-message -p "#{session_id}-#{window_index}-#{pane_index}" |
sed 's/\$//'
}

View File

@@ -0,0 +1,23 @@
stored_search_not_defined() {
local key="$1"
local search_value="$(tmux show-option -gqv "${COPYCAT_VAR_PREFIX}_${key}")"
[ -z $search_value ]
}
stored_search_vars() {
tmux show-options -g |
\grep -i "^${COPYCAT_VAR_PREFIX}_" |
cut -d ' ' -f1 | # cut just variable names
xargs # splat var names in one line
}
# get the search key from the variable name
get_stored_search_key() {
local search_var="$1"
echo "$(echo "$search_var" | sed "s/^${COPYCAT_VAR_PREFIX}_//")"
}
get_stored_search_pattern() {
local search_var="$1"
echo "$(get_tmux_option "$search_var" "")"
}

View File

@@ -0,0 +1,26 @@
# stored search variable prefix
COPYCAT_VAR_PREFIX="@copycat_search"
# basic search
default_copycat_search_key="/"
copycat_search_option="@copycat_search"
# git special search
default_git_search_key="C-g"
copycat_git_search_option="@copycat_git_special"
# regular searches
default_file_search_key="C-f"
copycat_file_search_option="@copycat_file_search"
default_url_search_key="C-u"
copycat_url_search_option="@copycat_url_search"
default_digit_search_key="C-d"
copycat_digit_search_option="@copycat_digit_search"
default_hash_search_key="M-h"
copycat_hash_search_option="@copycat_hash_search"
default_ip_search_key="M-i"
copycat_ip_search_option="@copycat_ip_search"