.\" pw: pipe watch .\" Copyright 2022 Kaz Kylheku .\" .\" BSD-2 License .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions are met: .\" .\" 1. Redistributions of source code must retain the above copyright notice, .\" this list of conditions and the following disclaimer. .\" .\" 2. Redistributions in binary form must reproduce the above copyright notice, .\" this list of conditions and the following disclaimer in the documentation .\" and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" .\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE .\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR .\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF .\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN .\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .TH PW 1 "26 April 2022" "Utility Commands" "Pipe Watch" .SH NAME pw \- Pipe Watch: monitor recent lines of output from pipe .SH SYNOPSIS command | pw [-i interval] [-l interval] [-n number-of-lines] [-d] .SH DESCRIPTION .I pw stands for Pipe Watch. This is a utility which continuously reads textual input from a pipe or pipe-like source, and maintains a dynamic display of the most recently read .I N lines. If .I pw is invoked such that its standard input is a TTY, it simply reads lines and prints them in its characteristic way, with control characters replaced by caret codes, until end-of-file is encountered. Long lines aren't clipped, and there is no interactive mode. The intended use of .I pw is that its standard input is a pipe, such as the output of another command, or a pipe-like device such as a socket or whatever. In this situation, .I pw expects to be executed in a TTY session in which a .B /dev/tty device can be opened, for the purposes of obtaining interactive input. The remaining description pertains to this interactive mode. In interactive mode, .I pw simultaneously monitors its standard input for the arrival of new data, as well as the TTY for interactive commands. Lines from standard input are placed into a FIFO buffer. While the FIFO buffer is not yet full, lines are displayed immediately. After the FIFO buffer fills up with the specified number of lines (controlled by the .B -n option) then .I pw transitions into a mode in which, old lines are bumped from the tail of the FIFO as new ones are added to the head, and refresh operations are required in order to display the current FIFO contents. The display only refreshes with the latest FIFO data when .IP 1. there is some keyboard activity from the terminal; or .IP 2. when the interval period has expired without new input having been seen; or else .IP 3. whenever the long period elapses. .PP In other words, while the pipe is spewing, and there is no keyboard input, the display is updated infrequently, only according to the long interval. The display is also updated when standard input indicates end-of-data. In this situation, .I pw terminates, unless the .B -d (do not quit) option has been specified, in which case it .I pw stays in interactive mode. The the end-of-data status is indicated by the string .B EOF being displayed in the status line after the data. .SH DISPLAY Lines displayed by .I pw are trimmed not to exceed the number of terminal columns. When a line is trimmed, it is terminated by the .B < character to indicate that there are more characters. The display may be scrolled interactively to read the long lines. The ASCII DEL character (127) is displayed as .B ^? and ASCII control characters are displayed as .BR ^@ , .BR ^A ", ..." .BR ^Z ", ..." .BR ^_ . All other characters are sent to the display as-is. No attempt is made to account for the width of East Asian Unicode characters, and such. When the display is scrolled horizontally, the .B > character appears at the start of each line to indicate this state. Thus, if neither end of a long line is currently visible, then its visible portion appears delimited by .BR >...< . .SH COMMANDS When .I pw enters closed loop operation, the following single-key commands are available: .IP "\fBq\fP, \fBCtrl-C\fP" Quit the program. .IP "\fBl\fP, \fILeft Arrow\fP" Scroll the display to the left. .IP "\fBh\fP, \fIRight Arrow\fP" Scroll the display to the right. .IP "\fB0\fP, \fIHome\fP" Reset scroll to first column. .IP \fISpace\fP Suspend the refresh of the display. In suspended mode, input continues to pass through the FIFO, but all display refresh is stopped. The status indicator .B SUSPENDED is displayed below the data. If the the status is already .B EOF then suspend mode cannot be entered. .IP \fIEnter\fP Cancel suspended mode, resuming display refresh. The display is refreshed immediately and the .B SUSPENDED status indicator disappears. .IP \fB:\fP Enter colon command mode. In colon command mode, the status line clears and a colon prompt appears there. An extended command can be entered. Pressing .I Enter in colon mode dispatches the command. Simple editing is available: backspace, .B Ctrl-W word erase and .B Ctrl-U line erase. If backspace is used in an empty colon line, colon mode terminates without executing a command. .B Ctrl-C and .B Esc also terminate colon mode without executing a command. Colon commands are documented in the COLON COMMANDS section below. .IP "\fB/\fP\fIpattern\fP, \fB?\fP\fIpattern\fP" Activate trigger mode if a non-empty .I pattern is specified, or else cancel trigger mode if an empty pattern is specified. The .B / command specifies .I "head trigger" mode, whereas .B ? specifies .I "tail trigger" mode. Under head trigger mode, the display refreshes only when the most recent line ("head line") in the FIFO matches the specified .IR pattern . The head line is the one which will appear at the bottom of the display, since newer lines appear at the bottom and scroll out toward the top. In head trigger mode, the status string .BI "TRIG (/" pattern ")" appears, showing the pattern preceded by a slash. Under tail trigger mode, the display refreshes only when the least recent line ("tail line") in the FIFO matches the specified .IR pattern . That line is the one which will appear at the top of the display. In tail trigger mode, the status string .BI "TRIG (?" pattern ")" appears, showing the pattern preceded by a question mark. The .I pattern is an extended regular expression (ERE). Trigger patterns saved in a history which may be navigated for recall using the up and down arrow keys or .B Ctrl-P and .BR Ctrl-N . .IP \fBCtrl-Z\fI Suspends .IR pw , and indeed the entire surrounding process group, to the background to gain shell access. This requires a job control shell. When .IR pw is foregrounded again, it will refresh the display in a new text area below the cursor, avoiding overwriting anything in the terminal. Thus suspending and then immediately foregrounding provides a way to save a snapshot of the window into the terminal sessions history. .SH COLON COMMANDS First, some general remarks. Display refresh doesn't pause during the editing of a colon command. If that is required, the suspend command must be used. The space between the command and the argument may be omitted. After a command is executed, a result message appears in its place. This message persists over the poll interval period. The longer the poll interval .RB ( -i " option), the longer the result message persists. Colon commands are saved in a history which may be navigated for recall using the up and down arrow keys or .B Ctrl-P and .BR Ctrl-N . .IP "\fB:w\fP \fIfilename\fP" Write the current contents of the display into the specified file. .IP "\fB:a\fP \fIfilename\fP" Append the current contents of the display into the specified file. .IP "\fB:!\fP \fIfilename\fP" Pipe the current contents of of the display into the specified command. .IP "\fB:g\fP \fIpattern\fP, \fB:v\fP \fIpattern\fP" Push a .I grep pattern onto the grep stack. The .B :g command pushes a plain pattern; the .B :v command pushes a logically inverted pattern. The grep stack holds up to 64 patterns, which are extended regular expressions (EREs). If the pattern is successfully pushed onto the stack, it restricts which lines are admitted into the FIFO and available for display. The plain pattern admits only the lines which match .IR pattern ; the inverted pattern admits only lines which do .I not match .IR pattern . Lines which are already in the FIFO at the time a new pattern is introduced are not affected. The status line shows .B GREP .BI ( pattern "[, ...])" to indicate that grep mode is in effect, and gives the list of patterns, separated by commas. The inverted patterns are indicated by a leading .B ! character. .IP \fB:r\fP[\fB!\fP] Remove and forget the most recent grep pattern .RB ( :g or :v ) from the grep stack. If the stack depth decrements from 1, the grep mode is disabled and the .B GREP status line disappears. If the optional .B ! modifier is included in the command, then it pops the entire stack, forgetting all the patterns and disabling grep mode. .PP Any other command results in a brief error message. .SH OPTIONS .IP "\fB-i\fP \fIreal\fP" Set the poll interval to number of seconds specified by .IR real . This is is a floating-point constant such as 3 or 1.5. Exponential notation such as 5E-1 (equivalent to 0.5) is permitted. This interval determines the input poll timeout of .IR pw 's input processing loop. If no data arrives from the primary input, or from the TTY for this amount of time, a timeout occurs, and the display is refreshed if the FIFO has changed since the last refresh. The default poll interval is 1s. .IP "\fB-l\fP \fIreal\fP" Set the long update interval to number of seconds specified by .IR real . The format is the same as .BR -i , and the default value is 10s. Every time the long update interval passes, the display is updated, if the FIFO has changed since the last update. This happens even when input is arriving too rapidly to permit the poll timeout to take place. The purpose of the long interval is to ensure that there are updates even when the data source continuously and rapidly produces data, and there is no TTY input activity. The long interval should be at least several times longer than the short interval. The granularity of the timing of the long interval updates depends on the poll interval; in the absence of TTY input, .I pw will not perform any display updates more often that the poll interval, even if the long interval is made smaller than the poll interval. .IP "\fB-n\fP \fIinteger\fP" Set the number of lines .I N to the specified decimal integer value. The default value is 15. This value must be positive, and is clipped to the number of display lines available in the terminal, less one. .IP \fB-d\fP Disable auto-quit: when no more input is available, instead of updating the display one last time and terminating, .I pw will updating the status to .B EOF and staying in the interactive mode. This is useful when the last portion of the input is of interest, and contains long lines that require horizontal scrolling. .SH TERMINATION STATUS If .I pw reaches EOF on standard input without encountering a read error, then its termination status will be successful. This is regardless of whether it automatically quits, or whether it stays in interactive mode and then quits due to a quit command. If the data ends prematurely due to a read error, or if the program is asked to quit before all of the data has been read, then unsuccessful termination status will be indicated. Incorrect usage, such as nonexistent options or bad arguments to options, result in a diagnostic on standard error and an unsuccessful termination. Unexpected conditions like out of memory result in abnormal termination (abort). .SH BUGS This was written over the course of a couple of hours, and tested only interactively. The program doesn't respond to window size changes. The display format, such as the handling of control characters, is hard-coded. The program uses hard-coded ANSI sequences, so it doesn't support interesting old terminals. On the other hand, it carries no dependency on any terminal abstraction library/data. The intervals and number of lines cannot be dynamically adjusted. There is no support for unwrapping long lines, which would be useful for copy and paste. During the .B :! command's execution, the TTY settings are not restored. Most of these issues are easy; patches welcome. .SH AUTHOR Kaz Kylheku .SH COPYRIGHT Copyright 2022, BSD2 License.