-
-
Save nkh/d53717d26c425fd4e954fba241ec41e4 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# prompt matching function for tmux | |
# it can be also defined elsewhere | |
if ! type -t __copy_app_match_my_prompt 1> /dev/null ; then | |
__copy_app_match_my_prompt() { printf '^(\\\\033\\[[^m]+m)?[[:digit:]]+\ ' ; } # the way it looks for me in a tmux buffer | |
fi | |
last_command() { history -p !! | perl -pe 's/^\s*[0-9]+\s*//' | tr -d '\n' ; } | |
extract_last_command_from_tmux_buffer() | |
{ | |
# extract last command and its output from tmux buffer | |
# code can skip section, although it doesn't in this case | |
read -r -d '' perl_code << 'EOP' | |
use warnings ; | |
use strict ; | |
my ($regex, $display_last_line) = @ARGV ; | |
my ($skipping_blocks, $started) = (0, 0) ; | |
LINE: | |
while (<STDIN>) | |
{ | |
if ($skipping_blocks) | |
{ | |
$skipping_blocks-- if /$regex/ ; | |
} | |
else | |
{ | |
if (! $started) | |
{ | |
#skip the line | |
$started++ if /$regex/ ; | |
} | |
else | |
{ | |
if(/$regex/) | |
{ | |
print if $display_last_line ; | |
last LINE ; | |
} | |
else | |
{ | |
print ; | |
} | |
} | |
} | |
} | |
EOP | |
cat | perl -e "$perl_code" "$(__copy_app_match_my_prompt)" "$1" | |
} | |
grab_tmux_pane() | |
{ | |
local last_command=false last_command_command=0 ansi_codes= | |
local PARSING=`getopt -o alc --long help -n 'copy' -- "$@"` | |
eval set -- "$PARSING" | |
while true ; do | |
case $1 in | |
-h | --help) echo "Usage: grab_tmux_pane [-l -a]" | |
printf "\tgrabs and writes the contents of the tmux pane on stdout\n" | |
printf "\n" | |
printf "\t-a\tgrab ansi codes too\n" | |
printf "\t-l\tgrab last command output\n" | |
printf "\t-c\tif -l, include the command\n" | |
printf "\t\tyou will need to define a match_my_prompt function\n" | |
return ;; | |
-l ) last_command=true ; shift ;; | |
-c ) last_command_command=1 ; shift ;; | |
-a ) ansi_codes=" -e " ; shift ;; | |
-- ) shift ; break ;; | |
* ) echo "Internal error while parsing!" ; exit 1 ;; | |
esac | |
done | |
tmux capture-pane -b grab_tmux_pane $ansi_codes -C -J -S - -E - | |
tmux save-buffer -b grab_tmux_pane /tmp/grab_tmux_pane | |
tmux delete-buffer -b grab_tmux_pane | |
if $last_command ; then | |
tac /tmp/grab_tmux_pane | extract_last_command_from_tmux_buffer $last_command_command | tac | |
else | |
cat /tmp/grab_tmux_pane | |
fi | |
} | |
copy_help() | |
{ | |
cat << 'EOH' | |
NAME | |
copy - copies text, a file content, or a command output, to the clipboad | |
SYNOPSIS | |
command | copy [options] | |
copy [options --] [command/file/text] | |
DESCRIPTION | |
$ echo "a text" | copy stdin is copied to the clipboard | |
$ copy some random text copies "some random text" to the clipboad | |
$ copy file copies content of the file to the clipboard | |
$ copy command arg arg copies the output of $(command arg arg) | |
$ copy -- command -opt arg copies the output of $(command -opt arg), use -- | |
so the options go to the command not copy | |
# in tmmux, grab the output of the last command and the command too | |
# display how copy copied to the clipboard | |
$ copy -m -- grab_tmux_pane -l -c | |
OPTIONS | |
-m display message about the operation | |
-t trim new line from output | |
--file copy file content even if it is executable | |
--text copy as text even it matches a file name | |
--help display this help | |
SEE ALSO | |
original idea from http://brettterpstra.com/2015/04/27/a-universal-clipboard-command-for-bash/ | |
EOH | |
} | |
copy() | |
{ | |
local file= text= trim_nl=false display_message=false | |
local PARSING=`getopt -o htm --long help,file,text -n 'copy' -- "$@"` | |
eval set -- "$PARSING" | |
while true ; do | |
case $1 in | |
-h | --help) copy_help ; return ;; | |
--file ) file=true ; shift ;; | |
--text ) text=true ; shift ;; | |
-t ) trim_nl=true ; shift ;; | |
-m ) display_message=true ; shift ;; | |
-- ) shift ; break ;; | |
* ) echo "Internal error while parsing!" ; exit 1 ;; | |
esac | |
done | |
[[ $1 = "--" ]] && shift | |
local output | |
local res=false | |
local tmpfile="${TMPDIR}/copy.$RANDOM.txt" | |
local msg="" | |
if [[ $# == 0 ]]; then | |
output=$(cat) | |
msg="Input copied to clipboard" | |
res=true | |
else | |
local cmd="" | |
for arg in $@; do | |
cmd+="\"$(echo -en $arg|sed -E 's/"/\\"/g')\" " | |
done | |
command_type=$(type "$1" 2> /dev/null) | |
if [[ $? == 0 && -z $file ]] ; then | |
output=$(eval "$cmd" 2>&1 /dev/null) | |
if [[ $? == 0 ]]; then | |
msg="Results of command '$@' are in the clipboard" | |
res=true | |
else | |
msg="Error running command '$@', $command_type" | |
res=false | |
fi | |
else | |
if [[ -f $1 && -z $text ]]; then | |
output="" | |
for arg in $@; do | |
if [[ -f $arg ]]; then | |
type=`file "$arg"|grep -c text` | |
if [ $type -gt 0 ]; then | |
output+=$(cat $arg) | |
msg+="Contents of '$arg' are in the clipboard" | |
res=true | |
else | |
msg+="File '$arg' is not plain text" | |
fi | |
fi | |
done | |
else | |
output=$@ | |
msg="Text copied to clipboard" | |
res=true | |
fi | |
fi | |
fi | |
if $res ; then | |
if $trim_nl ; then | |
echo -ne "$output" | tr -d '\n' | xsel -i -p -s -b | |
else | |
echo -ne "$output" | xsel -i -p -s -b | |
fi | |
$display_message && echo -e "$msg" | |
return 0 | |
else | |
echo -e "$msg" | |
return 1 | |
fi | |
} | |
copy-cleanup() | |
{ | |
while read x; do unset -f $x; done << EOF | |
last_command | |
extract_last_command_from_tmux_buffer | |
grab_tmux_pane | |
minimum_version | |
copy_help | |
copy | |
copy-cleanup | |
EOF | |
} | |
minimum_version() | |
{ | |
current_version="$1" minimum_version="$2" | |
newest_version=$(echo -e "$current_version\n$minimum_version" | sed '/^$/d' | sort -nrb | head -1) | |
if [[ "$newest_version" = "$current_version" ]] ; then true ; else false ; fi | |
} | |
_bgc_copy () { COMPREPLY=( $( compgen -W 'last_command grab_tmux_pane' -- ${COMP_WORDS[COMP_CWORD]} ) $( compgen -o default -- ${COMP_WORDS[COMP_CWORD]} | sort -n ) ) ; } | |
if minimum_version "$BASH_VERSION" '4.4' ; then | |
complete -o nosort -F '_bgc_copy' 'copy' | |
else | |
complete -F '_bgc_copy' 'copy' | |
fi | |
[[ "${BASH_SOURCE[0]}" = "${0}" ]] && copy $@ | |
copy-cleanup | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment