Vip - Vi-Style Editor in PicoLisp

.vimrc

No double-width characters (e.g. Kanji)

No vertical window splitting (only horizontally)

No regular expressions in searches, only 'match'

No extensive error checks, diagnostics or feedback

Matching parentheses () and super parentheses []

and super parentheses Highlighting nested #{ .. }# comments

comments Knows about PicoLisp namespaces

TAB completion from internal symbols

PicoLisp-style indentation

Installation-relative "@path" names

Editable command window allowing s-expressions (REPL)

Command window is a normal editable buffer

Encryption/decryption ( :key command, needs ccrypt installed)

command, needs installed) Displays more informations in status line

Persistent marks

Returns a usable exit code to the shell

Multiple buffers and windows

Combining all move commands with change, delete, yank and external filters

optionally with a repeat count

Repeat changes with the . dot command

dot command Unlimited undo/redo

Copy/paste registers a-z, A-Z etc.

Jump marks a-z, A-Z etc.

TAB completion from path names

Spell checking ( gs command, needs hunspell installed)

The Source Code

picolisp

lib.l

~/.pil/viprc

(class +Buffer) ... (class +Window) ...

This

+Buffer

text

markup

+Window

prev

next

*CmdWin

qj

^Wj

:

!

/

Buffer number

Total number of edit buffers

The buffer's file path name

The current column

The current line number

The total number of lines in the buffer

And a percentage for the current line position

goto

getch

NIL

change

undo

redo

goLeft

goFind

word

move

*Repeat

.

command

loop

case

Running Vip

The system locale must be UTF-8

The terminal must be VT-100 compatible (XTerm, Termux, Tmux, Linux console etc.)

A 64-bit version of PicoLisp must be installed The UTF-8 locale is a general PicoLisp requirement. Due to the use of namespaces, native calls and SIGCONT handling, Vip runs only on pil64.



If you have a global installation of 64-bit PicoLisp on your machine, you can just move the file vip into some directory in your execution $PATH, and you are done.



Alternatively, you can install new PicoLisp locally, and put symbolic links into /usr/bin and /usr/lib as described in INSTALL or adjust the hash-bang in the first line to point to your local installation.



Window Management To start Vip, call it with one (or more) files names:

$ vip file.l

$ pil @lib/vip.l + : (vi "file.l") -> "file.l" # Return value is NIL if ":q" : (vi 'car) -> car

$ echo ok |vip

:n

F6

:N

F5

gf

K

\

.vimrc

qs

:n

e <file>

qx

qk

qj

qq

+

-

=

Tag Stack

K

^]

$ vip file1.l file2.l +

Q

^T

Differences to Vim

w

w

cw

dw

ce

de

cTAB

dTAB

cw

dw

u

map <LEFT> zh

map <RIGHT> zl

The Command Window

ex

:

:<cnt>!shell command

Apply shell command to the next <cnt> lines



:copy

Call a system-dependent script to copy to sysem clipboard



:ix.io

Send the current buffer to http://ix.io



:bak

Make a backup copy of the current file a file with "-" appended to the name



:kab

Restore the current file by copying the file with "-" appended to the name



:ls

List all buffers



:key

Set a key to encryp/decrypt the file with ccrypt



:m

Set a persistent mark for the current file position



:n

Go to next buffer in current window



:N

Go to previous buffer in current window



:e

Reload current buffer, discarding changes



:e <file>

Open <file> in current window



:r <file>

Read the contents of <file> into the current location in current window



:w

Write buffer to its file



:x

Exit buffer. If it was modified (only then!) write contents to the file



:q

Quit buffer, discarding changes



:bx

Exchange buffer with the next one



:bd

Delete buffer



:<count> Go to buffer <count>

ls

/

?

@

pico

: (symbols '(vip pico)) -> (pico)

Other Commands

,

F1

F2

bak

kab

F3

F4

F5

F6

F7

F8

F12

~/.pil/viprc

There is an old saying: Once in your life you should build a house, plant a tree, and write an editor. I decided to start with the last one.I implemented a subset of Vim in PicoLisp. It feels and behaves almost identically to what I'm used to, and what I have configured in my. It even has some features improved over Vim. I never really understood the quirks of vimscript, and it is easier for me to write the whole beast in PicoLisp.Not that the world needs yet another editor! Rather, I see Vip as a proof of concept, and as a collection of examples of PicoLisp coding. And of course it is fun!The "P" in "Vip" may mean "PicoLisp", but also "personalized". It does not even attempt to cover the full power of Vim, and is not intended as a replacement. But since then it is my default editor for PicoLisp code and e-mails, and of course for writing this article. So I should first report what it doessupport:(and probably other things which I did not care about)Simplicity was a major design goal, perhaps at the cost of efficiency. This may result in poor performance when editing large files with Vip.On the other hand, there are some dedicated PicoLisp features not easily available in Vim (at least I could not figure out how to do them in vimscript):In any case, Vip supports most expected features of a usable Vim subset, including:Vip is included in the PicoLisp distribution. It consists of the library in "@lib/vip.l" and an executable front-end "@bin/vip".The library has grown a lot since the original version of this article, so the line count is more than 1000 by now.It does not use any other PicoLisp libraries, only thebinary and thebase file.The first versions used the Unix "ncurses" library, which is still the standard Unix way of character screen handling. But as curses turned out to be a mess, it now uses only direct ANSI escape sequences (VT-100).If a fileexists, it is ' load 'ed as a config file. It may contain arbitrary configurations and extensions.Vip defines two classes for buffers and windows,but uses them in a somewhat unconventional, non-OOP, way. This is because these classes are final, and neither inheritance nor polymorphism is needed. Only few methods are defined, just normal functions operating implicitly on, the current window.holds the edited text in theproperty as a list of lists of characters. Each character is a transient symbol, storing markup information in its value.The markup is generated by thefunction. This function scans the whole text (a relatively expensive operation) using a ' finite state ' machine. As a result, each character is known to be either normal text, the member of a string, or of a comment of a certain nesting depth. This information is used later for highlighting strings (with underlines) and comments (cyan color), and to handle indentation and matching parentheses.displays the contents of a buffer. There may be multiple windows on a buffer, but no window without a buffer. Each window is linked to its neighbors with theandproperties.The bottom window, which is created implicitly with a default size of one line, is called the "command window" (stored in theglobal). It can get permanent focus with normal window-change commands (e.g.or), or temporary focus with commands likeor SPACE in a text window.All windows except the command window have a status line at the bottom. It displays (from left to right)If the path name is too long, the status toggles between path-only and the other informations upon each move or edit operation.Thefunction is the main workhorse to move around (jump, scroll) in the buffer and to display its contents.waits for - and returns - key-presses (if Escape was hit).Modifications of the text go throughand, to keep track of the undo and redo stacks for each buffer. The changes are done with a mixture of destructive and non-destructive list operations, to keep the amount of garbage small, yet still have data fragments which are shareable across the undo/redo steps. Usually this is achieved by destructively modifying a single cell in the top level list, saving its CAR and CDR for undo/redo.Movement functions likeorare the primitives to be combined inwith change, delete, yank and external filters, optionally with a count and other informations. It is important that they are usually never executed directly, but used to build - sometimes with the help of ' curried ' functions - executable expressions which are indeed executed, but also kept in theglobal to be repeatable with thedot command.interprets and executes text in the command window, and the longat the end of the source is the main program. Start with inspecting thestatements to find out available commands, and how Vip handles them.To run Vip on your machine, three conditions must be satisfied:or from the REPLIt will display the first file in the large main window above the single-line command window. If called without arguments, it opens an empty temporary file "~/.pil/tmp/ /empty".If called in a pipeit opens a temporary file "~/.pil/tmp/ /stdin".You can pass any number of files on the shell command line. Withoryou can open the next file(s), and withoryou can step backwards through the files.opens the file whose name is under the cursor. Similarly,jumps to the definition of the symbol under the cursor (debug mode only, see below).A backslashswitches to the most recent buffer in this window, and if you prefix with a count, the corresponding buffer is selected.As in my own, I mapped "q" to "^W", because "^W" is a bit tedious to type.Sosplits the current window into to halves, and you can scroll to other parts of the file, or open other files withoretc.exchanges the contents of two windows,changes the focus to the window above, andto the window below (possibly the command window).closes the current window, or Vip if this was the last (non-command) window.increases the size of the current window, anddecreases it.makes all windows of equal size.(orlike in Vim) open the source of the symbol under the cursor in the current window. Note that this works only when Vip was started in debug mode:This feature makes perhaps more sense when Vip is loaded as a library in the REPL while debugging other programs.With(orlike in Vim) the tag stack can be popped, going back to the previous location.Note that this "tag" functionality does not use a tag. Instead, the debug properties of the internal symbols are used directly.There are some deliberate - though not mission-critical - differences in behavior between Vim and Vip. Some of them are because I prefer them this way, and some as a consequence of the implementation.One is theword motion command. The normal Vi/Vim philosophy is that "change", "delete" etc. operate on the range specified by the motion., however, behaves differently in Vi/Vim for moves (going to the beginning of the next word) and changes (going only to the end of the current word).To keep Vip simple, and also for reasons of consistency, a command likeorwill change the text up tothe first character of the next word. This is usually not what you want. Instead, use(change to end of word) orA consistent addition is TAB in command mode, which goes to the last space before the next word. soorwill more behave likeandin Vim.Similar differences may also exist for other motion commands. As a rule, assume that Vip simply does what follows from the pure motion logic.When undoing a change operation, it often requires 2 presses of, because the removal of the old and the insertion of the new text are stored internally as separate steps. This is a bit odd at first, but turns out useful in certain situations.Not really ais the behavior of the left and right arrow keys. For that I haveandin ".vimrc".Another difference is the behavior of the command window.Vip does not implement the legacycommands which are available in Vi/Vim.Instead, we can consider the command window as a specialized REPL. It takes commands in special formats, and evaluates them.In some cases, it behaves very similar to Vi. For example, pressingin a text window will cause the focus to go to the command window, display a colon, and wait for a command. Currently only these commands are supported:For some commands (e.g.) it may be useful to increase the size of the command window.Similarly, pressingorin a text window will cause the focus to go to the command window, and start a search. Note, however, that regular expressions are not supported. You can either search for a constant text (case sensitive), or usein the search pattern as a wildcard.Writing ": " (colon plus space) followed by a Lisp expression causes this expression to be evaluated. To execute editor commands, you may need to set the namespace first, because Vip by default runs in thenamespace.In any case, the command window can be edited just like any other window, to go back in the "history", and individual lines can be re-executed by pressing ENTER.Thecomma command is redefined in Vip to fix the indentation of a paragraph (i.e. until the next empty line) according to the PicoLisp rules (3 spaces per level). It uses the internal markup information to handle strings, (nested) comments and (super)parentheses.toggles the markup highlight display (strings, comments) on and off.shows the differences (changes) of the current file and a file with "-" appended to the name (see theandcommands above).is similar, but calls a custom "dif" program. I use it with dedicated scripts which show the differences to files on other machines and/or in the incremental backups. The count prefix is used then to select the backup version.formats the current paragraph, calling the Unix "fmt" command.steps backwards through the buffers.steps forward through the buffers. load 's the current file, with output redirected to the command window.throughmay be defined in

http://picolisp.com/wiki/?vip