Progress Bar With Go
Following tutorial is intended for anyone who are curious about the beauty of the APT progress bar; also includes the people who still use the command line.
Have you noticed that when installing a package in Ubuntu the screen shows the actions that are happening and also a progress bar is shown in the last line of the terminal. This last observation that I would like to implement with Go for my future applications running in the terminal.
I would like to have a progress bar that does not deform when modifying the size of my Terminal, that the progress bar adjusts to the changes of the Terminal; basically a clone of the progress bar that is used in Ubuntu and other Linux distributions.
Planning the component
Lets quickly describe what the Progress Bar should do and look like. It seems, to me, that we only need the following elements to make the progress bar:
- Monitor when the Terminal changes the size.
- Adjust the size of the progress bar. - Update the content of the window when the Terminal size changes.
- Update the content of the entire Terminal and the progress bar. - Display the progress bar in the last line of the terminal.
- This last line must be reserved, and it shouldn’t be overwritten by anything.
Monitor the Terminal size
The Terminal is divided into cells and the cells are placed into a 2D matrix, being the matrix traversed from left-to-right and from top-to-bottom. We can write to any cell with a X and Y relative position, these coordinates are the initial position where the characters on the screen will be written.
I use init()
function to monitor when the Terminal changes size, I even use it as the first function to be executed since it initially seeks to know the current size of the terminal.
updateWSize()
uses the IoctlGetWinsize
system call, with this call we directly obtain the values to map the 2D matrix. This function fulfills the following objectives:
- Reserve the last line of the Terminal.
- The reserved line from previous iterations has to be removed. - Updates the size of the header used to report the progress of the running task.
- Terminal with size less than 9 columns only shows the elapsed percentage.
- Size less than 20 columns shows percentage and progress bar.
- For the other cases, the wordProgress
is shown next to the percentage and progress bar:Progress: [100%] [###...]
Render the Progress Bar
To make the progress bar, we need to write to different cells position, using the coordinates from updateWSize()
and calculate the size of the header to be displayed along with the new size of the progress bar; this creates the doing effect.
To control the cursor in the 2D matrix ANSI escape sequences are used, with this we could ensure in a certain way that our bar behaves the same in UNIX-like OS.
The end result is a progress bar that behaves just fine, adaptable to changes in the size of the Terminal and with the same style as Ubuntu.
Very simple example if what can be done with Go, being simple and easy to understand.
See full code at: https://github.com/elulcao/progress-bar