Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
dc08bef
sh: Add option to target one particular tmux pane
Matt-A-Bennett Jan 5, 2022
c110afa
sh: Func sortu() to keep duplicate lines if NOSORT
Matt-A-Bennett Jan 5, 2022
4413f49
Add functions to capture pane to buffer (needs integrating)
Matt-A-Bennett Jan 5, 2022
4ed0107
Name new functions correctly: plugin#function()
Matt-A-Bennett Jan 5, 2022
5758aa2
Merge pull request #1 from Matt-A-Bennett/just_to_play
Matt-A-Bennett Jan 5, 2022
6128c12
Use s:script variable for path to script
Matt-A-Bennett Jan 5, 2022
5137f0f
Just echo target pane rather than grepping for it
Matt-A-Bennett Jan 5, 2022
d3ec897
Add global option for tmux pane index display
Matt-A-Bennett Jan 5, 2022
0f01ffe
Fix Accidental deletion of tmuxcomplete#init()...
Matt-A-Bennett Jan 5, 2022
a52273d
Add comment in script for global user option
Matt-A-Bennett Jan 5, 2022
694039c
Add description and usage of new functionality
Matt-A-Bennett Jan 5, 2022
ab6588a
Fix accidental file name change
Matt-A-Bennett Jan 5, 2022
195a295
Update README.md
Matt-A-Bennett Jan 5, 2022
59f1bdf
Show how to map the tmux_pane_to_buffer function
Matt-A-Bennett Jan 5, 2022
e3fb432
Update README.md
Matt-A-Bennett Jan 5, 2022
a7d5a7b
Update README.md
Matt-A-Bennett Jan 5, 2022
0af8be6
Update README.md
Matt-A-Bennett Jan 5, 2022
952c45b
test
Matt-A-Bennett Jan 6, 2022
c2cd587
rm test
Matt-A-Bennett Jan 6, 2022
7dcfddf
Don't overide user g:tmuxcomplete_pane_index_display_duration_ms
Matt-A-Bennett Aug 12, 2022
f8a5227
tmp
Matt-A-Bennett Aug 12, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 51 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
# tmux-complete.vim

Vim plugin for insert mode completion of words in adjacent tmux panes
Vim plugin for insert mode completion of words in adjacent tmux panes and
duplicating the contents of a visible tmux pane in a split buffer.

## Motivation

If you're using Vim in tandem with Tmux you might be familiar with this pesky
situation:

You're happily editing your lovely files in Vim, when you notice you need to
type a word that you can see in a different Tmux pane right next to Vim. This
might be some secret key found in your REPL or the name of a failing test.
type a word, or a chunk of text, that you can see in a different Tmux pane
right next to Vim. This might be some secret key found in your REPL or the name
of a failing test.

Usually the interesting text is too short to warrant switching panes and going
into Tmux' copy mode, so you end typing it out again.
Usually the interesting text is too short, to warrant switching panes and going
into Tmux's copy mode, so you end up typing it out again.

## But fear no longer!
Or maybe You just don't like using Tmux's copy mode, period. You feel like that
chunk of text sitting in a distant Tmux pane ought to be just as accessible to
you as a chunk of text sitting in a Vim buffer.

## Well, fear no longer!

This plugin adds a completion function that puts all words visible in your Tmux
panes right under your fingertips. Just enter insert mode, start typing any
Expand All @@ -32,6 +38,30 @@ MacVim!
[example]: https://raw.githubusercontent.com/wellle/images/master/tmux-complete-example.png
[gvim]: https://raw.githubusercontent.com/wellle/images/master/gvim-complete.png

There is also a function that copies all the text visible in a particular tmux
pane directly into a new split buffer in your Vim instance!

Simply call the function like so:

```vim
:call tmuxcomplete#tmux_pane_to_buffer()
```

Or map it to something convienient:

```vim
nnoremap <LEADER>t :call tmuxcomplete#tmux_pane_to_buffer()<CR>
```

After the function is called, the tmux pane indices are flashed for a brief moment. Then just type the number to specify the pane you want and hit enter:

![pane_selection](https://user-images.githubusercontent.com/52209396/148301300-c4b002d6-6362-4e81-b1a0-52277088a51c.jpg)


Here I typed '2', ad it's right there, ready to be bent to Vim's will:

![pane_2](https://user-images.githubusercontent.com/52209396/148301308-2f8db950-498c-442c-84e4-d354f94dbcec.jpg)

## Third party integration

Tmux complete is automatically integrated with the following plugins:
Expand Down Expand Up @@ -196,3 +226,18 @@ tmux-complete by putting one of these lines into your `.vimrc`:

The trigger function itself is named `tmuxcomplete#complete` (in case you want
to call it manually).

- When copying the text in a Tmux pane to a Vim buffer, Tmux is instructed to
briefly flash the pane indexes for 350ms to aid in your choice. To disable this
behavior, put this in your .vimrc:

```vim
let g:tmuxcomplete_pane_index_display_duration_ms = 0
```

- Or set it to a different duration (as a string):

```vim
let g:tmuxcomplete_pane_index_display_duration_ms = "1000"
```

22 changes: 22 additions & 0 deletions autoload/tmuxcomplete.vim
Original file line number Diff line number Diff line change
Expand Up @@ -133,4 +133,26 @@ function! tmuxcomplete#gather_candidates()
return tmuxcomplete#completions('', s:capture_args, 'words')
endfunction

function! tmuxcomplete#display_tmux_pane_indices(duration)
" bring up the pane numbers as a background job
call job_start(["tmux", "display-pane", "-d", a:duration])
endfunction

function! tmuxcomplete#tmux_pane_to_buffer()
if g:tmuxcomplete_pane_index_display_duration_ms > 0
call tmuxcomplete#display_tmux_pane_indices(g:tmuxcomplete_pane_index_display_duration_ms)
endif
" get the input from user
let targetpane = input("target_pane:")
if targetpane =~ '\d\+'
silent execute 'split .tmux_pane_'.targetpane
silent execute '%!sh '.s:script.' -t '.targetpane.' -s lines -n'
set filetype=bash
setlocal buftype=nofile
setlocal bufhidden=hide
setlocal noswapfile
setlocal nobuflisted
endif
endfunction

call tmuxcomplete#init()
6 changes: 6 additions & 0 deletions plugin/tmuxcomplete.vim
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ function! s:init()
if exists('g:loaded_compe')
lua require'compe'.register_source('tmux', require'compe_tmux')
endif

if !exists('g:tmuxcomplete_pane_index_display_duration_ms')
" for use with tmuxcomplete#tmux_pane_to_buffer()
let g:tmuxcomplete_pane_index_display_duration_ms = "350"
endif

endfunction

call s:init()
14 changes: 11 additions & 3 deletions sh/tmuxcomplete
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
# Words visible in current window, excluding current pane
# sh tmuxcomplete -e
#
# Words visible in specified pane in current window
# (can't be used alongside the -e option)
# sh tmuxcomplete -t <pane_idex>
#
# Words visible in current session
# sh tmuxcomplete -l '-s'
#
Expand Down Expand Up @@ -35,21 +39,23 @@ fi

EXCLUDE='0'
NOSORT='0'
TARGET='-1'
PATTERN=''
SPLITMODE=words
LISTARGS=''
CAPTUREARGS=''
GREPARGS=''
while getopts enp:s:l:c:g: name
while getopts enp:s:t:l:c:g: name
do case $name in
e) EXCLUDE="1";;
n) NOSORT="1";; # internal/undocumented, don't use, might be changed in the future
t) TARGET="$OPTARG";;
p) PATTERN="$OPTARG";;
s) SPLITMODE="$OPTARG";;
l) LISTARGS="$OPTARG";;
c) CAPTUREARGS="$OPTARG";;
g) GREPARGS="$OPTARG";;
*) echo "Usage: $0 [-p pattern] [-s splitmode] [-l listargs] [-c captureargs] [-g grepargs]\n"
*) echo "Usage: $0 [-t <pane_index>] [-p pattern] [-s splitmode] [-l listargs] [-c captureargs] [-g grepargs]\n"
exit 2;;
esac
done
Expand All @@ -64,6 +70,8 @@ excludecurrent() {
# echo 1>&2 'current' "$currentpane"
# use -F to match $ in session id
grep -v -F "$currentpane"
elif ! [ "$TARGET" = "-1" ]; then
echo $(tmux display-message -p '01-#{session_id} ')$TARGET
else
cat
fi
Expand Down Expand Up @@ -155,7 +163,7 @@ splitwords() {

sortu() {
if [ "$NOSORT" = "1" ]; then
uniq
cat
else
sort -u
fi
Expand Down
185 changes: 185 additions & 0 deletions tmuxcomplete
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
#!/bin/sh

# Usage: Get a list of all words visible in current window
# sh tmuxcomplete
#
# Words visible in current window, excluding current pane
# sh tmuxcomplete -e
#
# Words visible in specified pane in current window
# (can't be used alongside the -e option)
# sh tmuxcomplete -t <pane_idex>
#
# Words visible in current session
# sh tmuxcomplete -l '-s'
#
# Words visible in all sessions
# sh tmuxcomplete -l '-a'
#
# Words containing 'foo'
# sh tmuxcomplete -p 'foo'
#
# List of lines
# sh tmuxcomplete -s lines
#
# Words containing 'foo', ignoring case
# sh tmuxcomplete -p 'foo' -g '-i'
#
# Words beginning with 'foo'
# sh tmuxcomplete -p '^foo'
#
# Words including 2000 lines of history per pane
# sh tmuxcomplete -c '-S -2000'

if ! tmux info > /dev/null 2>&1; then
echo "[tmux-complete.vim]"
echo "No tmux found!"
exit 0
fi

EXCLUDE='0'
NOSORT='0'
TARGET='-1'
PATTERN=''
SPLITMODE=words
LISTARGS=''
CAPTUREARGS=''
GREPARGS=''
while getopts enp:s:t:l:c:g: name
do case $name in
e) EXCLUDE="1";;
n) NOSORT="1";; # internal/undocumented, don't use, might be changed in the future
t) TARGET="$OPTARG";;
p) PATTERN="$OPTARG";;
s) SPLITMODE="$OPTARG";;
l) LISTARGS="$OPTARG";;
c) CAPTUREARGS="$OPTARG";;
g) GREPARGS="$OPTARG";;
*) echo "Usage: $0 [-t <pane_index>] [-p pattern] [-s splitmode] [-l listargs] [-c captureargs] [-g grepargs]\n"
exit 2;;
esac
done

listpanes() {
tmux list-panes $LISTARGS -F '#{pane_active}#{window_active}-#{session_id} #{pane_id}'
}

excludecurrent() {
if [ "$EXCLUDE" = "1" ]; then
currentpane=$(tmux display-message -p '11-#{session_id} ')
# echo 1>&2 'current' "$currentpane"
# use -F to match $ in session id
grep -v -F "$currentpane"
elif ! [ "$TARGET" = "-1" ]; then
echo $(tmux display-message -p '01-#{session_id} ')$TARGET
else
cat
fi
}

paneids() {
cut -d' ' -f2
}

capturepanes() {
panes=$(cat)
if [ -z "$panes" ]; then
# echo 'no panes' 1>&2
return
elif tmux capture-pane -p >/dev/null 2>&1; then
# tmux capture-pane understands -p -> use it
echo "$panes" | xargs -n1 tmux capture-pane $CAPTUREARGS -p -t
else
# tmux capture-pane doesn't understand -p (like version 1.6)
# -> capture to paste-buffer, echo it, then delete it
echo "$panes" | xargs -n1 -I{} sh -c "tmux capture-pane $CAPTUREARGS -t {} && tmux show-buffer && tmux delete-buffer"
fi
}

split() {
if [ "$SPLITMODE" = "ilines,words" ]; then
# this is most reabable, but not posix compliant
# tee >(splitilines) >(splitwords)

# from https://unix.stackexchange.com/a/43536
# this has some issues with trailing whitespace sometimes
# tmp_dir=$(mktemp -d)
# mkfifo "$tmp_dir/f1" "$tmp_dir/f2"
# splitilines <"$tmp_dir/f1" & pid1=$!
# splitwords <"$tmp_dir/f2" & pid2=$!
# tee "$tmp_dir/f1" "$tmp_dir/f2"
# rm -rf "$tmp_dir"
# wait $pid1 $pid2

splitilinesandwords
elif [ "$SPLITMODE" = "lines" ]; then
splitlines
elif [ "$SPLITMODE" = "ilines" ]; then
splitilines
elif [ "$SPLITMODE" = "words" ]; then
splitwords
fi
}

splitilinesandwords() {
# print full line to duplicate it
# on the duplicate substitute all spaces with newlines
# duplicate that result again
# in that duplicate replace all non word characters by linebreaks
sed -e 'p;s/[[:space:]]\{1,\}/\
/g;p;s/[^a-zA-Z0-9_]\{1,\}/\
/g' |
# remove surrounding non-word characters
grep -o "\\w.*\\w"
}

splitlines() {
# remove surrounding whitespace
grep -o "\\S.*\\S"
}

splitilines() {
# starts at first word character
grep -o "\\w.*\\S"
}

# returns both WORDS and words of each given line
splitwords() {
# use sed like this instead of tr?
# substitute all spaces with newlines
# duplicate that line
# in the duplicate replace all non word characters by linebreaks
# sed -e 's/[[:space:]]\{1,\}/\
# /g;p;s/[^a-zA-Z0-9_]/ /g;s/[[:space:]]\{1,\}/\
# /g' |

# copy lines and split words
sed -e 'p;s/[^a-zA-Z0-9_]/ /g' |
# split on spaces
tr -s '[:space:]' '\n' |
# remove surrounding non-word characters
grep -o "\\w.*\\w"
}

sortu() {
if [ "$NOSORT" = "1" ]; then
cat
else
sort -u
fi
}

# list all panes
listpanes |
# filter out current pane
excludecurrent |
# take the pane id
paneids |
# capture panes
capturepanes |
# split words or lines depending on splitmode
split |
# filter out items not matching pattern
grep -e "$PATTERN" $GREPARGS |
# sort and remove duplicates
sortu