Control a pager (like the less program) from an ex

2019-07-14 18:51发布

In this question I am exploring how to go about monitoring my project directory for changes so that I can keep a terminal that shows an always up-to-date git diff so that I can skip typing git diff over and over into the shell and further streamline my workflow.

Supposing that I have a sufficiently intelligent tool that knows exactly when the filesystem has changed, how can I go about disrupting the display of git diff? The ultimate solution would be able to figure out where the current display is scrolled to, and re-scroll to the same position (where reasonable, as everything could potentially have been changed, of course). I'm sure there's a way to find out how far down in the buffer you are with less and then pass that along with the new instance of it.

But the question here is how do I programmatically control an interface that is also interactive? Is this something that is possible to do? Could I make use of certain heavy-duty tools like tmux, to send input into the program? In my experience of customizing tmux to do many things it does have the ability to receive commands from the shell and also to execute shell commands, and it does have a command which sends keys.

1条回答
Bombasti
2楼-- · 2019-07-14 19:11

What's this? a close vote? Maybe somebody thought this couldn't be done. ;)

I present to you the full solution (you can find the most up to date versions on github):

~/util/git-diff-puppet:

#!/bin/sh

# This script runs git diff through tmux at the current directory, so that you can
# interactively scroll it. Listens for changes to the filesystem at this directory
# and tmux is used to issue commands to reload the diff.
set -e
[[ -f .tmp_git_diff ]] && echo "found .tmp_git_diff, exiting" && exit -1
# save the current git diff string to use for comparison
git diff > .tmp_git_diff
function cleanup {
    kill $FSWATCHPID
    rm .tmp_git_diff
    tmux kill-session -t git-diff-puppet
}
trap cleanup EXIT
tmux new-session -d -s git-diff-puppet sh
tmux send-keys -t git-diff-puppet "git diff" enter
fswatch . ~/util/git-diff-puppet-onchange &
FSWATCHPID=$!
tmux attach -t git-diff-puppet
echo "tmux finished: puppet script exiting"

~/util/git-diff-puppet-onchange:

#!/bin/sh

# This script is not for invoking directly. It is for use in conjunction (as a "callback") with
# git-diff-puppet: this script will be looking for the .tmp_git_diff file
set -e

[[ ! -f .tmp_git_diff ]] && echo ".tmp_git_diff not found; i was probably invoked in error, aborting" && exit 1
# diffing the current diff with the saved diff to see if we should re-show the git diff in tmux
if ! git diff | diff - .tmp_git_diff > /dev/null; then
    tmux send-keys -t git-diff-puppet q "git diff" enter
    git diff > .tmp_git_diff
fi

It is glorious. Instantaneous update thanks to the super fast fswatch program.

What is also nice, is that I account for fswatch firing spuriously (which it unfortunately does). If my git diff is unchanged, no re-running via tmux is done, so the scroll offset is preserved.

查看更多
登录 后发表回答