21 June 2014

Introduction

One of the biggest web trends over the past 3 years has been responsive designs. This is where the width of your device dictates the layout of your website. This allows you to support 1 design, but let it dynamically adapt from mobile device to tablets to full blown desktop browsers.

Well, what about terminal shells? I spend the majority of my day in a shell, and using a tool like Spectacle, the width of my terminal changes every few minutes. I thought to myself how I could take the idea of responsive web and deploy it to my terminal.

For the interested, you can check out my .dotfiles.

Responsive Shell, Oh My!

We're going to do this quickly and efficiently using tput. This would still be possible without tput, which became public domain back in 1986, but you would not get cross-environment support. tput allows you to query and change certain terminal capabilities. If your environment doesn't support it, you are seriously in need of a new box.

The command we are specifically interested in at the moment is tput cols. This command returns the width of the current terminal window. Using the response, we can formulate our PS1 based on different widths.

Example

Below, we take the ideas from above and put some bash around it:

# Get columns
cols=$(tput cols)


# Resize for smaller prompts
if [["$cols" -le 60]]; then
    PS1="\u@\h in \W # "
# Full width  
else
    # Output the Prompt
    PS1="[\t] \u@\h: \w # "
fi

Making It Responsive

Just detecting the width does not mean it's responsive. What responsive really means is, when you change the window size, it adjusts automatically. By just using the code above, you would have to reload bash or source your .bashrc/.bash_profile files to get the change. But this would be annoying, so how do we fix this?

We can use the PROMPT_COMMAND environment variable to assign a function to the prompt. How would one do this you may be asking?

# .bashrc
export PROMPT_COMMAND=prompt


# Create the prompt
prompt() {


    # Get columns
    cols=$(tput cols)


    # Resize for smaller prompts
    if [["$cols" -le 60]]; then
        PS1="\u@\h in \W # "
    # Full width  
    else
        # Output the Prompt
        PS1="[\t] \u@\h: \w # "
    fi
}

What this does is execute the prompt() function every time you enter

Conclusion

So one of the biggest gotcha's with this method is that, SCP and certain SSH methods don't use interactive shells. This means the tty environment will not be set how you expect. As a result, tput will error out.

To get around this, you can do a check to make sure a tty exists, by using:

# Check if this is a TTY or not
IS_TTY=$(tty -s)
if [$? -eq 0]; then
    # Code goes here
fi

Enjoy.

Tagged under bash, linux-system-administration, mac-osx, cli, fish, responsive, shell, terminal, tput, tty, zsh, and others
Mike Mackintosh

This post was written by Mike Mackintosh, a decorated security professional.




Related Posts