Skip to content

Latest commit

 

History

History
411 lines (320 loc) · 20.6 KB

editors.md

File metadata and controls

411 lines (320 loc) · 20.6 KB

History of editors for Lisp

Mainly focused on features related to the treatment of parentheses.

Starting backwards from today:

  • 2015 - Parinfer
  • 2014 - Paxedit
  • 2014 - Lispy
  • 2013 - vim-sexp with better keys
  • 2012 - Smartparens
  • 2005 - Paredit by Taylor Campbell
  • 2001 - DrScheme, now DrRacket
  • ...
  • 1991 - List Window, not an editor, but a fisheye pretty-print
  • 1987 - Interlisp SEdit (structure editor. full interactive display)
  • 198? - Interlisp DEdit (display editor. clickable display + command window)
  • 1980 - Lispedit (display editor)
  • 1980 - Zmacs - first structure commands for text editor
  • 1979 - Nokolisp - screen-based editor
  • ...
  • 1967 - BBN (InterLisp) - (teletype structure editor)
  • 1966 - PILOT - first thesis on structure editing

Interlisp Teletype Editor

Try it here!

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.

  • use N to go Nth child of current expression
  • use 0 to go up to parent
  • nested sub-expressions collapsed by default to &
  • expand with ?
  • pretty-print with 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.

Interlisp DEdit

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.

  1. pretty-print window (left) - click to select expressions (current=solid-lined, previous=dash-lined)
  2. command menu (right) - click to perform an operation on selections (current=arg1, previous=arg2)
  3. type-in window (below) - manually type an expression. when done, it becomes selected and clickable

dedit-screen

Clicking an expression while holding Shift unreads it into the type-in window (pastes as text).

  • left click - select object
  • middle click - select containing list
  • right click - select lowest common ancestor with previous selection
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 107.

Interlisp SEdit

Try it here!

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

sedit-screen

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

Try it here?

Zmacs in 1980 is reported to be the first text-based editor with auto-balancing paren operations.

zmacs-screen

When a cursor touched the outside of a list, the corresponding paren would blink. This is a staple feature among all text editors today.

The primary paren commands are suggested to be those associated with the simplest hotkeys:

Hotkey Description with number arg n
CTRL-( find unbalanced paren
META-( wrap () forward size n (default 0)
META-) move over next )

The others are run with META-X and by typing the full command (with the help of auto-completion):

Command Description with number arg n
META-X "Close Definition" inserts enough ))))) to end definition
META-X "Delete ()" delete ( and matching ) n th innermost ()
META-X "Grow List Backward" move ( backward over an expression n jumps (can be negative)
META-X "Grow List Forward" move ) forward over an expression n jumps (can be negative)
META-X "Make () Backward" wrap () backward size n (default 1)

To pass a number arg to a hotkey, do CTRL-1, CTRL-0, META-( for example to wrap the next 10 elements in a list.

See the 1987 Zmacs Editor Reference on page 209 (3-137)

Lispedit

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.

Nokolisp

Try it here!

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.

Nokolisp's editor displayed a subexpression on each line, allowing you to move a cursor up and down to select one to operate on. Conventional pretty-print could be toggled with p.

For example, there is a builtin function fib:

(lambda
 (x)
 (if
  (< x 2)
  x
  (+ (fib (1- x)) (fib (- x 2)))))

Running (edit fib) will start the editor, with each top-level subexpression on each line. Moving the cursor to the third line and pressing 6 will navigate into the expression as shown:

┌──────────────────────────────────────────┐            ┌──────────────────────────────────────────┐
│                             BOOT fib 0 0 │            │                             BOOT fib 1 0 │
│ (                                        │            │ (                                        │
│   lambda                                 │      ┌───> │ _ if                                     │
│   (x)                                    │      │     │   (< x 2)                                │
│ _ (if (< x 2) x &)                       │ ─────┘     │   x                                      │
│ )                                        │ go into    │   (+ (fib (1- x)) (fib (- x 2)))         │
│                                          │ expression │ )                                        │
│                                          │            │                                          │
└──────────────────────────────────────────┘            └──────────────────────────────────────────┘

(Notice & elides the long expression at first for fitting.)

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.

Maclisp

(preferred formatted ASCII files over data structures for programs)

Debating Maclisp vs Interlisp (i.e. storing code as text vs structure)

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

Appendix

Non-Lisp discussions on structure editing

Researching methods

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.

  • finding mailing list discussions
  • looking for official reference manuals of lisp machines
  • using deepdyve to find articles
  • asking around

General: