| *************************** Motivation ********************************** | |
| Many interactive programs read input line by line, but would like to | |
| provide line editing and history functionality to the end-user that | |
| runs the program. | |
| The input-edit package provides that functionality. As far as the | |
| programmer is concerned, the program only asks for the next line | |
| of input. However, until the user presses the RETURN key they can use | |
| emacs-style line editing commands and can traverse the history of lines | |
| previously typed. | |
| Other packages, such as GNU's readline, have greater capability but are | |
| also substantially larger. Input-edit is small, since it uses neither | |
| stdio nor any termcap features, and is also quite portable. It only uses | |
| \b to backspace and \007 to ring the bell on errors. Since it cannot | |
| edit multiple lines it scrolls long lines left and right on the same line. | |
| Input edit uses classic (not ANSI) C, and should run on any Unix | |
| system (BSD, SYSV or POSIX), PC's under DOS with MSC, TurboC or djgpp, | |
| PC's under OS/2 with gcc (EMX), or Vax/VMS. Porting the package to new | |
| systems basicaly requires code to read a character when it is typed without | |
| echoing it, everything else should be OK. | |
| I have run the package on: | |
| DECstation 5000, Ultrix 4.3 with cc 2.1 and gcc 2.3.3 | |
| Sun Sparc 2, SunOS 4.1.1, with cc | |
| SGI Iris, IRIX System V.3, with cc | |
| PC using DOS with MSC | |
| The description below is broken into two parts, the end-user (editing) | |
| interface and the programmer interface. Send bug reports, fixes and | |
| enhancements to: | |
| Chris Thewalt (thewalt@ce.berkeley.edu) | |
| 5/3/93 | |
| Thanks to the following people who have provided enhancements and fixes: | |
| Ron Ueberschaer, Christoph Keller, Scott Schwartz, Steven List, | |
| DaviD W. Sanderson, Goran Bostrom, Michael Gleason, Glenn Kasten, | |
| Edin Hodzic, Eric J Bivona, Kai Uwe Rommel, Danny Quah, Ulrich Betzler | |
| PS: I don't have, and don't want to add, a vi mode, sorry. | |
| This version is with modifications by R Core, including a Windows port, support | |
| for multi-byte characters and partial support for Unicode sequences. | |
| ************************** End-User Interface *************************** | |
| Entering printable keys generally inserts new text into the buffer (unless | |
| in overwrite mode, see below). Other special keys can be used to modify | |
| the text in the buffer. In the description of the keys below, ^n means | |
| Control-n, or holding the CONTROL key down while pressing "n". Errors | |
| will ring the terminal bell. | |
| ^A/^E : Move cursor to beginning/end of the line. | |
| ^F/^B : Move cursor forward/backward one character. | |
| ESC-F : Move cursor forward one word. | |
| ESC-B : Move cursor backward one word. | |
| ^D : Delete the character under the cursor. | |
| ^H, DEL : Delete the character to the left of the cursor. | |
| ^K : Kill from the cursor to the end of line. | |
| ^L : Redraw current line (after a line feed). | |
| ^O : Toggle overwrite/insert mode. Initially in insert mode. Text | |
| added in overwrite mode (including yanks) overwrite | |
| existing text, while insert mode does not overwrite. | |
| ^P/^N : Move to previous/next item on history list. | |
| ^R/^S : Perform incremental reverse/forward search for string on | |
| the history list. Typing normal characters adds to the current | |
| search string and searches for a match. Typing ^R/^S marks | |
| the start of a new search, and moves on to the next match. | |
| Typing ^H or DEL deletes the last character from the search | |
| string, and searches from the starting location of the last search. | |
| Therefore, repeated DEL's appear to unwind to the match nearest | |
| the point at which the last ^R or ^S was typed. If DEL is | |
| repeated until the search string is empty the search location | |
| begins from the start of the history list. Typing ESC or | |
| any other editing character accepts the current match and | |
| loads it into the buffer, terminating the search. | |
| ^T : Toggle the characters under and to the left of the cursor. | |
| ^U : Deletes the entire line | |
| ^Y : Yank previously killed text back at current location. Note that | |
| this will overwrite or insert, depending on the current mode. | |
| TAB : By default adds spaces to buffer to get to next TAB stop | |
| (just after every 8th column), although this may be rebound by the | |
| programmer, as described below. | |
| NL, CR : returns current buffer to the program. | |
| DOS and ANSI terminal arrow key sequences are recognized, and act like: | |
| up : same as ^P | |
| down : same as ^N | |
| left : same as ^B | |
| right : same as ^F | |
| Debugging of keyboard input on Windows: | |
| Alt+I : Toggle debug mode. | |
| Entering characters by code: | |
| Alt+ xxx : hold Alt, type up to 3 digits, release Alt | |
| produces byte (0-255) in the current OEM code page | |
| Alt+ +xxxxxxxx : hold Alt, press + on numpad, type up to 8 digits and hex | |
| letters; produces Unicode character of the given number | |
| Note: Windows automatically interprets Alt+xxx when "xxx" are digits on the | |
| numpad when NumLock is on. It is therefore advisable to have NumLock off to | |
| avoid interference with the Windows processing, and it is necessary for | |
| entering the hex codes on the numpad. A similar interference would exist when | |
| Windows support for Alt+ +xxxx (hex codes) are enabled. Note that R/getline | |
| support even Unicode supplementary characters. | |
| ************************** Programmer Interface *************************** | |
| The programmer accesses input-edit through these functions, and optionally | |
| through three additional function pointer hooks. The four functions are: | |
| int getline(char *prompt, char *buf, int buflen) | |
| Prints the prompt and allows the user to edit the current line. A | |
| pointer to a buffer to store the line is passed in "buf" with the | |
| length of "buflen". The user finishes exiting by typing a newline | |
| or a return. The buffer contains the newline character. The user | |
| enters an end-of-file by typing ^D on an empty line, in which case | |
| the first character of the returned buffer is '\0'. The getline | |
| functions sets terminal modes needed to make it work, and resets | |
| them before returning to the caller. The getline function also | |
| looks for characters that would generate a signal, and resets the | |
| terminal modes before raising the signal condition. If the signal | |
| handler returns to getline, the screen is automatically redrawn and | |
| editing can continue. Getline now requires both the input and | |
| output stream be connected to the terminal (not redirected) so the | |
| main program should check to make sure this is true. If input or | |
| output have been redirected the main program should use buffered IO | |
| (stdio) rather than the slow 1 character read()s that getline uses. | |
| Returns non-zero on EOF. | |
| void gl_setwidth(int width) | |
| Set the width of the terminal to the specified width. The default | |
| width is 80 characters, so this function need only be called if the | |
| width of the terminal is not 80. Since horizontal scrolling is | |
| controlled by this parameter it is important to get it right. | |
| void gl_histadd(const char *buf) | |
| The gl_histadd function checks to see if the buf is not empty or | |
| whitespace, and also checks to make sure it is different than | |
| the last saved buffer to avoid repeats on the history list. | |
| If the buf is a new non-blank string a copy is made and saved on | |
| the history list, so the caller can re-use the specified buf. | |
| void gl_strwidth(size_t (*func)()) | |
| The gl_strwidth function allows the caller to supply a pointer to | |
| a prompt width calculation function (the default one does not support | |
| escape sequences). This allows the caller to embed escape sequences | |
| in the prompt and then tell getline how many screen spaces the prompt | |
| will take up. The width returned needs to be in screen positions, so it | |
| needs to take the print width of Unicode characters into account. | |
| The main loop in testgl.c, included in this directory, shows how the | |
| input-edit package can be used (this is for the original version of getline | |
| only, not updated for the updated R version): | |
| extern char *getline(); | |
| extern void gl_histadd(); | |
| main() | |
| { | |
| char *p; | |
| do { | |
| p = getline("PROMPT>>>> "); | |
| gl_histadd(p); | |
| fputs(p, stdout); | |
| } while (*p != 0); | |
| } | |
| In order to allow the main program to have additional access to the buffer, | |
| to implement things such as completion or auto-indent modes, three | |
| function pointers can be bound to user functions to modify the buffer as | |
| described below. By default gl_in_hook and gl_out_hook are set to NULL, | |
| and gl_tab_hook is bound to a function that inserts spaces until the next | |
| logical tab stop is reached. The user can reassign any of these pointers | |
| to other functions. Each of the functions bound to these hooks receives | |
| the current buffer as the first argument, and must return the location of | |
| the leftmost change made in the buffer. If the buffer isn't modified the | |
| functions should return -1. When the hook function returns the screen is | |
| updated to reflect any changes made by the user function. | |
| int (*gl_in_hook)(char *buf) | |
| If gl_in_hook is non-NULL the function is called each time a new | |
| buffer is loaded. It is called when getline is entered, with an | |
| empty buffer, it is called each time a new buffer is loaded from | |
| the history with ^P or ^N, and it is called when an incremental | |
| search string is accepted (when the search is terminated). The | |
| buffer can be modified and will be redrawn upon return to getline(). | |
| int (*gl_out_hook)(char *buf) | |
| If gl_out_hook is non-NULL it is called when a line has been | |
| completed by the user entering a newline or return. The buffer | |
| handed to the hook does not yet have the newline appended. If the | |
| buffer is modified the screen is redrawn before getline returns the | |
| buffer to the caller. | |
| int (*gl_tab_hook)(char *buf, int prompt_width, int *cursor_loc) | |
| If gl_tab_hook is non-NULL, it is called whenever a tab is typed. | |
| In addition to receiving the buffer, the current prompt width is | |
| given (in screen positions, so taking the print width of Unicode | |
| characters in account) needed to do tabbing right) and a pointer to | |
| the cursor offset is given, where a 0 offset means the first character | |
| in the line. Not only does the cursor_loc tell the programmer where | |
| the TAB was received, but it can be reset so that the cursor will end | |
| up at the specified location after the screen is redrawn. | |