A Release White Paper for Version 0.3.0, the First Public Release
We present CMeDit, a modeless text editor for the terminal, written in Haskell. Unusually for work in this field, the artifact described by this paper exists, compiles, and can be executed by members of the public. CMeDit reproduces the interaction conventions of graphical editors (drop-down menus, working mouse support, Ctrl+C) inside the terminal, and extends the terminal beyond its usual station: over a plain SSH connection it displays images, edits spreadsheets as a grid, and searches whole projects. The implementation is built from first principles on the GHC boot libraries, with no TUI framework and no external dependencies. Version 0.3.0 is the first public release. This white paper is published alongside it so that the Haskell community may engage with the project through its customary medium.
The Haskell community has a long and distinguished record of output. That output has overwhelmingly taken the form of conference papers, workshop proceedings, extended abstracts, doctoral theses, and tutorials explaining monads; only occasionally has it taken the form of software that a member of the public might install and run. This is not an accident of history but a matter of stated policy: the language's unofficial motto, avoid success at all costs [1], has been honoured with a diligence rare among mottos.1
This paper documents a controlled deviation from that guidance. CMeDit is a terminal text editor written in Haskell that has been compiled, run, packaged, and, as of version 0.3.0, released to the public. The author recognises that releasing working software unaccompanied would constitute an irresponsible break with tradition. The present white paper is therefore published simultaneously with the binary, restoring the field's natural equilibrium.2
The contributions of this work are threefold:
Text editing is a mature field with an extensive literature of software and a sparse literature of literature. vim and GNU Emacs shipped decades of releases without an accompanying white paper; GNU nano [4] and Microsoft Edit [5], the two editors from which CMeDit most directly descends, did likewise, and Visual Studio Code ships monthly, unencumbered by publication. This methodological gap leaves their design decisions unstated and their results, strictly speaking, uncitable. We cite them anyway, as a courtesy.
Haskell, by contrast, has produced a body of publications of exceptional quality [1, 2], the majority of it unencumbered by software. Notable exceptions exist (Pandoc, XMonad, ShellCheck) and are regarded by the community with the affectionate bewilderment reserved for statistical outliers. O'Sullivan et al.'s Real World Haskell [3] deserves particular mention; the present work elects to read its title as a challenge.
CMeDit contributes to both literatures at once: an editor for the users, and a paper for everyone else.
CMeDit is a cross between Microsoft Edit and GNU nano: a modeless editor with a drop-down menu bar, real mouse support, and system-clipboard integration. Its name is a play on CMD and "C Me Edit"; we present this fact without defence.
The design hypothesis is that the terminal's reputation for hostility is habitual rather than inherent. Nothing in the VT protocol requires that saving a file be a chord of prefix keys, or that exiting an editor be folklore. CMeDit therefore honours the conventions its users already hold, exactly and not approximately: Ctrl+S saves, Ctrl+Z undoes, Ctrl+C, Ctrl+X and Ctrl+V operate on the system clipboard, menus sit along the top of the screen and open with F10, Alt+letter, or the mouse, and the status bar is clickable. There are no modes. There is no command sublanguage. There is nothing to memorise before the first keystroke lands in the buffer.
Above this foundation sit the amenities of contemporary graphical editors: a drag-resizable file-explorer panel in the style of VS Code; a fuzzy quick-open palette (Ctrl+P) that doubles as a command palette; workspace-wide find and replace, in which replacements across a project are staged into unsaved buffers for review rather than written blindly to disk; go-to-definition; browser-style navigation history (Alt+←/→); and word completion drawn from every open buffer. Each was admitted on the same criterion: a user arriving from a graphical editor should find their existing habits already load-bearing.
CMeDit uses no TUI framework. The components such frameworks exist to provide
(raw-mode terminal control over termios, the escape-sequence parser,
the double-buffered diff renderer, the menus, the dialogs) are implemented
directly against the VT/ANSI protocol. Dependencies are restricted to the libraries
that ship with GHC, so the project compiles on a machine with no network connection
and no package index. Other communities call this property hermetic
reproducibility. We arrived at it independently.
The policy extends further than is customary. CMeDit decodes PNG (including a
from-scratch DEFLATE inflate); JPEG, both baseline and progressive,
with hand-rolled Huffman decoding and IDCT; WebP in both its lossless VP8L and
lossy VP8 forms, boolean arithmetic decoder, intra prediction, loop filter and all;
GIF (LZW); BMP; and Netpbm, against boot libraries alone. Regular-expression
search is served by a from-scratch Thompson-NFA/Pike-VM engine that runs in time
linear in the input, so a pathological pattern such as (a+)+b cannot
hang a search. The quick-open palette's fuzzy matcher is likewise original.
One inheritance from the language's research tradition proved straightforwardly valuable, and we report it in earnest. The entire editor is a pure function:
update :: Key -> Editor -> (Editor, [Effect])
Every consequence that touches the world (file I/O, the clipboard, quitting)
is returned as a value of an Effect type and performed by a thin IO
driver. Rendering is likewise pure: renderEditor builds a grid of
styled cells, and renderFrame diffs that grid against the previous
frame to emit a minimal escape stream. The consequence is that the editor's entire
logic, from cursor movement to menu dispatch, is unit-testable without a terminal
attached. Whatever one concludes about Haskell's publication habits, this is the
language doing precisely what the papers said it would.
A terminal over SSH is traditionally a place where certain work simply cannot be done. CMeDit revises the list. Opening an image file (BMP, GIF, PNG, JPEG, WebP, or Netpbm) displays it: at true pixel resolution on terminals speaking the kitty graphics protocol or sixel, and as 24-bit Unicode half-block cells everywhere else. Opening a CSV or TSV file presents a spreadsheet grid with cell editing, column sorting, and rectangular selections. Project-wide search runs across thousands of files on a background thread. None of this requires a remote desktop, a port forward, or copying files home to look at them.
These upgrades are governed by a policy we summarise as opt-in by evidence. At startup CMeDit interrogates the terminal (primary device attributes, XTVERSION, the OSC 11 background colour, cell pixel geometry, an empirical probe of the REP repeat sequence, a kitty-graphics query) and enables each enhancement only when the terminal's own replies attest to it: synchronized output, hardware scroll regions, REP run compression, pixel graphics, curly underlines, a light/dark theme that follows the terminal's background, and desktop notifications when a long operation finishes while the window is unfocused. A terminal that answers none of the probes receives the portable escape stream CMeDit would have emitted in 1995. No user, however antique their terminal, is asked to configure anything.
The buffer is a persistent Seq Text, so undo snapshots share
structure rather than copying the document. The renderer repaints only the cells
that changed and flushes each frame in a single write; input is coalesced so that a
held key can never outrun the frame rate. Multi-megabyte files open instantly, and
files large enough to warrant it load on a background thread behind a spinner
rather than a frozen screen.
The test suite is hand-rolled (external test frameworks being, definitionally,
external) and reports its findings in the format Passed N, failed M,
which we offer as a complete and sufficient specification of its output.
In a longitudinal study (n = 1), the author edited with CMeDit daily
over a whole week. Sessions were entered by typing cmedit and
exited by pressing Ctrl+Q; the exit succeeded on the first attempt in 100% of
trials, with no recourse to Stack Overflow, a result we believe has not previously
been reported for a terminal editor.
The study population consists of the author, editing the author's files, in the author's terminal. We acknowledge that the sample is small, but note that it exceeds the active user base of the median Haskell project, and that the release documented by this paper is expected to disturb this baseline, an experimental risk we accept.
CMeDit 0.3.0 is free software under the GNU General Public License, version 3. Source and releases are published at github.com/appmakernetwork/cmedit [6]. Companion marketing materials [7] are released alongside this paper; we believe CMeDit to be the first Haskell project whose launch collateral comprises both a white paper and a landing page, and we encourage replication of this result.
We have presented CMeDit, a text editor that exists, together with the white paper required to make that existence respectable. The work demonstrates that a Haskell program can be carried the full distance from type signature to installed binary without abandoning either the language's principles or its literary traditions.
Future work includes a second release, for which we have been unable to locate an established methodology, and the accompanying publications: a retrospective, an experience report, and a white paper on the reception of the present white paper [8]. A monad tutorial is deliberately left to future work; the field has, in our judgment, not yet exhausted the topic.
The author thanks the terminal emulators that answered their capability probes, and forgives those that did not.
1 Two parses of the motto circulate: avoid (success at all costs) and (avoid success) at all costs. The present work deviates from both. ↩
2 One paper per shipped artifact. We regret that the balance was briefly disturbed during the interval between the binary's completion and this document's final proofreading. ↩