3

I have the following BASH function that takes arguments and displays them at the bottom of the terminal in a new line that's excluded from the scroll region:

bottomLine() {
    clear
    # Get all arguments and assign them to a var
    CONTENT=$@
    # Save cursor position
    tput sc
    # Add a new line
    tput il 1
    # Change scroll region to exclude the last lines
    tput csr 0 $(($(tput lines) - 3))
    # Move cursor to bottom line
    tput cup $(tput lines) 0
    # Clear to the end of the line
    tput el
    # Echo the content on that row
    echo -ne "${CONTENT}"
    # Restore cursor position
    tput rc
}

It's fairly straightforward and works. Thing is, after some commands (sometimes after just a few, sometimes after 15 minutes of work) the line would get scrolled up even though it should be excluded from the scrolling region.

This happens to me in both Tilda and Terminator.

Any help would be appreciated, cheers.

EDIT: The best way to reproduce the issue is if you do several "ls -a, ls -a, ls -a, ls -a" until you reach the bottom of the page, then open a random file with Vi and then do another "ls -a". When you do this, the unscrollable bottom row goes above even though it shouldn't.

Neekoy
  • 2,325
  • 5
  • 29
  • 48
  • 1
    Maybe you occasionally pass a linefeed within the parameters - try `CONTENT=$(tr -d '\n' <<< "$@")` – Mark Setchell Jul 04 '18 at 18:27
  • @MarkSetchell Sorry, I tried this but it doesn't seem to work. I added an edit to the OP that explains exactly how to reproduce it. It does that both in Terminator and Tilda. – Neekoy Jul 24 '18 at 10:53

1 Answers1

3

My first impulse was to answer that there is no way to freeze the scrollable region once and forever, since any program manipulating the terminal (like vim does) can override your settings. However then I figured out that you can restore the settings through the shell prompting functionality. To this end you must add your terminal control sequence to the PS1 environment variable.

I've modified your function so that it automatically updates the prompt the first time it is called. To this end I had to split it into two functions.

bottomLineTermCtlSeq() {
    #clear
    # Save cursor position
    tput sc
    # Add a new line
    tput il 1
    # Change scroll region to exclude the last lines
    tput csr 0 $(($(tput lines) - 3))
    # Move cursor to bottom line
    tput cup $(tput lines) 0
    # Clear to the end of the line
    tput el
    # Echo the content on that row
    cat "${BOTTOM_LINE_CONTENT_FILE}"
    # Restore cursor position
    tput rc
}

bottomLine() {
    local bottomLinePromptSeq='\[$(bottomLineTermCtlSeq)\]'
    if [[ "$PS1" != *$bottomLinePromptSeq* ]]
    then
        PS1="$bottomLinePromptSeq$PS1"
    fi
    if [ -z "$BOTTOM_LINE_CONTENT_FILE" ]
    then
        export BOTTOM_LINE_CONTENT_FILE="$(mktemp --tmpdir bottom_line.$$.XXX)"
    fi
    echo -ne "$@" > "$BOTTOM_LINE_CONTENT_FILE"
    bottomLineTermCtlSeq
}

I store the current content of the bottom line in a file rather than in an environment variable so that subprocesses of the top level shell can also manipulate the bottom line.

Note that I removed the clear command from the terminal manipulation sequence, which means that you may need to call it yourself before calling bottomLine for the first time (when you call it while having reached to the bottom of your screen).

Also note that the bottom line can be messed up when the terminal window is resized.

Leon
  • 31,443
  • 4
  • 72
  • 97
  • Brilliant. This is exactly how I did it but I just edited my PS1 and it was getting ran every single time which had some breaking effects, but your check if the content is there is what makes it usable. Thank you! – Neekoy Aug 17 '18 at 15:26