shaunlebron / history-of-lisp-editing
- четверг, 29 июня 2017 г. в 03:11:47
how people tolerated parens back in the 70s and 80s
NOTE: this is research in progress (references appreciated!)
I'd like to find out how people tolerated parens back in the golden days of Lisp. I have a feeling we might've forgotten some things that would be useful today, or might influence some new ideas.
I started by working backwards from today (still filling in blanks):
In Interlisp, the programmer worked with source code presented by a structure editor, which operated on source code in the form of memory-resident Lisp data structures.
—Evolution of Lisp
A command-line interface for editing s-expressions. Rather than displaying the whole file, only one expression is displayed at a time—by printing after each command.
N
to go Nth child of current expression0
to go up to parent&
?
pp
Six paren commands can be performed on the current expression's children:
Command | Name | Mnemonic | Extra Inference |
---|---|---|---|
BI |
Both In | ()+ |
|
BO |
Both Out | ()- |
|
LI |
Left In | (+ |
adds ) at end |
LO |
Left Out | (- |
removes ) and EVERYTHING AFTER IT |
RI |
Right In | )< |
|
RO |
Right Out | )> |
(A B C D E F G H)
>(BI 3)
(A B (C) D E F G H)
^ ^ wrap parens around index 3
(A B C D E F G H)
>(BI 3 5)
(A B (C D E) F G H)
^ ^ wrap parens from index 3 to index 5
>(BO 3)
(A B _C D E_ F G H)
^ ^ unwrap parens around index 3
(A B C D E F G H)
>(LI 3)
(A B (C D E F G H))
^ ^ insert left-paren before index 3, and right-paren at end
(A B (C D E) F G H)
>(LO 3)
(A B _C D E_ _ _ _)
^ ^ ^ ^ ^ remove parens around index 3, and EVERYTHING AFTER IT
(A B (C D E F G H))
>(RI 3 2)
(A B (C D) E F G H_)
^ <----- ^ move right-paren of index 3 to inner index 2
>(RO 3)
(A B (C D_ E F G H))
^ -----> ^ move right-paren of index 3 to end
See the 1967 BBN Lisp System section on "structure changing commands" page 49.
The display editor was a visual alternative to the teletype editor—click one or two expressions in the pretty-print, then click a command to execute on those expressions.
Clicking an expression while holding Shift unreads it into the type-in window (pastes as text).
DEdit Paren Command | Initially Hidden? | Teletype Command |
---|---|---|
() |
same as BI |
|
( in |
middle-click () to show |
same as LI |
) in |
middle-click () to show |
same as RI |
() out |
same as BO |
|
( out |
middle-click () out to show |
same as LO |
) out |
middle-click () out to show |
same as RO |
See the 1985 Interlisp-D Reference Manual Volume II: Environment, Chapter 16 page 407.
SEdit later replaced DEdit as the default visual structure editor for Interlisp. It allowed the user to type directly into the pretty-printed view, and did away with the separate type-in window from DEdit. It may look closer to a normal text editor we're used to, but...
Though it appears to be a normal modern text editor, it still has the constraints of an auto-formatted structure editor. To give the user the most freedom within these constraints, a very interesting language was crafted around the mouse, allowing it to interact with the structure in a way I can only describe as vim-like. See my take on documenting its unique caret states and selection types.
After seeing this novel mouse behavior, I can see why most paren commands from DEdit and teletype editor were removed in SEdit. The mouse primitives work well with just the simplest paren commands (wrap/unwrap), exposed as hotkeys:
Hotkey | Name | Description |
---|---|---|
Meta-( |
Parenthesize | wraps selection in a list. places ▲ after ( |
Meta-) |
Parenthesize | wraps selection in a list. places ▲ after ) |
Meta-/ |
Extract | unwraps selected list, string, or quote |
Normal insertions, deletions, and clicking of parens have the following behavior:
Paren Operation | Description |
---|---|
Type ( |
inserts () with ▲ inside |
Type ) |
nothing inserted. places ▲ after next ) . selects whole list |
Backspace at ( |
removes list if empty, else no-op |
Backspace at ) |
nothing deleted. places ▲ before ) |
Middle-click ( |
selects list. places ▲ on clicked side of ( |
Middle-click ) |
selects list. places ▲ on clicked side of ) |
See the 1987 Lyric Release Notes or Medley Release Notes in Appendix B, and mailing lists musings 1, 2
ZMacs in 1980 is reported to be the first text editor with balanced parentheses commands. The 1987 ZMacs Editor Reference shows them on page 209 (3-137):
I must say that I wish I could use LISP/VM again, and Martin's editor. I've always felt it gave me the best interface, with the highest productivity, of any editor I've ever used for LISP. —Cyril N. Alberga
An important feature of Lispedit is a program display that shows the structure of a Lisp expression from the point of view of a selected sub-expression. The sub-expression, called the focus, is shown high-lighted and its relationship to the surrounding context is shown by automatically generated indentation. Selected components of the focus and its context are elided (shown as '...') in order to condense large expressions to the confines of a finite screen. —Interactive program execution in Lispedit
There are no surviving images of what Lispedit looked like. But reconstructing from descriptions:
┌────────────────────────────────────────────────────────────────┐ │TOP DISPLAY AREA: pretty-printed and condensed code ▲│ │ ("focus" expression highlighted) ││ │ ││ │ 1 (LAMBDA ││ │ 2 (INPUT) ││ │ 3 (PROG (WORDLIST) ││ │ 4 (DO ((I 0 (+ (FINDENDWORD INPUT I) 1))) ...) ││ │ 5 (SETQ WORDLIST (REVERSE WORDLIST)) ││ │ 6 (NMAPCAR ││ │ 7 (LAMBDA ││ │ 8 (WORD) ││ │ 9 (COND ││ │ 10 (((ONE-OF a e i o u) (ELT WORD 0)) &) ││ │ 11 ('ELSE ││ │ 12 (CONCAT ││ │ 13 (SUBSTRING WORD 1 (- (SIZE WORD) 1)) ││ │ 14 (SUBSTRING WORD 0 1) ││ │ 15 "ay ")))) ││ │ 16 WORDLIST) ...) ││ │ ▼│ ├────────────────────────────────────────────────────────────────┤ │FENCE LINE: (recursion-level / input-state / current-object) │ ├────────────────────────────────────────────────────────────────┤ │MESSAGE AREA: (recent command messages, multiline if needed) ▲│ │ ▼│ ├────────────────────────────────────────────────────────────────┤ │Program Function Keys: (currently defined keys) │ ├────────────────────────────────────────────────────────────────┤ │Command Area: _ │ └────────────────────────────────────────────────────────────────┘
See the 1984 LISP/VM User's Guide and Experience with an Uncommon Lisp.
In 1979, Nokolisp's editor was added as the author's reaction to the first Interlisp teletype editor, to see what it might look like as a screen-based editor.
Rather than conventional pretty-printing seen in later screen-based editors, Nokolisp's editor displayed a subexpression on each line, allowing you to move a cursor line-by-line to select one to operate on. For example:
0> fib
(lambda
(x)
(if
(< x 2)
x
(+ (fib (1- x)) (fib (- x 2)))))
1> (edit fib)
This would bring up the following editor view:
┌──────────────────────────────────────────────┐
│ BOOT fib 0 0 │
│ ( │
│ _ lambda │
│ (x) │
│ (if (< x 2) x &) │
│ ) │
│ │
│ │
└──────────────────────────────────────────────┘
(Notice &
elides the long expression for fitting.)
The _
cursor is initially on the first line. If we move _
down to the third
line, we can select and focus it to see our next view:
┌──────────────────────────────────────────────┐
│ BOOT fib 1 0 │
│ ( │
│ _ if │
│ (< x 2) │
│ x │
│ (+ (fib (1- x)) (fib (- x 2))) │
│ ) │
│ │
└──────────────────────────────────────────────┘
BOOT fib 1 0
is a status line indicating filename - function - level - ?
.
Command | Description |
---|---|
↕ |
move cursor to select an expression |
6 |
navigate into list (edit inline if atom) |
4 |
navigate out to parent list (exit if top) |
p |
toggle pretty-print |
Paren Command | Description | Example |
---|---|---|
a |
add parens | a => (a) |
r |
remove parens | (a) => a |
w |
wrap with next | a b => (a b) |
c |
conjoin with next | (a) b => (a b) |
See all the nokolisp commands.
(preferred formatted ASCII files over data structures for programs)
A discussion/debate from 1978 that reveals a lot about how people thought about text vs structure when storing and displaying their code:
Programming in an Interactive Environment: the Lisp Experience
This is so far my favorite summary of this topic from 1997. (too many great points to list). https://groups.google.com/d/msg/comp.lang.lisp/dldLx8Yj7q8/u4y2zq19XIYJ
started from Paredit credits, (could not locate sedit.el
):
The original inspirations for paredit were Interlisp-D's structure editor 'SEdit' -- a real structure editor, not a cheesy imitation like paredit -- and Guillaume Germain's sedit.el for GNU Emacs.
General: