Bash – Populate PS1 asynchronously

asyncbashbashrcprompt

I have a few git svn related functions that see if I have to pull/push from/to the repository.

My problem is that the functions I've written to gather this information are too slow. I'd like to make them async so that PS1 shows a default, if though the data produced by the functions is ready I want it printed.

I'd like to have these information in my prompt – so that, for example, I know if I have to pull – without doing a git svn fetch everytime.

This is the function I call to add a ↑ to my PS1 if I have to push my changes.

function hasToPush {
    (($1 == 0)) && 
        (git svn dcommit --dry-run 2>/dev/null | grep -q "diff-tree" && echo "↑")
}

These are the functions I call to add a ↓ if I have to pull. The first is used to refresh my index every 2 minutes so that I can do the (($latest > $current)) check.

function loopingGitSvnFetch {
     sleep 120
     git svn fetch &>/dev/null
}
loopingGitSvnFetch &
function hasToPull {
    (($1 == 0)) && (
        latest=$(git svn log | awk 'NR==2' | cut -d ' ' -f1 | tr -d 'r')
        current=$2
        (($latest > $current)) && echo "↓"
    )
}

To make them async, I've tried to put them together like this:

function async {
    {
     git diff-index --quiet --cached HEAD &>/dev/null
     dirty=$(echo $?)
     push=$(hasToPush $dirty)
     gitsvn=$(git svn info 2> /dev/null | grep Revision)
     gitsvn=${gitsvn#Revision: }
     pull=$(hastoPull $dirty $gitsvn)
     callback $push $pull
     } &
 }

But that produces the same slow behaviour.
I've tried to put results in a file and then read it after, but I don't like that approach.

I've thought about using PROMPT_COMMAND. But that would not be async; it would be on demand.

Could you shed some light on how PS1 behaves or on what I'm doing wrong?
Thank you in advance.

PS: Could someone with 300 rep add the async and ps1 tags?

EDIT:

I added these line to my .bashrc as a simple test, it seemed to work, so having rewrote them (I reverted my previous attempt) seems was a good thing 🙂

while true;
do
    discoverScmInfo &>~/.ps1
    sleep 1
done &
PS1='$(customW)$(cat ~/.ps1)\$ '

I'll put this in a function and check if the job is already running before calling it.
Sorry about this, after all it seems that all I needed was to write about it. 🙂

Best Answer

re: your solution of a loop every second: you could write to a file in /tmp, instead of in your home directory. And PS1=$(customW)$(< ~/.ps1)\$ ' would save a fork/exec of cat.

re: the original question: how to get an async update to PS1: To start an async write to PS1:

  • set PROMPT_COMMAND to a function that checks if the data is available.
    • If it is, update PS1 and unset PROMPT_COMMAND
    • If not, leave PS1 with the old or placeholder value.

Use a file in /tmp for the async IO to write to, and PROMPT_COMMAND to read from.

I think this should work.

Related Question