1## About23This is a POSIX-compatible implementation of the standard Unix text4editor [`ed(1)`][ed posix]. The implementation is written entirely in5[R7RS][r7rs] [CHICKEN Scheme][chicken] and provides a Scheme library6interface for extending the editor with custom commands.78## Status910I am presently not aware of any POSIX.1-2024 conformance issues. The11library interface, for extending `edward` with custom commands, is12usable but still very experimental and subject to change. Refer to13the `TODO.md` file for more information.1415## Design1617This implementation relies on [parser combinators][parser combinators]18as well as [hygienic Scheme macros][hygienic macros] to ease the19implementation of ed commands. Each ed command is defined using a macro20(i.e. similar to how one would normally define procedures in Scheme) and21parsed through provided parser combinators. In a sense, thus employing22[language-oriented programming][language-oriented programming] to23implement ed commands and thereby making this ed implementation very24hackable and easy to extend. The implementation is also split into a25CHICKEN program and various library components which allows defining26custom commands (refer to the library interface documentation below).2728## Installation2930The program can be installed either using [GNU make][gnu make] or31[chicken-install][chicken egg-install]. Both installation methods32presuppose that CHICKEN 6 is installed.3334### GNU make3536Installation via GNU make does not require any CHICKEN configuration37and should work out-of-the-box. As such, it is especially useful for38packaging purposes. In order to build edward using GNU make run the39following commands:4041 $ make4243To install edward to system-wide directories run the following command:4445 $ make install4647The GNU make installation method only installs the edward binary. It48does not install the library interface. If you want to interact with49the edward library you need to install edward via chicken-install.5051### chicken-install5253Contrary to installation via GNU make, this installation method requires54a properly configured CHICKEN toolchain. If CHICKEN has been configured55correctly, run the following command to install both the library and the56program component:5758 $ chicken-install5960The edward binary will be added to a directory in your `$PATH`,61furthermore the edward library will be available in your CHICKEN library62path. More usage information for the edward library is provided below.6364## Tests6566This repository contains both unit tests and integration tests. The67latter require a reference implementation of a POSIX.1-2024 compatible68ed implementation. Currently, [GNU ed >= 1.22.3][gnu ed] is used for this69purpose.7071Both unit and integration tests can be run using:7273 $ make check7475Optionally, [tmux][tmux web] can be installed to also execute tests for76edward's end-of-file handling in an interactive environment.7778## Usage7980For interactive usage I can highly recommend using this software in81conjunction with a [readline][GNU readline] frontend such as82[rlwrap][rlwrap github]. This enables readline-like keybindings (e.g.83Ctrl+A, Ctrl+W, …) as well as input history support.8485Detailed usage instructions for the `ed(1)` text editor can be found in86the [POSIX documentation][ed posix]. Additionally, a nice introduction87to the editor is provided in the book *The Unix Programming Environment*88by Brian W. Kernighan and Rob Pike (Appendix 1: Editor Summary). In89general, since ed is an old editor which hasn't changed much in the past90centuries, many historic documents explaining its usage are still91applicable today. Most notably, volume 2A of the seventh edition of the92[UNIX Programmer's Manual][unix v7vol2a] contains two documents which93provide a beginner-friendly introduction to the editor: *A Tutorial94Introduction to the UNIX Text Editor* and *Advanced Editing on UNIX*95both written by Brian W. Kernighan.9697## Library Interface9899Apart from an `ed(1)` implementation, `edward` also provides a library100interface for extending the editor with custom commands. While the101implementation provided here focuses solely on POSIX compatibility,102extension to the POSIX standard can be supplied separately using the103library interface. The `edward` library can be used by creating a custom104CHICKEN Scheme program which imports the edward libraries, defines105custom commands through provided hygienic macros, and executes106`(edward-main)` to start the editor. For example, an `edward` variant107which provides a pipe command for passing a range of lines through108a filter can be implemented as follows:109110 (import (scheme base)111 (chicken process)112 (srfi 14)113114 (edward cli)115 (edward util)116 (edward parse)117 (edward ed cmd)118 (edward ed addr)119 (edward ed posix)120 (edward ed editor))121122 ;; Executor for the pipe command123 (define (exec-pipe editor range cmd)124 (let* ((proc (process cmd))125 (lines (editor-get-lines editor range)))126 (call-with-port127 (process-input-port proc)128 (lambda (port) (lines->port lines port)))129 (let* ((in (process-output-port proc))130 (recv (port->lines in)))131 (close-input-port in)132 (exec-delete editor range)133 (exec-insert editor (car range) (car recv)))))134135 ;; Parser for the pipe command136 (define-file-cmd (pipe exec-pipe (make-range))137 (parse-cmd-char #\|)138 (parse-token (char-set-complement (char-set #\newline))))139140 ;; Start the editor141 (edward-main)142143Save this code in `edward++.scm` and compile it as follows:144145 $ csc edward++.scm146147Drop the resulting `edward++` binary somewhere in your `$PATH` and148invoke it as usual. Naturally, it is possible to define multiple custom149commands. Refer to `lib/ed/posix.scm` for the implementation of editor150commands mandated by the POSIX standard. Additional commands are also151available in a separate [edward-contrib][edward-contrib github]152repository.153154## API Documentation155156The API of the library interface is documented using Scheme source code157comments. An HTML documentation can be generated from these comments158using the [scmdoc][scmdoc github] utility. More information on that159is provided in `doc/README.md`.160161The API documentation is available via: https://files.8pit.net/edward/latest/doc/162163## History164165The existing GNU and BSD ed implementations are both derived from an166implementation written by Andrew Moore in the early-to-mid 1990s. As167such, they still share a lot of code and are potentially subject to the168same bugs [\[1\]][ed history]. To the best of my knowledge, edward is169the first ed implementation which strives to be fully POSIX compatible170but is not derived from Andrew's original implementation.171172## License173174This program includes code from [chibi-scheme][chibi-scheme github]175(`lib/parse/parse.scm`) written by Alex Shinn and licensed under a176BSD-style license. Furthermore, it includes a stripped-down and slightly177modified version of the [SRFI 214][srfi 214] reference implementation178(`lib/buffer/srfi214-minimal.scm`) written by Adam Nelson under MIT.179The program itself is licensed as follows:180181> This program is free software: you can redistribute it and/or modify it182> under the terms of the GNU General Public License as published by the183> Free Software Foundation, either version 3 of the License, or (at your184> option) any later version.185>186> This program is distributed in the hope that it will be useful, but187> WITHOUT ANY WARRANTY; without even the implied warranty of188> MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General189> Public License for more details.190>191> You should have received a copy of the GNU General Public License along192> with this program. If not, see <https://www.gnu.org/licenses/>.193194[ed posix]: https://pubs.opengroup.org/onlinepubs/9799919799/utilities/ed.html195[gnu make]: https://www.gnu.org/software/make/196[chicken]: https://call-cc.org197[chicken egg-install]: https://wiki.call-cc.org/man/5/Extensions#installing-eggs198[chicken matchable]: https://wiki.call-cc.org/eggref/5/matchable199[chicken posix-regex]: https://wiki.call-cc.org/eggref/5/posix-regex200[chicken process signal]: https://api.call-cc.org/5/doc/chicken/process/signal201[gnu ed]: https://www.gnu.org/software/ed/202[srfi]: https://srfi.schemers.org/203[srfi 204]: https://srfi.schemers.org/srfi-204/204[srfi 214]: https://srfi.schemers.org/srfi-214/205[r7rs]: https://small.r7rs.org/206[parser combinators]: https://en.wikipedia.org/wiki/Parser_combinator207[GNU readline]: https://tiswww.cwru.edu/php/chet/readline/rltop.html208[rlwrap github]: https://github.com/hanslub42/rlwrap209[unix v7vol2a]: https://s3.amazonaws.com/plan9-bell-labs/7thEdMan/v7vol2a.pdf210[hygienic macros]: https://doi.org/10.1145/319838.319859211[language-oriented programming]: https://doi.org/10.1145/3127323212[ed history]: https://lists.gnu.org/archive/html/bug-ed/2021-12/msg00001.html213[tmux web]: https://tmux.github.io214[scmdoc github]: https://github.com/nmeum/scmdoc215[edward-contrib github]: https://github.com/nmeum/edward-contrib216[chibi-scheme github]: https://github.com/ashinn/chibi-scheme