Design and Implementation of an Advanced Text Editor

by Craig Bruce ( )


This secion discusses the other features of the editor that have not been described yet. In general, the operation of this version follows closely from the standalone version, so you can read its documentation for more details. First, I will give a summary of all of the implemented and planned commands, and then I will discuss the operation of a few selected commands.


Here is a command summary. The "I" column in this list tells whether the feature is currently implemented or not. A blank means "no", and an asterisk means "yes". Note that "currently" means "by the time that you read this" (which will be a couple of weeks after I have written this). The "CODE" column tells the internal ACE-PETSCII code for the key. A plus symbol following it means that the shift status of the key is checked to distinguish this key. The "KEY" column tells what keystroke you must make ("CT-" means Ctrl, "CO-" means Commodore, "SH-" means Shift, and "AL-" means Alt). The "ACTION" column tells you what happens.
- ----  -------  ------- 
  $e0   CT-@     Exchange cursor position with mark position 
* $e1   CT-A     Alter case of letter under cursor 
  $e2   CT-B     Go on to next document buffer 
  $e2+  SH-CT-B  Go on to previous document buffer 
  $e3   CT-C     Copy range 
* $e4   CT-D     Delete range 
* $e5   CT-E     Exit with save 
* $e6   CT-F     Find next occurrence of hunt string 
  $e6+  SH-CT-F  Find previous occurrence of hunt string 
  $e7   CT-G     Go to given line number 
  $e7+  SH-CT-G  Go to given _physical_ line number 
* $e8   CT-H     Set Hunt string 
* $e9   CT-I     Insert new file into current one 
  $ea   CT-J     Juggle the lines of paragraphs, keep separate 
  $eb   CT-K     Kill current line 
* $ec   CT-L     Load file 
  $ed   CT-M     Set Mark for range operations 
* $ee   CT-N     Set Name of current file 
  $ef   CT-O     Set Options: input/output translation/tab-expansion, etc. 
  $f0   CT-P     Print current file 
* $f1   CT-Q     Quit without save 
* $f2   CT-R     Recall text from the Kill buffer 
* $f2+  SH-CT-R  Recall text from the Rub buffer 
* $f3   CT-S     Save file 
  $f4   CT-T     Tie together multiple lines into one big line (paragraph) 
  $f5   CT-U     Undo the last change made to the document 
  $f6   CT-V     Verify file 
  $f7   CT-W     Write range with new name 
  $f8   CT-X     Extract the individual lines from a paragraph 
  $f9   CT-Y     Replace (all the other letters were taken!) 
* $fa   CT-Z     Goto bottom of screen 
* $fb   CT-[     Toggle insert mode 
* $fc   CT-\     Toggle modified flag 
* $fd   CT-]     Toggle indent mode 
  $fe   CT-^     Change the current working directory 
  $ff   CT-_     Compose ISO-8859-1 character 
I CODE  KEY          ACTION 
- ----  ---          ------ 
* $91   UP           Cursor up 
* $11   DOWN         Cursor down 
* $9d   LEFT         Cursor left 
* $1d   RIGHT        Cursor right 
* $06   SH-LEFT      Word left 
* $0b   SH-RIGHT     Word right 
* $16   CT-UP        Page up 
* $17   CT-DOWN      Page down 
* $19   CT-LEFT      Page left 
* $1a   CT-RIGHT     Page right 
* $0c   CO-UP        Goto top of document 
* $0f   CO-DOWN      Goto bottom of document 
* $10   CO-LEFT      Goto beginning of line 
* $15   CO-RIGHT     Goto end of line 
* $0d   RETURN       Split current line (indent not yet implemented) 
  $8d   SH-RETURN    Go to next paragraph 
  $01   CT-RETURN    Go up one paragraph 
  $09   TAB          Tab 
  $02   SH-TAB       Backtab 
  $18   CT-TAB       Insert to next tab stop 
* $14   DEL          Delete character 
* $08   CO-DEL       Rubout 
* $94   INST         Insert one space 
* $13   HOME          
* $93   CLR          Cursor home 
  $04   HELP         Bring up help window 
  $84   SH-HELP      Display help screen 
* $0a   LINEFEED      
* $07   SH-LINEFEED   
* $1b   ESCAPE       Redisplay screen 
* $0e   SH-ESCAPE     
* $03   STOP          
* $83   RUN           
  $90   CT-1         Clear document 
  $05   CT-2         Clear buffer 
  $1c   CT-3         Enter hexadecimal PETSCII character code 
  $9f   CT-4         Display directory 
  $9c   CT-5         Destroy current document buffer 
  $1e   CT-6         Create new document buffer 
  $1f   CT-7         Display PETSCII code of current character 
* $9e   CT-8         Scroll left margin of status line 
* $12   CT-9         Reverse screen on 
* $92   CT-0         Screen reverse off 
  $81   CO-1         Set display to show single buffer 
  $95   CO-2         Set display to show two buffers 
  $96   CO-3         Set display to show three buffers 
  $97   CO-4         Set display to 40 columns, default rows 
  $98   CO-5         Set display to take full screen 
  $99   CO-6         Set display to default number of rows 
  $9a   CO-7         Set display to maximum number of rows 
  $9b   CO-8         Set display to 80 columns, default rows 
  $85   F1           Function key 1  : user-defined string 
  $89   SH-F1        Function key 2  : user-defined string 
  $86   F3           Function key 3  : user-defined string 
  $8a   SH-F3        Function key 4  : user-defined string 
  $87   F5           Function key 5  : user-defined string 
  $8b   SH-F5        Function key 6  : user-defined string 
  $88   F7           Function key 7  : user-defined string 
  $8c   SH-F7        Function key 8  : user-defined string 
  $80   CT-F1        Function key 9  : user-defined string 
  $82   CT-F3        Function key 10 : user-defined string 
  $8e   CT-F5        Function key 11 : user-defined string 
  $8f   CT-F7        Function key 12 : user-defined string 


This function is, of course, implemented, since the text-modification functions of the editor would be useless without it. It is really quite simple, because of the data structure of the document. First, we try to open the file for writing. If not successful and we get a "file exists" error, then we scratch the old file. Then, we re-open for writing.

To save the file contents, we start at the top line, and fetch each line in turn until we hit the trailer line of the document, at which point we are finished. After fetching the line, we check if it ends with a hard return, and if so, we append the line buffer with a carriage return character and bump up the line length. We then call the ACE "write" primitive with the line buffer as the argument to write out the line. Writing in this size of chunk rather than in single bytes gives ACE the opportunity to carry out this operation as efficiently as it can.

We then close the file and we are done. We display status information to the user during all phases of this operation, and we certainly tell him if anything goes wrong.


Range delete and recall are implemented, since they are very useful for general editing. What will normally happen is that the user will set the mark with Ctrl-M (mark) to one end of the range to be deleted, and then move the cursor to the other end of the range and press Ctrl-D (delete). The text then disappears into the kill buffer and can be recalled any number of times at any point in the document using the Ctrl-R (recall).

One difference between this ZED and the operations mentioned here are "character oriented" rather than "line oriented". So, you can now delete only portions of lines rather than entire lines. You just have to keep in mind that the cursor is logically located "between" the previous character and the character that the cursor is currently over. For example, if the cursor was on the "y" in "xyz", then the mark would be set to between the "x" and "y" if you pressed Ctrl-M at that point. This also means that if you wanted to delete an entire line (that ended with a hard return), then you would move the cursor to the first character of the line and press Ctrl-M and then move the cursor to the first character of the NEXT line and press Ctrl-D. (The Hard Return itself won't be included in the delete operation if you move the cursor to the end of the line to be deleted--this is one of the reasons for having a displayable trailer line).

To implement the delete operation, all of the lines in the operation are unlinked from the main document and are linked into the kill buffer. If there already was something in the kill buffer, then it is deallocated and the kill buffer is cleared. A trailer line is permanently allocated to the kill buffer, to make it work consistently with the main document. Partial lines (potentially, the first and last lines of the range) are a bit of a pain and have to be split into two lines at the point of the mark/cursor, where one of the broken lines stays with the document and the other goes into the kill buffer. After extracting the range, the lines around the extracted region are sewn back together ("sponge, nurse!") and text is "sloshed" about the stitch point (if necessary). The number of bytes and lines involved are counted up and are subtracted from the global counts for the main document.

Ctrl-C (copy) is very similar to the delete operation, except that the data to be deleted is actually copied to the kill buffer and the document is left unmodified. Range copy is not currently implemented, since its operation can be emulated with a Ctrl-D followed immediately by a Ctrl-R.

To implement the recall operation, the kill buffer is replicated into a temporary document and the current line of the main document is broken into two lines at the recall point (if necessary). Then, the temporary document is linked into the main document at the recall point and the text is "sloshed" about the two stitch points. The line and byte counts are adjusted, and we are done.


Forward text searching is implemented, since it is very useful for both finding things and for moving quickly around in a document. (Reverse search and Range search and replace are not currently implemented, since they are less useful).

The implementation is quite straightforward. The user will first use Ctrl-H (hunt-string) to set the string to search for. The user will input this on the top line of the screen, and we don't have to do much work for inputting the string, since ACE already provides a console-input routine complete with left/right cursor movement and a scroll-back buffer (although it is a bit hard to use if the input line is longer than the input window on the screen).

After the search string is set, the user will press Ctrl-F (find) to find the next occurrence of the string. So, we just search for that string, starting at the cursor position to the right of the current position. A simple algorithm of keeping a pointer to the current scan position in the hunt string and pointers to both the current position in the document and to the position in the document corresponding to the start of the string is used.

If the current document character matches the current hunt-string character, then both the document and hunt-string pointers are advanced. If the hunt string is exhausted by this, then we have found a match and can stop searching. We move the cursor to the saved document position of the start of the hunt string and exit. If the characters don't match, then we move the current document pointer back to the postition corresponding to the start of the hunt string, advance it by one, save it, and start searching again. Our algorithm needs to be able to wrap around soft returns in the main document.

On to Chapter 6.

Last Updated: 1995-12-06 Rev A