mirror of
https://github.com/PDP-10/its.git
synced 2026-01-11 23:53:12 +00:00
Drop the older of two EMACS Pascal mode info files; autoload.
This commit is contained in:
parent
782ecb6302
commit
a4d2004132
@ -1,748 +0,0 @@
|
||||
-*-Text-*-
|
||||
|
||||
File: EPASC Node: Top Up: (EMACS)Top Next: Available
|
||||
|
||||
PASCAL mode in EMACS provides support for inputing and editing Pascal
|
||||
code. You should be in Pascal Mode automatically when you edit a
|
||||
Pascal file. You can call it directly by loading the Pascal library
|
||||
(M-X Load Library <esc> Pascal <cr>) and giving the command M-X Pascal Mode.
|
||||
|
||||
* Menu:
|
||||
|
||||
* Available:: List of all special commands.
|
||||
* Compile:: Macros for hopping right to your compiler errors.
|
||||
* Variables:: Synopsis of the customization variables.
|
||||
* Indent:: Indenting old and new lines of code.
|
||||
* Statements:: Inserting complete structured statements.
|
||||
* Comments:: Things you can do with comments in PASCAL mode.
|
||||
* Paren Groups:: Commands which manipulate parenthesized expressions.
|
||||
* Hints:: Other commands useful for editing Pascal code.
|
||||
* Hacker:: Information for hackers or the very interested.
|
||||
|
||||
Node: Available, Previous: Top, Next: Compile, Up: Top
|
||||
|
||||
Commands which start on keys:
|
||||
|
||||
C-M-I The main indentation driver, described under Indent.
|
||||
LINEFEED Does a CRLF, then a C-M-I. Useful at the ends of lines.
|
||||
C-M-? Explains the last indentation, if you're curious.
|
||||
C-M-\,C-M-G,M-G Indent Pascal Region (re-indent all lines in region)
|
||||
|
||||
Rubout TAB-hacking Rubout (converts TABs to spaces).
|
||||
C-Rubout Normal Rubout.
|
||||
|
||||
M-; Start comment at end of line. *note comments: comments.
|
||||
C-M-* Insert a comment right here (don't re-indent)
|
||||
C-M-$ Global Pascal Comment
|
||||
|
||||
C-M-N Forward over a BEGIN/END (or REPEAT/UNTIL etc.) pair.
|
||||
C-M-P Backward over a BEGIN/END pair.
|
||||
C-M-H Mark Procedure
|
||||
|
||||
C-M-. Prefix for Structured Insert Commands. *note: St: Statements
|
||||
|
||||
C-M-E If in ErrList Mode, jumps to position of next compiler error
|
||||
and prints the error in the echo area. *note Error: Compile
|
||||
|
||||
C-M-C Same Capitalization, make all occurences of word same cap.
|
||||
C-M-S No Comment Search, search for something ignoring
|
||||
comment contents.
|
||||
|
||||
C-M-+ Turns previous variable name into command to increment
|
||||
that variable. That is, FOO C-M-+ turns into
|
||||
FOO:= FOO + 1;
|
||||
C-M-' Inserts a string of specified length and lets you
|
||||
recursively edit the contents of the string in
|
||||
overwrite mode.
|
||||
C-M-{ Pulls non-comment text from previous line beginning at
|
||||
character (asked for) and puts it on this line. Also
|
||||
performs indentation on the result. Useful when you
|
||||
want to change the way a line is broken.
|
||||
|
||||
Pascal Mode
|
||||
Restart Pascal Mode
|
||||
Pascal Expand Abbrevs in Region
|
||||
Expands all abbrevs in region, but not in comments.
|
||||
|
||||
Node: Compile, Previous: Available, Next: Variables, Up: Top
|
||||
|
||||
With the command M-X Compile (C-M-,) you can automatically compile
|
||||
and execute your program in an inferior exec. To get special compiler
|
||||
switches or to load other files with yours, put the switches and other
|
||||
files in the variable Compiler Switches.
|
||||
|
||||
If you are in ErrList Mode, the compiler errors you see when you do M-X
|
||||
Compile (C-M-,) are saved away in the buffer named *LST*. You can jump to
|
||||
the position of the "next" error in your source file with the command
|
||||
C-M-E. Do this till the message "(No more errors)" appears.
|
||||
|
||||
To go into ErrList Mode, just give the command M-X ErrList Mode. To get
|
||||
out, give the same command again. You can also get in by setting
|
||||
the variable, ErrList Mode, to something other than zero. This will work
|
||||
from an init or evars file (*Note: Init: (EMACS)INIT.) or a local modes list
|
||||
(*Note: Locals: (EMACS)Locals). You do not want to be in ErrList mode when
|
||||
you are not finding compiler errors because it is inefficient and it will be
|
||||
creating a .LST file every time you compile.
|
||||
|
||||
Appologies: (1) In the current implementation this command creates a
|
||||
compiler listing of your program, which could waste a lot of space. If this
|
||||
is a problem, connect to a scratch directory while doing the compilation. It
|
||||
is also a good idea to have your source program on the same directory you are
|
||||
connected to. (2) The routine for jumping to the position of an error does
|
||||
not adjust for changes you have made to your file after the compilation. This
|
||||
means that it may show errors you have already fixed, and that the position it
|
||||
jumps to will be wrong if (a) you change the number of pages before the page
|
||||
with the error, or (b) you change the number of lines before the line with the
|
||||
error on the page with the error, or (c) you change the number of characters
|
||||
before position of the error on the line with the error.
|
||||
|
||||
|
||||
Node: Variables, Previous: Available, Up: Top, Next: Indent
|
||||
|
||||
The PASCAL library has several switches you can set to customize its
|
||||
behavior. For info on how to set variables *note Vars: (EMACS)Variables.
|
||||
|
||||
Variable name D Explaination
|
||||
----------------------------------------------------------------------------
|
||||
ErrList Mode 0 If non-zero, compiler errors found with
|
||||
M-X Compile (C-M-,) are saved so that
|
||||
you can step through them with C-M-E.
|
||||
|
||||
Indent Align Only 0 If non-zero, LINEFEED only aligns
|
||||
with previous line (does ^R Indent Nested).
|
||||
|
||||
Indent After --- 4 For any keyword, Indent After <keywd>
|
||||
is the amount to indent extra after
|
||||
seeing <keywd>.
|
||||
Begin-Block Body Indentation 4 Default indent after BEGIN,
|
||||
REPEAT, CASE, LOOP, RECORD.
|
||||
IF-Block Body Indentation 4 Default indent after IF, THEN, ELSE,
|
||||
WHILE, FOR, DO, WITH.
|
||||
Decl Body Indentation 4 Default indent after CONST, TYPE,
|
||||
VAR, LABEL.
|
||||
--- Body Indentation 4 Amount to indent Body, but not variables, of
|
||||
subprogram keyword specified. Indentation
|
||||
for declaration section is Indent After ---
|
||||
PROCEDURE Body Indentation 4 Default for both "--- Body Indentation" and
|
||||
"Indent After ---" for PROCEDURE, FUNCTION,
|
||||
and PROGRAM.
|
||||
Indent After Everything 4 Default for any value not specified.
|
||||
|
||||
Reindent ENDs 1 0 = leave ENDs & UNTILs indented same as
|
||||
statements in block; 1 = align END's with
|
||||
corresponding BEGIN line.
|
||||
Match Block Word 0 If non-zero, indentation after line with
|
||||
the keyword BEGIN, REPEAT, CASE, and RECORD
|
||||
will start from the position of the keyword
|
||||
within the line, not the indentation of the
|
||||
line.
|
||||
|
||||
BEGIN on same line 0 Non-zero means inserted BEGINs are
|
||||
left on same line as stmt.
|
||||
THEN on same line 1 Non-zero means leave THEN on line
|
||||
with IF.
|
||||
ELSE on same line 0 Non-zero means try to stick ELSE on
|
||||
end of previous line.
|
||||
|
||||
Automatic Capitalization: 0 If non-zero, all keywords typed or
|
||||
inserted are capitalized.
|
||||
Insert Comments 1 Non-zero means insert functions
|
||||
insert some labeling comments.
|
||||
|
||||
-------------------Comment Controlling Variables--------------------
|
||||
Comment Column 0 Where EMACS tries to start your
|
||||
comments (here or after your code).
|
||||
Global Comment Column 10 Comment Column when doing a Global
|
||||
Pascal Comment.
|
||||
Pascal Star Line Width 51 Do Describe on ^R Global Pascal Comment.
|
||||
Comment Rounding "+1" Algorithm which EMACS uses
|
||||
to figure where to start the comment
|
||||
if your code extends beyond the
|
||||
comment column.
|
||||
* Menu:
|
||||
|
||||
* Examples:: Variable settings for various kinds of indentation.
|
||||
|
||||
File: EPASC, Node: Indent, Up: Top, Previous: Variables, Next: Statements
|
||||
|
||||
PASCAL mode allows easy formatting of Pascal code as you type it in. Its
|
||||
main concern is with indentation, not with breaking lines, so that it fits in
|
||||
well with most styles of formatting. There is also a great deal of
|
||||
customization avaialable to suit individual tastes. Note: If the load is too
|
||||
high to effectively use the indentation package, or you just don't get along
|
||||
with it, you can turn it off by setting Indent Align Only to 1. This will
|
||||
force the indentation to only align with the previous line, without trying to
|
||||
figure out how much less or more to indent.
|
||||
|
||||
* Menu:
|
||||
|
||||
* Basics:: The basics of using PASCAL mode indentation
|
||||
* Details:: Some details about how indentation mode operates
|
||||
* Examples:: Variable settings for various kinds of indentation.
|
||||
|
||||
Node: Basics, Previous: Indent, Up: Indent, Next: Details
|
||||
|
||||
The two indentation commands are LINEFEED and C-M-I. C-M-I calls the
|
||||
main routine to do indenting, and LINEFEED does a return, then calls
|
||||
C-M-I.
|
||||
|
||||
While you are typing in a program, the normal mode of operation will
|
||||
be to type in your lines of code, and at the end of each line type
|
||||
LINEFEED instead of Return. This will cause EMACS to decide how far
|
||||
in the next statement should be indented. You can get the same effect
|
||||
by typing Return then C-M-I. C-M-I can also be used to indent or
|
||||
re-indent existing lines. If you type C-M-I at the beginning of an
|
||||
existing line, the line will be indented the way that EMACS thinks it
|
||||
ought to be. Typing C-M-I in the middle of a line will cause the rest
|
||||
of the line to be lined up with a word in the line above (i.e. M-X ^R
|
||||
Pascal Indent Relative is called).
|
||||
|
||||
A special case is when you type LINEFEED after an END or UNTIL, or
|
||||
type C-M-I at the beginning of the line after an END or UNTIL. Doing
|
||||
either of these causes EMACS to go back and decide which BEGIN or
|
||||
REPEAT or other keyword the END (UNTIL) matches. It then will go and
|
||||
move the END (UNTIL) so that it lines up with the BEGIN or whatever.
|
||||
This allows you to not have to worry about trying to convince it that
|
||||
the line you are about to type is an END, not just another statement.
|
||||
Just type the END, which will be in the wrong place, then type
|
||||
LINEFEED, like you would with any line. It will go back and move the
|
||||
END so that it's in the right place. You can turn off this "feature"
|
||||
by setting the variable Reindent ENDs to zero.
|
||||
|
||||
Note that, even though TABs are used for indentation, RUBOUT is
|
||||
redefined so that TABs act like 8 spaces. So, if you try to rub out a
|
||||
TAB, what you will get as a result is that you've moved one character
|
||||
position to the left on the screen. If you want to get the ordinary
|
||||
Rubout, you can use C-Rubout, which you can get by typing Control-^
|
||||
followed by Rubout.
|
||||
|
||||
Using LINEFEED and C-M-I, you should be able to do all of the
|
||||
formatting that you want. In cases where it fails, complain!
|
||||
|
||||
Node: Details, Previous: Basics, Up: Indent, Next: Statements
|
||||
|
||||
If you know that EMACS is about to give you indentation that you don't
|
||||
want (see *note Failure: Future Work, for some known cases) you can be
|
||||
more specific about the indentation you want. Giving an argument to
|
||||
LINEFEED (or C-M-I) makes it run ^R Indent Nested. Positive arguments
|
||||
make it line up with a line <arg> levels out (to the left) of the
|
||||
previous line and negative arguments make in indent -arg spaces
|
||||
further in (to the right). This also works if you've set Indent Align
|
||||
Only.
|
||||
|
||||
If there is no argument then if the cursor is not at the left margin,
|
||||
the indenter calls M-X ^R Pascal Indent Relative, which lines up with
|
||||
successive keywords on the previous line. Otherwise, if there is an
|
||||
un-matched open parenthesis or open comment in the previous 10 lines,
|
||||
it matches that. Otherwise it calls the indenter.
|
||||
|
||||
If there is a keyword on the previous line and the line doesn't end
|
||||
with ";", the new line is indented to the amount of the previous line
|
||||
plus the amount specified by "Indent After <keyword>" for the last
|
||||
keyword on the previous line.
|
||||
|
||||
If no keyword is found or the line ends with a sem, we just line up
|
||||
with the previous statement, which may not be the previous line if
|
||||
it is a nested statement or the END of a compound statement.
|
||||
|
||||
If the PREVIOUS line contains an END, it will be re-indented to match
|
||||
the matching BEGIN, unless Reindent END is zero.
|
||||
|
||||
If the indentation you just got seems strange to you, you can get a
|
||||
short description of what was done (including a pointer to the point
|
||||
which was matched to get the base indentation) with M-X Print Last
|
||||
Pascal Indenter (C-M-?).
|
||||
|
||||
To make the indenter ignore a keyword which it now recognizes, set the
|
||||
variable "Indent After <x>" to -1.
|
||||
|
||||
A description of the algorithm used is in *note Internal: Indentation.
|
||||
|
||||
Node: Statements, Previous: Indent, Up: Top, Next: Comments
|
||||
|
||||
These are the available insertion commands:
|
||||
|
||||
C-M-. E ^R Pascal END
|
||||
C-M-. W ^R Pascal WHILE
|
||||
C-M-. F ^R Pascal FOR
|
||||
C-M-. ^R Pascal WITH
|
||||
C-M-. I ^R Pascal IF
|
||||
C-M-. ^R Pascal ELSE
|
||||
C-M-. P ^R Pascal PROCEDURE
|
||||
C-M-. ^R Pascal FUNCTION
|
||||
C-M-. ^R Pascal PROGRAM
|
||||
C-M-. R ^R Pascal REPEAT
|
||||
C-M-. B ^R Pascal BEGIN
|
||||
C-M-. C ^R Pascal CASE
|
||||
C-M-. ^R Pascal RECORD
|
||||
C-M-. B ^R Pascal BEGIN
|
||||
|
||||
M-X ^R Pascal End goes back to an open block statement and inserts the
|
||||
corresponding close block (END or UNTIL). Use Describe (see *Note
|
||||
Help: (EMACS)Help.) on ^R Pascal End for more details.
|
||||
|
||||
The general purpose of the other commands is to insert the redundant
|
||||
text in their kinds of statements. For some individualities of the
|
||||
commands, you can see their internal documentation via the Describe
|
||||
command. Here are some of their general properties:
|
||||
|
||||
The column indented to is the current horizontal position or the
|
||||
indentation of the current line, if there is text on the line. For
|
||||
instance, if the cursor is at column three and C-M-F is pressed, this is
|
||||
inserted:
|
||||
FOR <cursor here> DO
|
||||
BEGIN
|
||||
<indented to here>
|
||||
END; (* FOR *)
|
||||
(assuming Indent After BEGIN = 3, Indent After DO = 3, and Capitalize
|
||||
Pascal Keywords = 1)
|
||||
but if the cursor is at the end of this line:
|
||||
while true do <cursor here>
|
||||
and C-M-B is pressed, this results:
|
||||
while true do begin
|
||||
<cursor here>
|
||||
end; (* while *)
|
||||
(if Capitalize Pascal Keywords = 0, Indent After BEGIN = 4, Match Block
|
||||
Word = 0).
|
||||
|
||||
If given a positive argument, the macros will not insert the
|
||||
BEGIN/END pair (where this makes sense), except the PROCEDURE/FUNCTION/
|
||||
PROGRAM group will not insert the line with VAR. If given a
|
||||
negative argument, they will try to enclose -<arg> lines within the
|
||||
BEGIN/END (or whatever) pair. If you want to enclose the region
|
||||
instead, do ^R Count Line Region (M-=) to see what argument to give.
|
||||
|
||||
^R Pascal Procedure and ^R Pascal Function will ask you for the
|
||||
subprogram name and parameters before it inserts the rest of the
|
||||
block. Type them normally into the buffer where the cursor is left
|
||||
and exit with C-M-C (C-M-Z on Twenex).
|
||||
|
||||
Undoing and fixing: Any of the calls to these functions can be be
|
||||
taken back with M-X Undo$. Remember, they insert a lot of comments;
|
||||
if you don't want them, they can be killed individually with C-M-;.
|
||||
Setting Insert Comments to zero will stop them all from being
|
||||
inserted.
|
||||
|
||||
* Menu:
|
||||
|
||||
* Examples:: Variable settings for various kinds of indentation.
|
||||
|
||||
Node: Examples, Previous: Statements, Up: Top, Next: Statements
|
||||
|
||||
|
||||
EXAMPLE1
|
||||
|
||||
Variable settings.
|
||||
|
||||
Procedure Body Indentation: 2
|
||||
Indent After Procedure: 5
|
||||
Indent after IF: 2
|
||||
Indent after THEN: 2
|
||||
Indent after ELSE: 1
|
||||
Indent after BEGIN: 3
|
||||
Indent after REPEAT: 4
|
||||
Indent after DO: 3
|
||||
Automatic Capitalization: 0
|
||||
BEGIN on same line: 0
|
||||
THEN on same line: 0
|
||||
ELSE on same line: 0
|
||||
|
||||
Indentation (assuming start column is left margin).
|
||||
|
||||
|
||||
procedure xx;
|
||||
|
||||
var b: integer;
|
||||
begin (* xx *)
|
||||
March;
|
||||
end; (* xx *)
|
||||
|
||||
while Foo do
|
||||
begin
|
||||
Bar;
|
||||
end; (* while *)
|
||||
|
||||
repeat
|
||||
Fosit;
|
||||
until false;
|
||||
|
||||
if x
|
||||
then
|
||||
Bar
|
||||
else
|
||||
Rag;
|
||||
|
||||
|
||||
EXAMPLE2:
|
||||
|
||||
The modern indentation style proposed by Arthur Sale might have these
|
||||
settings:
|
||||
|
||||
Indent After Everything: 4
|
||||
Automatic Capitalization: 1
|
||||
BEGIN on same line: 1
|
||||
THEN on same line: 1
|
||||
ELSE on same line: 1
|
||||
Match Block Word: 0
|
||||
|
||||
With resulting code indented this way:
|
||||
IF cond THEN BEGIN
|
||||
stmts;
|
||||
END; (* IF *)
|
||||
|
||||
PROCEDURE Foo(bar,baz: real);
|
||||
|
||||
VAR i: INTEGER;
|
||||
|
||||
BEGIN (* Foo *)
|
||||
body;
|
||||
END; (* Foo *)
|
||||
|
||||
Node: Comments, Previous: Statements, Up: Top, Next: Paren Groups
|
||||
|
||||
There are various things that you can do with comments in Pascal mode
|
||||
(most also work in other language mode). You can ask EMACS to start
|
||||
comments for you, go to the next comment, and go to the previous
|
||||
comment. There is also a global comment mode (only in Pascal) which
|
||||
allows you to enter a large comment, for instance at the beginning of
|
||||
a program.
|
||||
|
||||
To ask EMACS to start a comment on the current line, use the command
|
||||
Meta-;. This will go to the end of the line and start a comment by
|
||||
inserting open and close comment brackets and leaving the point
|
||||
between them. If there is already a comment on the line, EMACS will
|
||||
realign it and then move into it. C-U C-X ; will create a comment
|
||||
lined up with comment on the previous line, and make all subsequent
|
||||
comments also try to start in that column. M-* will create a comment
|
||||
at the current cursor position always (Pascal only).
|
||||
|
||||
If you want EMACS to always start comments no further left than a
|
||||
specific column, go to the column you want, and type C-X ; (Control-X
|
||||
Semicolon). EMACS should confirm by typing Comment Column = n at the
|
||||
bottom of the screen, where n is the column you changed it to. If you
|
||||
want to have the same one set up for you each time you start Pascal
|
||||
mode, set the variable Comment Column in you Pascal Mode Hook.
|
||||
*Note Vars: (EMACS)Variables.
|
||||
|
||||
If you want to go on and enter a comment at the end of the next line,
|
||||
you can use the command M-N to move down to (and maybe create) a
|
||||
comment on the next line. Similarly, you can use M-P to go up a line
|
||||
and start a comment.
|
||||
|
||||
To kill a comment at the end of the line use C-M-;. You can also use
|
||||
this to move a comment by killing it and then un-killing it where you
|
||||
want it to be. *Note Un-Killing: (EMACS)Un-killing.
|
||||
|
||||
There is another way to enter comments, and that is the global
|
||||
comment mode. To use this, use the command M-X Global Pascal Comment.
|
||||
This will enter a special mode where you will be entering a block of
|
||||
comments. Each comment will start in the 2nd column, and will start
|
||||
with "(**" (or "{*"). You can use the commands M-;, M-N, and M-P as
|
||||
described above. When you're done entering the block of comments,
|
||||
exit the inner mode with C-M-C (C-M-Z on Twenex). As it leaves, it
|
||||
will convert the beginnings of the comments to "(* " (or "{ ", and
|
||||
move the ends so that they all line up.
|
||||
|
||||
As it leaves the global comment mode, it will also convert any line
|
||||
which looks like "(*** *)" into a line of stars and spaces:
|
||||
"(* * * ...*)".
|
||||
|
||||
Node: Paren Groups, Previous: Comments, Up: Top, Next: Hints
|
||||
|
||||
The parenthesis manipulation functions are really LISP commands and
|
||||
their names reflect it. A "Sexp" is (for our purposes) either a
|
||||
parenthesized expression or a single word (depending what we are next
|
||||
to). Commands for manipulating them are:
|
||||
|
||||
C-M-F ^R Forward Sexp
|
||||
C-M-B ^R Backward Sexp
|
||||
C-M-K ^R Kill Sexp
|
||||
C-M-Rubout ^R Backward Kill Sexp
|
||||
C-M-K ^R Kill Sexp
|
||||
C-M-@ ^R Mark Sexp
|
||||
|
||||
In addition to the Sexp's there are "Lists". These are also
|
||||
parenthesized expressions, but we have additional commands for moving
|
||||
"down" inside the parens and "up" out of the paren group.
|
||||
|
||||
C-M-( ^R Backward Up List
|
||||
C-M-) ^R Forward Up List
|
||||
C-M-D ^R Down List
|
||||
C-M-U ^R Backward Up List
|
||||
|
||||
|
||||
Node: Hints, Previous: Paren Groups, Up: Top, Next: Hackers
|
||||
|
||||
. To figure out your BEGIN/END pairing, use the command M-X Display
|
||||
Matching Lines to show only the lines with a BEGIN or END. You can
|
||||
also use C-M-P and C-M-N to move over matching BEGIN/END (or
|
||||
REPEAT/UNTIL, etc.) pairs.
|
||||
|
||||
. Use M-X ^R Indent Rigidly (C-X TAB) to conveniently change the
|
||||
indentation of a block of text.
|
||||
|
||||
. Use ^R Back to Indentation (M-M) to move to the logical start of
|
||||
this line. ^R Up Indented Line and ^R Down Indented Line will move
|
||||
over their <arg> lines and end up at their logical start.
|
||||
|
||||
Node: Hackers, Previous: Hints, Up: Top, Next: Philosophy
|
||||
|
||||
This section is designed for people intending to do work on Pascal
|
||||
Mode, to install it on another system, or to modify it into another
|
||||
language. It might also be interesting and/or helpful for a heavy
|
||||
user of Pascal Mode.
|
||||
|
||||
* Menu:
|
||||
|
||||
* Philosophy:: Reasons why some things are how they are.
|
||||
* Syntax Table:: Table which keeps the syntax of interesting keywords.
|
||||
* Install:: Information for somebody installing or re-targetting.
|
||||
* Algorithms:: Description of the less obvious algorithms used.
|
||||
* Future Work:: If you know or want to learn TECO and have time...
|
||||
|
||||
Node: Philosophy, Previous: Hackers, Up: Hackers, Next: Syntax Table
|
||||
|
||||
The idea behind Pascal (or any language mode) in EMACS is to give the
|
||||
user extra support by allowing the editor to know something about the
|
||||
higher level structure of his file. At the same time, the reason
|
||||
there is not a seperate "structured editor" for Pascal is so that the
|
||||
basic commands will be common between all editing tasks.
|
||||
|
||||
Because of the last point, it has been my attempt in Pascal Mode to
|
||||
minimize the disturbance of the user's basic editing. That's why I
|
||||
broke with standard EMACS philosophy and did not put the line indenter
|
||||
on TAB.
|
||||
|
||||
The reasons all of the keys defined are control-meta- commands are 1)
|
||||
to provide a better mnemonic for the user to remember where all the
|
||||
Pascal commands are, 2) because they replace unused keys or dangerous
|
||||
LISP commands, and 3) so that there will be a consistent "language
|
||||
prefix" which users know will be squashed by the major modes. It is
|
||||
my opinion that more major modes should follow this practice.
|
||||
|
||||
A lot of work has gone in to making the indentation commands correct
|
||||
and fast. This allows the user to ignore the question of indentation
|
||||
when typing in text and frees his concentration for more important
|
||||
aspects of the program. At the same time, I have attempted to keep
|
||||
the base algorithm as simple as possible; the user has to understand
|
||||
what is going on in the algorithm to get the most good out of it, and
|
||||
simple is better for that.
|
||||
|
||||
Node: Syntax Table, Previous: Philosophy, Up: Hackers, Next: Install
|
||||
|
||||
The syntax table is read from EMACS:PASCAL.SYN by the function M-X &
|
||||
Read Keywords when Pascal is loaded. There is one line per keyword.
|
||||
The first word on the line is the keyword itself, the second word is
|
||||
the default indentation, and the third word is a binary word of the
|
||||
"descriptor" bits. On loading the Pascal library, the file is read
|
||||
into the q-vector variable Pascal Syntax Table. This variable exactly
|
||||
mirrors the structure of the file.
|
||||
|
||||
The bits in the status word are decoded as follows: 1 (the least
|
||||
significant) is set for keywords which are "block beginners", things
|
||||
like BEGIN, REPEAT, RECORD & CASE; 2 is set for the "block enders"; 3
|
||||
& 4 are set for ELSE and THEN, resp., because these are matched up
|
||||
with each other when going back over a nested statement; 5 is for
|
||||
non-compounding and non-if keywords like WHILE, DO, WITH; 6 is for the
|
||||
subprogram statements, PROGRAM, PROCEDURE & FUNCTION; 7 is for the
|
||||
declaration keywords, LABEL, TYPE, CONST, & VAR; 8 is for the IF-Block
|
||||
Body keywords (IF, THEN, ELSE); 9 is for THEN and DO because when
|
||||
they end a sub-statement, the following statement is nested from that
|
||||
statement; and 10 is for BEGIN alone becuase it has significance as a
|
||||
simple blocker the other "block beginners" don't have.
|
||||
|
||||
Node: Install, Previous: Syntax Table, Up: Hackers, Next: Algorithms
|
||||
|
||||
Most of the language dependancies for indentation are keyed through
|
||||
the syntax table. If you can't get the indenter to work for your site
|
||||
by making changes to the syntax table, try adding a new entry to the
|
||||
syntax table and updating the indent macro for both languages. It
|
||||
will be nice to have as much in common as possible between structured
|
||||
languages.
|
||||
|
||||
Any characters which can appear in keywords should be listed in the
|
||||
routines & Back To Word and & Forward To Word.
|
||||
|
||||
Macros which would probably have to be replaced are Pascal Mode and &
|
||||
Default Init Pascal Mode. Macros which will have to be modified or
|
||||
replaced because of language dependancies which are not in the syntax
|
||||
table are the insert macros, Mark Procedure, and & Save Errors (which
|
||||
goes through the listing file getting the info on all the compiler
|
||||
errors when ErrList mode is in effect). There is also a shameful but
|
||||
necessary direct dependance on the syntax of the compiler. See & In
|
||||
ErrList Mode and the file PASCAL.MIC for places to make changes.
|
||||
|
||||
Also, in general when I look to ignore comments or strings I assume
|
||||
that both "{}" and "(* *)" are comment delimiters in addition to the
|
||||
variables Comment Start and Comment End. This is becuase our version
|
||||
of Pascal allows both those comment delimiters and more. The routines
|
||||
where this occurs are M-X & Forward To Chars, M-X & Back To Chars, and
|
||||
M-X ^R Pascal Begin. In the former two routines I pass over quoted
|
||||
strings, which I assume are bounded by a single quote, "'", on each
|
||||
side. If your language uses different or alternate string delimiters
|
||||
this will have to be changed in line, too.
|
||||
|
||||
Node: Algorithms, Previous: Install, Up: Hackers, Next: Future Work
|
||||
|
||||
Most of the algorithms used in the file are straight forward and are
|
||||
commented in line.
|
||||
|
||||
* Menu:
|
||||
|
||||
* Indentation:: How & Indent Line works
|
||||
* Error Saving:: Kluges for ErrList mode
|
||||
|
||||
Node: Indentation, Previous: Algorithms, Up: Algorithms, Next: Error Saving
|
||||
|
||||
The indent macro has four phases it goes through in trying to indent a
|
||||
line: scanning for the key token, moving back over begin/end pairs,
|
||||
moving back to controlling statements if the one found is nested, and
|
||||
rejoining split lines.
|
||||
|
||||
The first involves scaning back in the immediately previous line (or
|
||||
to any line which has an open paren or open comment for a close on
|
||||
this line) till it finds a keyword with a non-negative indent value or
|
||||
a block ender. If a semicolon is encountered it's presence is noted
|
||||
by setting the indent value to -2 (it starts as -1); after we see a
|
||||
sem we usually don't care if there is a keyword with a non-negative
|
||||
indent value (we want to line up with "IF x < 0 THEN Write(x);").
|
||||
However, we do pick up an indent value if we see one of the subprogram
|
||||
keywords or declaration keywords (you want to indent extra after "VAR
|
||||
i: Integer;").
|
||||
|
||||
At the end of that stage, if we have found a positive indent keyword,
|
||||
we are at our goal; we will indent from this statement offset by the
|
||||
value of the indent for that keyword and skip the next two stages. If
|
||||
we found a Block Beginner and Match Block Word is set, allign with the
|
||||
word (and goto DONE0 to avoid calculating a new position). Otherwise
|
||||
align with the indentation of this statement (DONE1).
|
||||
|
||||
Otherwise, we just want to line up with the proper line, but finding
|
||||
it will be tricky. In the next stage we continue back over the last
|
||||
line (and those connected by parens) to see if there is a block ender.
|
||||
If so, we use Back Level to move backwards to the matching beginer;
|
||||
the statement controling the one with the beginner keyword is the one
|
||||
we want to line up the next statement with.
|
||||
|
||||
This section also takes care of re-indenting ENDs. There are two
|
||||
philosophies on aligning ENDs which are supported. One says they
|
||||
should be lined up with the statements of the block. To get this
|
||||
behavior the user sets Reindent End to zero -- END's will be left
|
||||
alone where the normal statement indenter put them. The philosophy
|
||||
holds that the END (or UNTIL) should match the indentation of either
|
||||
the line with the beginner or (if Match Block Word is set) the
|
||||
beginner word itself. In this case the END will not be indented
|
||||
correctly in the text because we indented it for a statement; this
|
||||
stage takes care of properly re-aligning it.
|
||||
|
||||
The next stage goes back over nested statements (all substatements
|
||||
which end in THEN or DO nest the next statement) and THEN/ELSE pairs
|
||||
to the actual line we want to indent from. If we come to a THEN and
|
||||
the there was no SEM on the first line saw in the back parsing, assume
|
||||
the user is about to type an ELSE and indent the line the same as the
|
||||
THEN.
|
||||
|
||||
When we finally have the exact statement we want to match, we still
|
||||
can't count on it's being entirely on the line we went to. When
|
||||
conditions for an IF or WHILE or such get too large people often split
|
||||
them between several lines. The simple fix is to scan back to the
|
||||
matching IF or WHILE or such whenever we wound up on a DO or THEN.
|
||||
The two complications are 1) we want to do the same thing for THEN
|
||||
BEGIN and 2) many people like to have the THEN on a seperate line from
|
||||
the IF. To fix (1) we just move back over a BEGIN before checking for
|
||||
the THEN/ELSE and to fix (2), we check to be sure that the THEN or DO
|
||||
is not the first word on the line.
|
||||
|
||||
Now we finally have a line and a position in a line. The indentation
|
||||
is done and properly marked to be shown if the user is curious about
|
||||
what happened.
|
||||
|
||||
|
||||
Node: Error Saving, Previous: Indentation, Up: Algorithms, Next: Algorithms
|
||||
|
||||
None of the algorithms for this part are particularly brilliant;
|
||||
instead the problem is that they are somewhat klugy. There has been a
|
||||
constant race with the compiler developers who like to change the
|
||||
syntax for calling the compiler with a listing file and to change the
|
||||
format of the listing file itself.
|
||||
|
||||
When ErrList mode is selected, the hooks used by M-X Compile are
|
||||
arranged so that a listing file will be created on the compilation and
|
||||
so that M-X & Compile Compilation will be called after the compile.
|
||||
|
||||
M-X & Compile Compilation grabs the listing file in the buffer *LST*
|
||||
and deletes the file from disk. Then it calls M-X & Save Errors to
|
||||
extract the relevant information the errors from the listing file and
|
||||
build a q-vector to contain them. To find each error we search for
|
||||
a consistent string which the compiler puts on error lines. From the
|
||||
error line we get the error message (to display) and the position in
|
||||
the line of the error. From the previous line we extract the line
|
||||
number. While we are searching for the error messages we also keep
|
||||
the current page active.
|
||||
|
||||
M-X ^R Next Error just keeps an index into the q-vector of error
|
||||
information. Each time it is called it updates the pointer, hops to
|
||||
page, line, and line pos of the error and prints out the error
|
||||
message.
|
||||
|
||||
This will all work much better when I 1) hack the compiler to put out
|
||||
an error listing which contains just the errors and has the
|
||||
information I need in a more direct format (I might even convince it
|
||||
to give me the character position of the errors) and 2) hack TECO to
|
||||
have updating marks in the file. As things stand now, if the user
|
||||
inserts a page before the page of the error, or a line before the line
|
||||
of the error in the page of the error, or a character before the
|
||||
position of the error in the line of the error, everything is messed
|
||||
up. All those operations are reasonably likely in the course of
|
||||
fixing the previous errors. The fix will be to mark the positions of
|
||||
all the errors with updating marks so that we can still find them
|
||||
after all the changes have taken place.
|
||||
|
||||
|
||||
Node: Future Work, Previous: Algorithms, Up: Hackers, Next: Hackers
|
||||
1. Cases the indenter gets wrong
|
||||
A: After the declarations and before the BEGIN of a block we indent
|
||||
for another declaration.
|
||||
Fix: Re-indent previous line when BEGIN typed if previous keyword
|
||||
is a declaration keyword or subprogram keyword? Bad.
|
||||
|
||||
B: After the last END of a procedure. Tends to line up with a
|
||||
declaration statement of the ENDed procedure instead of with the
|
||||
PROCEDURE line itself.
|
||||
Fix: ?
|
||||
|
||||
C: Labels are totally ignored. I could find no clean way to handle
|
||||
them.
|
||||
Fix: Correct behavior = ? Statement labels (those which start on
|
||||
the left margin?) should be totally ignored, both in syntactic
|
||||
processing (make "back to token" ignore them?) and in
|
||||
determining the indentation of the line they're on. Case
|
||||
labels should probably have an indent after them if there is
|
||||
no text after them, but they should be ignored if there is
|
||||
text on the same line as them.
|
||||
D: After a THEN when it is on the same line as the IF.
|
||||
|
||||
2. Mark Procedure should be able to handle procedures with nested
|
||||
procedures.
|
||||
|
||||
3. Automatic capitalization should not expand the words in comments.
|
||||
This is easy but expensive to do. You just put a macro on each
|
||||
expansion definition which does a search backwards for an open or
|
||||
close comment. If an open comment is found, we are in an abbrev
|
||||
and the abbrev should be unexpanded.
|
||||
|
||||
4. Match Block Word should be replaced by a bit per keyword saying
|
||||
whether to match that keyword. This is for two reasons: 1) many
|
||||
people like to match RECORD but few like to match BEGIN and 2) this
|
||||
will allow people to indent like this if they want:
|
||||
IF c1 THEN WHILE c2 DO
|
||||
s;
|
||||
|
||||
5. The insert commands should be hacked to be one command parsing a
|
||||
general schema string. Maybe add a bit to the symbol table
|
||||
corresponding to "Indent After <x>" to help out.
|
||||
|
||||
6. The language dependancies of Mark Procedure and the insert routines
|
||||
should be eliminated. The insert routines should have one driver
|
||||
to which a schema is passed; they are too ad hoc and messy as it is.
|
||||
| ||||