TEACH POPCOURSE12 - Programming the Poplog editor

Contents


Introduction

Poplog is a multi-language programming environment. It allows the user to program using any one of several high-level programming languages, or indeed a mixture of languages. The basic user-interface in Poplog is the Ved editor (word-processor). This is used for displaying information, writing programs, showing output, displaying diagrams etc. The Ved editor, like the rest of the Poplog system, is implemented in POP-11. That is to say, the editor is essentially a POP-11 program. This means that the Poplog user can customise Ved using POP-11 commands. It also means that the user can write programs that make use the facilities provided by the editor program.


Basic customisation

The Ved editor is highly customisable. It can be made to do good impersonations of most other popular text editors. This is achieved by redefining what particular keys do. For example, it is possible to make Ved behave in roughly the same way as the popular EMACS editor by loading the library file LIB VEDEMACS. If you go and look at this file (by doing `showlib vedemacs') you will see that it contains a lot of POP-11 code. This redefines the behaviour of keys so as to fit in with the EMACS conventions.

Loading a customisation file such as LIB VEDEMACS produces a complete change in the behaviour of Ved. We can change particular aspects of Ved's behaviour using single POP-11 commands. For example, to change the size of the indentation step produced by the tab key we assign an integer to `vedindentstep'; e.g.,

3 -> vedindentstep;
If we want output generated a `lmr' command to always come out in the current file we can do

true -> vedlmr_print_in_file;
If we want POP-11 mishaps to come out in the current file we can do

true -> vedlmr_errs_in_file;
In fact the Ved command `output' can be used to achieve the same effect. If you give the command `output .' (i.e., `output' with a full-stop as argument) then the `** 4', and any other POP-11 printing, will come out in the current file. To get back to the original arrangement, do `output output.p'.

To see what other customisation variables and procedures there are, look at REF VEDVARS and REF VEDPROCS.


Basic implementation details of the Ved editor

To understand the basic implementation of the Ved editor we should first look at the principal data-structures that it uses. The main function of the editor is to provide a method of editing files. Thus the principle data-structure is the one used to hold information relating to files. This is a vector object, known as a `file structure' for obvious reasons. The components of this vector specify attributes of the file, such as its name, its length, the position of the cursor and whether the file can be updated or not.

File structures are stored in a list called `vedbufferlist'. The file structure for the file currently being edited is also stored in the variable vedcurrentfile. Within the file structure, the main component is the representation of the text itself. This is stored in a vector called `vedbuffer'. The `vedbuffer' structure contains the lines of the file represented in the form of strings. Thus

vedbuffer(2) ==>
** - TEACH POPCOURSE10 - Programming the Poplog editor
The main procedure in the editor program is called `vedprocesschar'. This procedure reads in a key press from the keyboard and updates the current file structure accordingly. If the user has pressed an ordinary character key, then the procedure inserts the corresponding character into the string representing the current line, at the appropriate position (possibly pushing the rest of the text one position to the right). If the user has pressed some sort of function key (e.g. ENTER) then actions are performed to implement the relevant function.


The program interface to Ved

You already have plenty of experience of the user interface to the Ved editor. You use it every time you work on a file in Poplog. The program interface to Ved is made up of a set of procedures and variables that the user has access to. By writing POP-11 programs that call these procedures, and update/access the variables it is possible to achieve useful behaviour. In doing so one is essentially treating Ved as a set of text-processing subroutines.

To illustrate the way in which one can exploit the program interface to Ved, we will look at the implementation of a command that tests for the presence of duplicated words (such as `the the') in the current file. To create a new Ved command we simply define a procedure whose name begins with ved_. For example, if we want to implement a command called `silly' we define a procedure called `ved_silly'. Once we have done this, giving the command `silly' will execute the procedure. You can test this out by loading the following definition and then giving the command `silly'.

define ved_silly;
   'A very silly command' ==>
enddefine;
Note how the output does not come out in the usual place. This is because the print command was executed from the command line, i.e., outside a Ved file.

Ved commands are just procedures and can therefore perform any action you like. To work gradually towards the definition of the command that tests for duplicate words, let us first write a command that counts the number of words in a file. This can be done by writing a procedure that moves the cursor to the top of the file and then keeps advancing it forwards, word by word, until the end of the file is reached. The number of cursor moves is then the number of words in the file. The command might be defined like this.

define ved_count;
   vars n = 0;
   vedtopfile();
   until vedatend() do
      vedwordright();
      n + 1-> n;
   enduntil;
   vedputmessage('There are '><n><' words in the file');
enddefine;
The header of the definition is self-explanatory. We want a command called `count'; we therefore define a procedure called `ved_count'. The second line contains a `vars' command that sets up and initializes to 0 a variable called `n'. In the third line we see a call on a procedure called `vedtopfile'. This procedure is the Ved procedure that causes the cursor to jump to the very top of the file. We then see an `until' loop. This continues executing until such time as the Ved procedure `vedatend' returns a non-false result. This only occurs when the cursor is at the very end of the file. Thus the loop will continue to execute until such time as the cursor has reached the end of the file.

Within the body of the loop we see a call on the procedure `vedwordright' followed by a `+' command that increments the variable `n' by 1. The `vedwordright' procedure moves the cursor one word to the right or onto the next line if there is no word to the right. Thus, the loop will continue to execute until successive calls on `vedwordright' have brought the cursor all the way to the end of the file. By incrementing `n' each time we go around the loop we end up with a count of the number of words in the file.

In the final line of the procedure we see a call on the procedure `vedputmessage'. This is the Ved procedure that displays messages on the command line. It takes a string as argument. In the present call the string is constructed by joining together two strings (`There are ' and ` words in the file') and the value of `n'.


Using procedures that access Ved words

Using the definition of `ved_count' as a template we can produce a command to find the next occurrence of duplicate words in the file. The basic strategy for the command will be to search through the file from beginning to end, testing all adjacent words for equality. If it finds a pair of adjacent, identical words it should stop and print an explanatory message. The procedure will have more or less the same form as the `ved_count' procedure. However it will also make use of the procedure `vednextword', defined below.

This procedure advances the cursor to the right until the current character (the value produced by `vedcurrentchar') is not an alphabetical character, or the current position is off the end of the line (the value of `vvedlinesize'). In most circumstances this will ensure that the cursor moves to a position immediately after the current word. Once the end of the current word has been found, the procedure uses the built-in procedure `substring' to derive the substring between the original position and the word-end position. This is then returned in the output variable `word'.

define vednextword -> word;
   vars i = vedcolumn,;
   until not(isalphacode(vedcurrentchar()))
   or vedcolumn > vvedlinesize do
      vedcharright()
   enduntil;
   substring(i, vedcolumn-i,vedthisline()) -> word;
   if length(word) < 1 then false -> word endif;
enddefine;
The `vednextword' procedure is used repeatedly by the `ved_nextdups' procedure. This is the procedure that actually implements the command. It works forwards from the current position in the file to the end, at each point picking up the current word and comparing it against the previous word (stored in the local variable `last_word'). If it discovers a duplication, the procedure puts up an explanatory message and returns. At the end of the loop the procedure assigns the value of `word' to be the new value of `last_word'.

define ved_nextdups;
   vars last_word = false, word;
   until vedatend() do
      vednextword() -> word;
      if isstring(word) and word = last_word then
         vedputmessage('Multiple occurrence of '><word);
         return;
      endif;
      word -> last_word;
      vedwordright();
   enduntil;
enddefine;

Commands with arguments

Many Ved commands take arguments. The `ved_w' command for example takes an optional file-name argument. Arguments are passed in to a command via the variable `vedargument'. When the procedure implementing a command is called, this variable contains any argument that was given to the command in the form of a string. Depending on the command, the string in `vedargument' may have to be processed in different ways. An illustrative example is the command defined below. This command called `ved_log' takes a mathematical expression as argument and returns the approximate log (to base 10) of the number.

The command is a useful aid when one wishes to convert an expression with a very large value into a power of 10. In order to obtain the value of the expression provided as argument, the procedure has to evaluate it as POP-11 code. This can be done quite conveniently by calling the built-in procedure `compile' giving it the result of applying `stringin' to `vedargument'. The call on stringin converts the string into what is known as a a `character repeater'. In this form the `compile' procedure can effectively implement the POP-11 code contained in the string. If the code comprises a single expression this will produce a value on the stack. Thus the whole call produces the value of the expression.

define ved_log;
   vars i, n = compile(stringin(vedargument));
   for i from 1 to 1000 do
      if 10 ** i > n then return(i-1) endif;
   endfor;
enddefine;
Within the body of the procedure a `for' loop is used to gradually increase the value of the local variable `i' until such time as the value of

10 ** i
exceeds the value of the specified expression. At this point the procedure simply returns the value of `i' (using an explicit `return' command with arguments). Thanks to the convention that any value left on the stack at the end of a command execution gets displayed on the command line, the returning of this value causes it to be displayed to the user.


Commands that update the text

In addition to displaying messages on the command line, commands can also update the text in the file. An example of a command that does this is `ved_subtract' defined below. This reads in the number under the current cursor position and the number immediately below it. It then subtracts the latter from the former and prints the result on the next line down in the file.

define ved_subtract;
   dlocal vedcolumn vedline vvedlinesize;
   vars n1 n2;
   vedcurrentitem() -> n1;
   vedchardown();
   vedcurrentitem() -> n2;
   vedchardown();
   vedinsertstring(n1-n2 >< nullstring);
enddefine;
It uses a fairly straightforward sequence of commands. It uses the procedure `vedcurrentitem' to read in the numbers under the cursor position and it uses `vedchardown' to descend to the line below. Finally it applies `vedinsertstring' to the string produced by joining the resulting value to an empty string (contained in the built-in variable `nullstring'). This inserts the appropriate value into the file. Note also the use of the `dlocal' command here to localize the changes made to the position-defining variables `vedline', `vedcolumn', and `vvedlinesize'.

You can test the command out by executing it with the cursor over the initial `2' of `23456'.

23456
  721

Principal sources of information on Ved

There are many online files in Poplog that deal with Ved. For the purposes of using the program interface to Ved, some of the more useful files are as follows.

REF VEDCOMMS
REF VEDPROCS
REF VEDVARS
If you have plenty of time on your hands you might want to look at

DOC VEDMANUAL
DOC VEDUSERGUIDE

Exercises

To test your understanding of the material presented in this file you should do the following exercises. In order to complete them successfully you will need to delve deeply into the Poplog online information (HELP, TEACH, and REF files). Once you have completed the exercises get your tutor or a friend to check them.

  1. Define a ved command that is capable of adding up a column of numbers in a marked range. The procedure should be able to cope with blank lines in the column and with numbers that are not exactly aligned. It should insert the total at a relevant at the end of the marked range.

  2. Design and implement a Ved interface to the Unix spelling checker. This should first send all the text in the current file to the spelling checker and then enter a loop in which it repeatedly places the cursor over a spelling error. To produce this program you will need to read up on procedures such as `sysobey', `vedreadin', `sysexecute'

  3. Construct a Ved command that following a command such as `grid 4 6' will insert a grid with 4 columns and 6 rows into the current file. Note that the vertical lines of the grid can be drawn using the `|' character and horizontal lines can be drawn using the `-' character.

Moving on

If you have completed the above exercises successfully you can move on to TEACH POPCOURSE13.


Page created on: Fri Apr 26 09:35:06 BST 2002
Feedback to Chris Thornton
hits this year