
- TEACH POPCOURSE12 - Programming the Poplog editor       Chris Thornton
                                                       Sussex University


 CONTENTS - (Use <ENTER> g to access required sections)

 -- Introduction
 -- Basic customisation
 -- Basic implementation details of the Ved editor
 -- The program interface to Ved
 -- Using procedures that access Ved words
 -- Commands with arguments
 -- Commands that update the text
 -- Principal sources of information on Ved
 -- Exercises
 -- Moving on

-- 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.

 #  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.

 #  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'

 #  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.
