vis: move selected prompt entry to end of the file
[vis.git] / README.md
blobaa159e6b5fc4838fd1a58fae2bd097f060ba78cb
1 Vis a vim-like text editor
2 ==========================
4 Vis aims to be a modern, legacy free, simple yet efficient vim-like editor.
6 As an universal editor it has decent Unicode support (including double width
7 and combining characters) and should cope with arbitrary files including:
9  - large ones e.g. >500M SQL dumps or CSV exports
10  - single line ones e.g. minified JavaScript
11  - binary ones e.g. ELF files
13 Efficient syntax highlighting is provided using Parsing Expression Grammars
14 which can be conveniently expressed using Lua in form of LPeg.
16 The editor core is written in a reasonable amount of clean (your mileage
17 may vary), modern and legacy free C code enabling it to run in resource
18 constrained environments. The implementation should be easy to hack on
19 and encourage experimentation (e.g. native built in support for multiple
20 cursors). There also exists a Lua API for in process extensions.
22 Vis strives to be *simple* and focuses on its core task: efficient text
23 management. As an example the file open dialog is provided by an independent
24 utility. There exist plans to use a client/server architecture, delegating
25 window management to your windowing system or favorite terminal multiplexer.
27 The intention is *not* to be bug for bug compatible with vim, instead a 
28 similar editing experience should be provided. The goal could thus be
29 summarized as "80% of vim's features implemented in roughly 1% of the code".
31 ![vis demo](https://raw.githubusercontent.com/martanne/vis/gh-pages/screencast.gif)
33 Getting started / Build instructions
34 ====================================
36 In order to build vis you will need a C99 compiler as well as:
38  * a C library, we recommend [musl](http://www.musl-libc.org/)
39  * [libcurses](http://www.gnu.org/software/ncurses/), preferably in the
40    wide-character version
41  * [libtermkey](http://www.leonerd.org.uk/code/libtermkey/)
42  * [lua](http://www.lua.org/) >= 5.2
43  * [LPeg](http://www.inf.puc-rio.br/~roberto/lpeg/) >= 0.12 (runtime
44    dependency required for syntax highlighting)
46 If you want a self contained statically linked binary you can try
47 to run `make standalone` which will attempt to download, compile
48 and install all of the above dependencies. `make local` will do
49 the same but only for libtermkey, lua and LPeg (i.e. the system
50 C and curses libraries are used).
52 To build a regular dynamically linked binary using the system
53 libraries, simply run `make` (possibly after adapting `config.mk`
54 to match your system).
56     $ $EDITOR config.mk
57     $ make
58     $ VIS_PATH=. ./vis config.h
60 Editing Features
61 ================
63 The following section gives a quick overview over the currently
64 supported features.
66 ###  Operators
68     d   (delete)
69     c   (change)
70     y   (yank)
71     p   (put)
72     >   (shift-right)
73     <   (shift-left),
74     J   (join)
75     ~   (swap case)
76     gu  (make lowercase)
77     gU  (make uppercase)
78     !   (filter)
79     =   (format using fmt(1))
81 Operators can be forced to work line wise by specifying `V`.
83 ### Movements
85     h        (char left)
86     l        (char right)
87     j        (line down)
88     k        (line up)
89     gj       (display line down)
90     gk       (display line up)
91     0        (start of line)
92     ^        (first non-blank of line)
93     g_       (last non-blank of line)
94     $        (end of line)
95     %        (match bracket)
96     b        (previous start of a word)
97     B        (previous start of a WORD)
98     w        (next start of a word)
99     W        (next start of a WORD)
100     e        (next end of a word)
101     E        (next end of a WORD)
102     ge       (previous end of a word)
103     gE       (previous end of a WORD)
104     {        (previous paragraph)
105     }        (next paragraph)
106     (        (previous sentence)
107     )        (next sentence)
108     [[       (previous start of C-like function)
109     []       (previous end of C-like function)
110     ][       (next start of C-like function)
111     ]]       (next end of C-like function)
112     gg       (begin of file)
113     g0       (begin of display line)
114     gm       (middle of display line)
115     g$       (end of display line)
116     G        (goto line or end of file)
117     |        (goto column)
118     n        (repeat last search forward)
119     N        (repeat last search backwards)
120     *        (search word under cursor forwards)
121     #        (search word under cursor backwards)
122     f{char}  (to next occurrence of char to the right)
123     t{char}  (till before next occurrence of char to the right)
124     F{char}  (to next occurrence of char to the left)
125     T{char}  (till before next occurrence of char to the left)
126     ;        (repeat last to/till movement)
127     ,        (repeat last to/till movement but in opposite direction)
128     /{text}  (to next match of text in forward direction)
129     ?{text}  (to next match of text in backward direction)
131   An empty line is currently neither a word nor a WORD.
133   The semantics of a paragraph and a sentence is also not always 100%
134   the same as in vim.
136   Some of these commands do not work as in vim when prefixed with a
137   digit i.e. a multiplier. As an example in vim `3$` moves to the end
138   of the 3rd line down. However vis treats it as a move to the end of
139   current line which is repeated 3 times where the last two have no
140   effect.
142 ### Text objects
144   All of the following text objects are implemented in an inner variant
145   (prefixed with `i`) and a normal variant (prefixed with `a`):
147     w  word
148     W  WORD
149     s  sentence
150     p  paragraph
151     [,], (,), {,}, <,>, ", ', `         block enclosed by these symbols
153   For sentence and paragraph there is no difference between the
154   inner and normal variants.
156   Additionally the following text objects, which are not part of stock vim
157   are also supported:
159     ae      entire file content
160     ie      entire file content except for leading and trailing empty lines
161     af      C-like function definition including immeadiately preceding comments
162     if      C-like function definition only function body
163     al      current line
164     il      current line without leading and trailing white spaces
166 ### Modes
168   At the moment there exists a more or less functional insert, replace
169   and visual mode (in both line and character wise variants).
170   
171   Visual block mode is not implemented and there exists no immediate
172   plan to do so. Instead vis has built in support for multiple cursors.
173   
174 ### Multiple Cursors / Selections
176   vis supports multiple cursors with immediate visual feedback (unlike
177   in the visual block mode of vim where for example inserts only become
178   visible upon exit). There always exists one primary cursor, additional
179   ones can be created as needed.
180   
181   To manipulate multiple cursors use in normal mode:
182   
183     CTRL-K   create a new cursor on the line above
184     CTRL-J   create a new cursor on the line below
185     CTRL-P   remove least recently added cursor
186     CTRL-N   select word the cursor is currently over, switch to visual mode
187     CTRL-A   try to align all cursor on the same column
188     ESC      if a selection is active, clear it.
189              Otherwise dispose all but the primary cursor.
191   Visual mode was enhanced to recognize:
192     
193     I        create a cursor at the start of every selected line
194     A        create a cursor at the end of every selected line
195     CTRL-N   create new cursor and select next word matching current selection
196     CTRL-X   clear (skip) current selection, but select next matching word
197     CTRL-P   remove least recently added cursor
199 ### Marks
201     [a-z] general purpose marks
202     <     start of the last selected visual area in current buffer
203     >     end of the last selected visual area in current buffer
205   No marks across files are supported. Marks are not preserved over
206   editing sessions.
208 ### Registers
210   Only the 26 lower case registers `[a-z]` and 1 additional default register
211   is supported.
213 ### Undo/Redo and Repeat
215   The text is currently snapshotted whenever an operator is completed as
216   well as when insert or replace mode is left. Additionally a snapshot
217   is also taken if in insert or replace mode a certain idle time elapses.
218   
219   Another idea is to snapshot based on the distance between two consecutive
220   editing operations (as they are likely unrelated and thus should be
221   individually reversible).
223   Besides the regular undo functionality, the key bindings `g+` and `g-`
224   traverse the history in chronological order. Further more the `:earlier`
225   and `:later` commands provide means to restore the text to an arbitrary
226   state.
228   The repeat command `.` works for all operators and is able to repeat
229   the last insertion or replacement.
231 ### Macros
233   `[a-z]` are recoginized macro names, `q` starts a recording, `@` plays it back.
234   `@@` refers to the least recently recorded macro.
236 ### Command line prompt
238   At the `:`-command prompt only the following commands are recognized, any
239   valid unique prefix can be used:
241     :nnn        go to line nnn
242     :bdelete    close all windows which display the same file as the current one
243     :edit       replace current file with a new one or reload it from disk
244     :open       open a new window
245     :qall       close all windows, exit editor
246     :quit       close currently focused window
247     :read       insert content of another file at current cursor position
248     :split      split window horizontally
249     :vsplit     split window vertically
250     :new        open an empty window, arrange horizontally
251     :vnew       open an empty window, arrange vertically
252     :wq         write changes then close window
253     :xit        like :wq but write only when changes have been made
254     :write      write current buffer content to file
255     :saveas     save file under another name
256     :substitute search and replace currently implemented in terms of `sed(1)`
257     :!          filter range through external command
258     :earlier    revert to older text state
259     :later      revert to newer text state 
260     :set        set the options below
262      tabwidth   [1-8]           default 8
264        set display width of a tab and number of spaces to use if
265        expandtab is enabled
267      expandtab  (yes|no)        default no
269        whether typed in tabs should be expanded to tabwidth spaces
271      autoindent (yes|no)        default no
273        replicate spaces and tabs at the beginning of the line when
274        starting a new line.
276      number         (yes|no)    default no
277      relativenumber (yes|no)    default no
279        whether absolute or relative line numbers are printed alongside
280        the file content
282      syntax      name           default yes
284        use syntax definition given (e.g. "c") or disable syntax
285        highlighting if no such definition exists (e.g :set syntax off)
287      show
289        show/hide special white space replacement symbols
291        newlines = [0|1]         default 0
292        tabs     = [0|1]         default 0
293        spaces   = [0|1]         default 0
295      cursorline (yes|no)        default no
297        highlight the line on which the cursor currently resides
299      colorcolumn number         default 0
301        highlight the given column
303      theme      name            default dark-16.lua | solarized.lua (16 | 256 color)
305        use the given theme / color scheme for syntax highlighting
307   Each command can be prefixed with a range made up of a start and
308   an end position as in start,end. Valid position specifiers are:
310     .          start of the current line
311     +n and -n  start of the line relative to the current line
312     'm         position of mark m
313     /pattern/  first match after current position
315   If only a start position without a command is given then the cursor
316   is moved to that position. Additionally the following ranges are
317   predefined:
319     %          the whole file, equivalent to 1,$
320     *          the current selection, equivalent to '<,'>
322   History support, tab completion and wildcard expansion are other
323   worthwhile features. However implementing them inside the editor
324   feels wrong.
326 ### Tab <-> Space conversion and Line endings \n vs \r\n
328   Tabs can optionally be expaned to a configurable number of spaces.
329   The first line ending in the file determines what will be inserted
330   upon a line break (defaults to \n).
332 ### Jump list and change list
334   A per window, file local jump list (navigate with `CTRL+O` and `CTRL+I`)
335   and change list (navigate with `g;` and `g,`) is supported. The jump
336   list is implemented as a fixed sized ring buffer.
338 ### Mouse support
340   The mouse is currently not used at all.
342 ### Non Goals
344   Some of the features of vim which will *not* be implemented:
346    - tabs / multiple workspaces / advanced window management
347    - file and directory browser
348    - support for file archives (tar, zip, ...)
349    - support for network protocols (ftp, http, ssh ...)
350    - encryption
351    - compression
352    - GUIs (neither x11, motif, gtk, win32 ...) although the codebase
353      should make it easy to add them
354    - VimL
355    - plugins (certainly not vimscript, if anything it should be lua based)
356    - right-to-left text
357    - ex mode (if you need a stream editor use `ssam(1)`
358    - diff mode
359    - vimgrep
360    - internal spell checker
361    - compile time configurable features / `#ifdef` mess
363 Lua API for in process extension
364 ================================
366 Vis provides a simple Lua API for in process extension. At startup the
367 `visrc.lua` file is executed, this can be used to register a few event
368 callbacks which will be invoked from the editor core. While executing
369 these user scripts the editor core is blocked, hence it is intended for
370 simple short lived (configuration) tasks.
372 At this time there exists no API stability guarantees.
374  - `vis`
375    - `lexers` LPeg lexer support module
376    - `events` hooks
377      - `start()`
378      - `quit()`
379      - `win_open(win)`
380      - `win_close(win)`
381    - `files()` iterator
382    - `windows()` iterator
383    - `command(cmd)`
384    - `info(msg)`
385    - `open(filename)`
386  - `file`
387    - `insert(file, pos, data)`
388    - `delete(file, pos, len)`
389    - `lines_iterator(file)`
390    - `name`
391    - `lines[0..#lines+1]` array giving read/write access to lines
392  - `window`
393    - `file`
394    - `cursor`
395      - `line`, `col`
396      - `pos` bytes from start of file
398 Most of the exposed objects are managed by the C core. Allthough there
399 is a simple object life time management mechanism in place, it is still
400 recommended to *not* let the Lua objects escape from the event handlers
401 (e.g. by assigning to global Lua variables).
403 Text management using a piece table/chain
404 =========================================
406 The core of this editor is a persistent data structure called a piece
407 table which supports all modifications in `O(m)`, where `m` is the number
408 of non-consecutive editing operations. This bound could be further
409 improved to `O(log m)` by use of a balanced search tree, however the
410 additional complexity doesn't seem to be worth it, for now.
412 The actual data is stored in buffers which are strictly append only.
413 There exist two types of buffers, one fixed-sized holding the original
414 file content and multiple append-only ones storing the modifications.
416 A text, i.e. a sequence of bytes, is represented as a double linked
417 list of pieces each with a pointer into a buffer and an associated
418 length. Pieces are never deleted but instead always kept around for
419 redo/undo support. A span is a range of pieces, consisting of a start
420 and end piece. Changes to the text are always performed by swapping
421 out an existing, possibly empty, span with a new one.
423 An empty document is represented by two special sentinel pieces which
424 always exist:
426     /-+ --> +-\
427     | |     | |
428     \-+ <-- +-/
429      #1     #2
431 Loading a file from disk is as simple as mmap(2)-ing it into a buffer,
432 creating a corresponding piece and adding it to the double linked list.
433 Hence loading a file is a constant time operation i.e. independent of
434 the actual file size (assuming the operating system uses demand paging).
436     /-+ --> +-----------------+ --> +-\
437     | |     | I am an editor! |     | |
438     \-+ <-- +-----------------+ <-- +-/
439      #1             #3              #2
441 Insert
442 ------
444 Inserting a junk of data amounts to appending the new content to a
445 modification buffer. Followed by the creation of new pieces. An insertion
446 in the middle of an existing piece requires the creation of 3 new pieces.
447 Two of them hold references to the text before respectively after the
448 insertion point. While the third one points to the newly added text.
450     /-+ --> +---------------+ --> +----------------+ --> +--+ --> +-\
451     | |     | I am an editor|     |which sucks less|     |! |     | |
452     \-+ <-- +---------------+ <-- +----------------+ <-- +--+ <-- +-/
453      #1            #4                   #5                #6      #2
455            modification buffer content: "which sucks less"
457 During this insertion operation the old span [3,3] has been replaced
458 by the new span [4,6]. Notice that the pieces in the old span were not
459 changed, therefore still point to their predecessors/successors, and can
460 thus be swapped back in.
462 If the insertion point happens to be at a piece boundary, the old span
463 is empty, and the new span only consists of the newly allocated piece.
465 Delete
466 ------
468 Similarly a delete operation splits the pieces at appropriate places.
470     /-+ --> +-----+ --> +--+ --> +-\
471     | |     | I am|     |! |     | |
472     \-+ <-- +-----+ <-- +--+ <-- +-/
473      #1       #7         #6      #2
475 Where the old span [4,5] got replaced by the new span [7,7]. The underlying
476 buffers remain unchanged.
478 Cache
479 -----
481 Notice that the common case of appending text to a given piece is fast
482 since, the new data is simply appended to the buffer and the piece length
483 is increased accordingly. In order to keep the number of pieces down,
484 the least recently edited piece is cached and changes to it are done
485 in place (this is the only time buffers are modified in a non-append
486 only way). As a consequence they can not be undone.
488 Undo/redo
489 ---------
491 Since the buffers are append only and the spans/pieces are never destroyed
492 undo/redo functionality is implemented by swapping the required spans/pieces
493 back in.
495 As illustrated above, each change to the text is recorded by an old and
496 a new span. An action consists of multiple changes which logically belong
497 to each other and should thus also be reverted together. For example
498 a search and replace operation is one action with possibly many changes
499 all over the text.
501 The text states can be marked by means of a snapshotting operation.
502 Snapshotting saves a new node to the history graph and creates a fresh
503 Action to which future changes will be appended until the next snapshot.
505 Actions make up the nodes of a connected digraph, each representing a state
506 of the file at some time during the current editing session. The edges of the
507 digraph represent state transitions that are supported by the editor. The edges
508 are implemented as four Action pointers (`prev`, `next`, `earlier`, and `later`).
510 The editor operations that execute the four aforementioned transitions
511 are `undo`, `redo`,`earlier`, and `later`, respectively. Undo and
512 redo behave in the traditional manner, changing the state one Action
513 at a time. Earlier and later, however, traverse the states in chronological
514 order, which may occasionally involve undoing and redoing many Actions at once.
516 Marks
517 -----
519 Because we are working with a persistent data structure marks can be
520 represented as pointers into the underlying (append only) buffers.
521 To get the position of an existing mark it suffices to traverse the
522 list of pieces and perform a range query on the associated buffer
523 segments. This also nicely integrates with the undo/redo mechanism.
524 If a span is swapped out all contained marks (pointers) become invalid
525 because they are no longer reachable from the piece chain. Once an
526 action is undone, and the corresponding span swapped back in, the
527 marks become visible again. No explicit mark management is necessary.
529 Properties
530 ----------
532 The main advantage of the piece chain as described above is that all
533 operations are performed independent of the file size but instead linear
534 in the number of pieces i.e. editing operations. The original file buffer
535 never changes which means the `mmap(2)` can be performed read only which
536 makes optimal use of the operating system's virtual memory / paging system.
538 The maximum editable file size is limited by the amount of memory a process
539 is allowed to map into its virtual address space, this shouldn't be a problem
540 in practice. The whole process assumes that the file can be used as is.
541 In particular the editor assumes all input and the file itself is encoded
542 as UTF-8. Supporting other encodings would require conversion using `iconv(3)`
543 or similar upon loading and saving the document.
545 Similarly the editor has to cope with the fact that lines can be terminated
546 either by `\n` or `\r\n`. There is no conversion to a line based structure in
547 place. Instead the whole text is exposed as a sequence of bytes. All
548 addressing happens by means of zero based byte offsets from the start of
549 the file.
551 The main disadvantage of the piece chain data structure is that the text
552 is not stored contiguous in memory which makes seeking around somewhat
553 harder. This also implies that standard library calls like the `regex(3)`
554 functions can not be used as is. However this is the case for all but
555 the most simple data structures used in text editors.
557 Syntax Highlighting using Parsing Expression Grammars
558 =====================================================
560 [Parsing Expression Grammars](https://en.wikipedia.org/wiki/Parsing_expression_grammar)
561 (PEG) have the nice property that they are closed under composition.
562 In the context of an editor this is useful because lexers can be
563 embedded into each other, thus simplifying syntax highlighting
564 definitions.
566 Vis reuses the [Lua](http://www.lua.org/) [LPeg](http://www.inf.puc-rio.br/~roberto/lpeg/)
567 based lexers from the [Scintillua](http://foicica.com/scintillua/) project.
569 Future Plans / Ideas
570 ====================
572 This section contains some ideas for further architectural changes.
574 Event loop with asynchronous I/O
575 --------------------------------
577 The editor core should feature a proper main loop mechanism supporting
578 asynchronous non-blocking and always cancelable tasks which could be
579 used for all possibly long lived actions such as:
581  - `!`, `=` operators
582  - `:substitute` and `:write` commands
583  - code completion
584  - compiler integration (similar to vim's quick fix functionality)
586 Client/Server Architecture / RPC interface
587 ------------------------------------------
589 In principle it would be nice to follow a similar client/server approach
590 as [sam/samterm](http://sam.cat-v.org/) i.e. having the main editor as a
591 server and each window as a separate client process with communication
592 over a unix domain socket.
594 That way window management would be taken care of by dwm or dvtm and the
595 different client processes would still share common cut/paste registers
596 etc.
598 This would also enable a language agnostic plugin system.
600 Efficient Search and Replace
601 ----------------------------
603 Currently the editor copies the whole text to a contiguous memory block
604 and then uses the standard regex functions from libc. Clearly this is not
605 a satisfactory solution for large files.
607 The long term solution is to write our own regular expression engine or
608 modify an existing one to make use of the iterator API. This would allow
609 efficient search without having to double memory consumption.
611 The used regex engine should use a non-backtracking algorithm. Useful
612 resources include:
614  - [Russ Cox's regex page](http://swtch.com/~rsc/regexp/)
615  - [TRE](https://github.com/laurikari/tre) as
616    [used by musl](http://git.musl-libc.org/cgit/musl/tree/src/regex)
617    which uses a parallel [TNFA matcher](http://laurikari.net/ville/spire2000-tnfa.ps)
618  - [Plan9's regex library](http://plan9.bell-labs.com/sources/plan9/sys/src/libregexp/)
619    which has its root in Rob Pike's sam text editor
620  - [RE2](https://github.com/google/re2) C++ regex library
622 Developer Overview
623 ==================
625 A quick overview over the code structure to get you started:
627  File(s)             | Description
628  ------------------- | -----------------------------------------------------
629  `text.[ch]`         | low level text / marks / {un,re}do / piece table implementation
630  `text-motions.[ch]` | movement functions take a file position and return a new one
631  `text-objects.[ch]` | functions take a file position and return a file range
632  `text-regex.[ch]`   | text search functionality, designated place for regex engine
633  `text-util.[ch]`    | text related utility functions mostly dealing with file ranges
634  `view.[ch]`         | ui-independent viewport, shows part of a file, syntax highlighting, cursor placement, selection handling
635  `ui.h`              | abstract interface which has to be implemented by ui backends
636  `ui-curses.[ch]`    | a terminal / curses based user interface implementation
637  `buffer.[ch]`       | dynamically growing buffer used for registers and macros
638  `ring-buffer.[ch]`  | fixed size ring buffer used for the jump list
639  `map.[ch]`          | crit-bit tree based map supporting unique prefix lookups and ordered iteration. used to implement `:`-commands
640  `vis.h`             | vi(m) specific editor frontend library public API
641  `vis.c`             | vi(m) specific editor frontend implementation
642  `vis-core.h`        | internal header file, various structs for core editor primitives
643  `vis-cmds.c`        | vi(m) `:`-command implementation
644  `vis-modes.c`       | vi(m) mode switching, enter/leave event handling
645  `vis-motions.c`     | vi(m) cursor motion implementation
646  `vis-operators.c`   | vi(m) operator implementation
647  `vis-lua.c`         | Lua bindings, exposing core vis APIs for in process extension
648  `main.c`            | key action definitions, program entry point
649  `config.def.h`      | definition of default key bindings (mapping of key actions)
650  `visrc.lua`         | Lua startup and configuration script
651  `lexers/`           | Lua LPeg based lexers used for syntax highlighting
653 Testing infrastructure for the [low level text manipulation routines]
654 (https://github.com/martanne/vis/tree/test/test/text), [vim compatibility]
655 (https://github.com/martanne/vis/tree/test/test/vim) and [vis specific features]
656 (https://github.com/martanne/vis/tree/test/test/vis) is in place, but
657 lacks proper test cases.