ebash

enhanced bash

Home Table of Contents GitHub

Module dialog

func dialog

This is a generic wrapper around dialog which adds --hide and --trace options across the board so that we don’t have to implement wrappers for every widget. Moreover, it also deals with dialog behavior of returning non-zero for lots of not-fatal reasons. We don’t want callers to throw fatal errors when that happens. Intead they should inspect the error codes and output and take action accordingly. Secondly, we need to capture the stdout from dialog and then parse it accordingly. Using the tryrc idiom addresses these issues by capturing the return code into dialog_rc and the output into dialog_output for subsequent inspection and parsing.

func dialog_cancel

dialog_cancel is a helper function to cancel the dialog process that we spawned in a consistent reusable way.

func dialog_checklist

dialog_checklist provides a very simple interface around the dialog checklist widget by simplying operating on an array variable. Instead of taking in raw strings and worrying about quoting and escaping this simply takes in the name of an array and then directly operates on it. Each entry in the widget is composed of the first three elements in the array.

So, typically you would format the array as follows:

array=()
array+=( tag "item text with spaces" status )

Where status is either on or off

Each 3-tuple in the array will be parsed and presented in a checklist widget. At the end, the output is parsed to determine which ones were selected and the input array is updated for the caller. With the --delete flag (on by default) it will delete anything in the array which was not selected. If this flag is not used, then the caller can manually look at the status field in each array element to see if it is on or off.

dialog_checklist tries to intelligently auto detect the geometry of the window but the caller is always allowed to override this with --geometry option.

func dialog_error

Helper function to make it easier to display simple error boxes inside dialog. This is similar in purpose and usage to eerror and will display a dialog msgbox with the provided text.

func dialog_info

Helper function to make it easier to display simple information boxes inside dialog. This is similar in purpose and usage to einfo and will display a dialog msgbox with the provided text.

func dialog_kill

dialog_kill is a helper function to provide a consistent and safe way to kill dialog subprocess that we spawn.

func dialog_list_extract

dialog_list_extract is a function to provide a simple interface to extract the elements of an array formatted for dialog_checklist and dialog_radiolist usage and copy out only the desired elements. The input array contains 3-tuples of the format ( tag text status ). You can then use this function to create a new array with just the text field of each tuple extracted. You can filter on fields with the desired status value of on or off.

By default it filters on elements with a status value of on if no explicit value is provided.

local options=( "1" "Option #1" "on"
                "2" "Option #2" "on"
                "3" "Option #3" "off"
               )
local results=()
dialog_list_extract options results
# Results: ( "Option #1" "Option #2" )
OPTIONS
(*) Denotes required options
(&) Denotes options which can be given multiple times

   --status <value>
         Matching status values to extract.


ARGUMENTS

   __source
         Source array to extract text values from.

   __target
         Target array to extract text values into.

func dialog_prgbox

Helper function to make it easier to use dialog --prgbox without buffering. This is done using stdbuf which can then disable buffering on stdout and stderr before invoking the command requested by the caller. This way we have a nice uniform way to call external programs and ensure their output is displayed in real-time instead of waiting until the program completes.

OPTIONS
(*) Denotes required options
(&) Denotes options which can be given multiple times

   --geometry, -g <value>
         Optional geometry in 'HxW format.

   --ok-label <value>
         Optional override of the OK button text.


ARGUMENTS

   text
         Text to display in the program box.

   command
         Command to execute and display the output from inside the program box.

func dialog_prompt

dialog_prompt provides a very simple interface for the caller to prompt for one or more values from the user using the dialog ncurses tool. Each named option passed into dialog_prompt will be displayed as a field within dialog. By default each value is initially empty, but the caller can override this by using option=value syntax wherein value would be the initial value for option and displayed in the dialog interface. By default all options are required and the user will be unable to exit the dialog interface until all required fields are provided. The caller can prefix an option with a ? to annotate that it is optional. In the dialog interface, required options are marked as required with a preceeding *. After the user fills in all required fields, the provided option names will be set to the user provided values. This is done using the “eval command invocation string” idiom so that the code to set variables is executed in the caller’s environment.

For example:

$(dialog_prompt field)

dialog_prompt tries to intelligently auto detect the geometry of the window based on the number of fields being prompted for. It overcomes some annoyances with dialog not scaling very well with how it pads the fields in the window. But the caller is always allowed to override this with the --geometry option.

OPTIONS
(*) Denotes required options
(&) Denotes options which can be given multiple times

   --backtitle <value>
         Text to display on backdrop at top left of the screen.

   --declare
         Declare variables before assigning to them. This is almost always required unless the
         caller has already declared the variables before calling into dialog_prompt and disires
         to simply reuse the existing variables.

   --geometry <value>
         Geometry of the box (HEIGHTxWIDTHxMENU-HEIGHT).

   --help-callback <value>
         Callback to invoke when 'Help' button is pressed.

   --help-label <value>
         Override label used for 'Help' button.

   --hide
         Hide ncurses output from screen (useful for testing).

   --instructions
         Include instructions on how to navigate dialog window.

   --title <value>
         String to display as the top of the dialog box.

   --trace
         If enabled, enable extensive dialog debugging to stderr.

   --transform (&)
         Accumulator of sed-like replace expressions to perform on dialog labels. Expressions
         are 's/regexp/replace/[flags]' where regexp is a regular expression and replace is a
         replacement for each label matching regexp. For more details see the sed manpage.


ARGUMENTS

   fields
         List of option fields to prompt for. Field names may not contain spaces, newlines or
         special punctuation characters.

func dialog_prompt_username_password

dialog_prompt_username_password is a special case of dialog_prompt that is specialized to deal with username and password authentication in a secure manner by not displaying the passwords in plain text in the dialog window. It also deals with pecularities around a password wherein we want to present a second inbox box to confirm the password being entered is valid. If they don’t match the caller is prompted to re-enter the password(s). Otherwise it functions the same as dialog_prompt does with the “eval command invocation string” idiom so that the code to set variables is executed in the caller’s environment. For example: $(dialog_prompt_username_password). The names of the variables it sets are ‘username’ and ‘password’.

OPTIONS
(*) Denotes required options
(&) Denotes options which can be given multiple times

   --declare
         Declare variables before assigning to them. This is almost always required unless the
         caller has already declared the variables before calling into dialog_prompt and disires
         to simly reuse the existing variables.

   --optional, -o
         If true, the username and password are optional. In this case the user will be allowed
         to exit the dialog menu without providing username and passwords. Otherwise it will
         sit in a loop until the user provides both values.

   --title <value>
         Title to put at the top of the dialog box.

func dialog_prompt_username_password_UI

This function separates the UI from the business logic of the username/password function. This allows us to unit test the business logic without user interaction.

OPTIONS
(*) Denotes required options
(&) Denotes options which can be given multiple times

   --password <value>
         Password to display (obscured), if any

   --title <value>
         Text for title bar of dialog

   --username <value>
         Username to display, if any

func dialog_radiolist

dialog_radiolist provides a very simple interface around the dialog radiolist widget by simplying operating on an array variable. Instead of taking in raw strings and worrying about quoting and escaping this simply takes in the name of an array and then directly operates on it. Each entry in the widget is composed of the first three elements in the array.

So, typically you would format the array as follows:

array=()
array+=( tag "item text with spaces" status )

Where status is either on or off

Each 3-tuple in the array will be parsed and presented in a radiolist widget. At the end, the output is parsed to determine which ones were selected and the input array is updated for the caller. With the --delete flag (on by default) it will delete anything in the array which was not selected. If this flag is not used, then the caller can manually look at the status field in each array element to see if it is on or off.

dialog_radiolist tries to intelligently auto detect the geometry of the window but the caller is always allowed to override this with --geometry option.

NOTE: A radiolist is almost identical to a checklist only the radiolist only allows a single element to be selected whereas a checklist allows multiple rows to be selected.

func dialog_read

Helper function to safely read characters in a while loop from the standard input stream for dialog. This function deals with many complications around reading characters for dialog properly and safely.

Race Conditions on Exit

We definitely cannot try to read characters from the input stream if the dialog process has exited. So, the first thing this function does is check if dialog is runnig or not. If it is no longer running then we are done reading and this function will return an error (1) to indicate that dialog_read did not complete successfully and we should exit the read loop.

While this check is necessary, it is not sufficient to know if we are done reading or not.

There are several non-obvious reasons for this:

So, we detect this situation by checking if the last character that was pressed was the ENTER key. This is the required key that the user must press to complete a form or close a window. If the last key pressed was indeed ENTER then we can check if dialog actually exited or not. We do this by checking if dialog has written its return code into rc_file or not. If it has, then we know it has exited and we should stop reading characters.

Multi-Byte Characters

Unfortunately some arrow keys and other control characters are represented as multi-byte characters:

So this function helps by reading a character and checking if it looks like the start of a multi-byte control character. If so, it will read the next character and so on until it has read the required 4 characters to know if it is indeed a multi-byte control character or not.

ARGUMENTS

   __dialog_pid
         Variable name which contains the PID of the dialog process.

   __rc_file
         Variable name which contains the name of the return code file that dialog will write
         its exit code to when it exits.

   __char
         Variable name which we should use for both INPUT and OUTPUT. Specifically, this will
         contain the character that was read in on the last input loop (if any). And this is
         the variable that we will write the updated value to after we read from the input stream.

func dialog_warn

Helper function to make it easier to display simple warning boxes inside dialog. This is similar in purpose and usage to ewarn and will display a dialog msgbox with the provided text.