🚨 Oracle not porting Rdb to x86 and EOL on Itanium 12/2027 🚨

The TPU Editor, Rebuilt for Modern Systems

Faithful DECTPU for Linux, macOS, and Windows: full built-in surface, multi-window layout, real TPU scripting language, and modern extensions — migrated apps keep running without retraining.
tpu — notes.txt
$ ./tpu notes.txt
────────────────────────────── notes.txt ──────────────────────────────
LOOP
  EXITIF CURRENT_ROW > 10;
  IF CURRENT_LINE = "" THEN ERASE_LINE; ELSE MOVE_VERTICAL(1); ENDIF;
ENDLOOP;
[EOB]
notes.txt  *  Modified  INSERT  3/27 :12
Ctrl-Z command, Ctrl-X EXIT, F2 or HELP for help
VX/TPU 1.1 — 84-test regression suite passing on macOS, Linux, and Windows. Full DECTPU built-in surface plus undo, box selection, incremental find, system clipboard, and ~/.tpurc startup files.
Capabilities

Everything DECTPU, with the modern parts you actually wanted.

Built-ins behave like the manual says. Where DECTPU was missing pieces, VX/TPU adds them — without losing the script-level compatibility you have under EVE.

🖥️

Multi-window layout

Horizontal and vertical splits, per-window status lines, CREATE_WINDOW, MAP/UNMAP, ADJUST_WINDOW, plus Ctrl-O and Ctrl-N shortcuts.

🔍

Pattern engine

ANCHOR, ANY, NOTANY, ARB, SCAN/SCANL, SPAN/SPANL, LINE_BEGIN, LINE_END, PAGE_BREAK, REMAIN, UNANCHOR. Composed with + and &.

⌨️

Real key maps

CREATE_KEY_MAP, CREATE_KEY_MAP_LIST, ADD_KEY_MAP, per-buffer SET (KEY_MAP_LIST), GOLD prefix, custom shift key, PRE/POST_KEY_PROCEDURE.

📋

First-class types

PATTERN, RANGE, MARKER, BUFFER, ARRAY, PROGRAM, LEARN, PROCESS. Assign them, return them, pass them to procedures.

🧠

Real language

IF/THEN/ELSE/ENDIF, LOOP/EXITIF/ENDLOOP, PROCEDURE with parameters, LOCAL declarations, ON_ERROR handlers, ! comments, - line continuation.

🛠️

FAO that works

Strings !AS, signed !SL, unsigned !UL, hex !XL, octal !OL, binary !BL, padded !nZL, plural !%S, date !%D, time !%T.

📐

Margins & wrap

SET (LEFT_MARGIN), SET (RIGHT_MARGIN), SET (MARGINS), SET (TAB_STOPS), SET (WRAP) with auto-wrap on type, tab-stop expansion on Tab.

🖱️

Mouse, timers, hooks

SET (MOUSE), LOCATE_MOUSE, SET (TIMER, ms, "stmt"), UNDEFINED_KEY, SHIFT_KEY.

🔗

External processes

CREATE_PROCESS("sort", out), SEND, SEND_EOF, ATTACH. Output streams non-blockingly into a buffer.

📓

Journals & learn

JOURNAL_OPEN, JOURNAL_CLOSE, RECOVER_BUFFER, LEARN_BEGIN, LEARN_END returns a replayable LEARN value.

🧪

Headless test mode

tpu --test file.tpu runs your TPU code without the screen, with built-in ASSERT, ASSERT_EQ, and TEST sections. CI-friendly.

🪟

Linux · macOS · Windows

One C++17 file. ncurses on POSIX, PDCurses on Windows. Tested under bash, zsh, and PowerShell 7.

↩️

Undo / redo

Per-buffer 200-snapshot undo stack. UNDO, REDO, plus GOLD-U / GOLD-R. Read-only commands never invalidate the redo history.

📦

Box selection

Rectangular selection: BOX SELECT, BOX CUT, BOX COPY, BOX PASTE. Renders as a real rectangle with the same selection machinery.

🔎

Live incremental find

Ctrl-F jumps to the first hit as you type. Ctrl-F again advances; Esc restores the original cursor. No popup; the message line is the prompt.

📋

System clipboard

WRITE_CLIPBOARD, READ_CLIPBOARD wrap pbcopy/pbpaste, wl-copy/wl-paste, xclip/xsel, and the Win32 clipboard.

🧩

CALL_USER → dlopen

CALL_USER(symbol, arg [, library]) loads a shared object (dlopen/LoadLibrary) and calls const char* fn(const char*), returning the result as a string.

🚦

Reload & backups

Captures file mtime on load. RELOAD / CHECK_DISK detect on-disk changes. WRITE_FILE renames the existing file to .bak first (toggle with SET (BACKUP, OFF)).

🎨

Video regions

SET (VIDEO, range, BOLD|REVERSE|UNDERLINE|...) paints ncurses attributes over a Range — the foundation for syntax highlighting hooks driven from TPU code.

📜

Persistent startup file

$TPU_STARTUP or ~/.tpurc is auto-COMPILEd at boot. Bind keys, define procedures, set margins — all your customisations load automatically.

📰

Custom status lines

SET (STATUS_LINE, win, "TEXT", " %n %m %l/%t :%c %d ")%n name, %f file, %l/%t line/total, %c column, %m modified, %i insert mode, %d direction.

🔢

Numeric base literals

Real DECTPU numeric literals: %X1A, %XFF, %O17, %B1010, %D42. Mix with the standard decimal literals.

📚

Help in many shapes

Inside the editor, HELP opens a system buffer. From a script, HELP_TEXT(topic) returns the body as a string. 17 topic sections.

📝

MESSAGE_BUFFER scrollback

Every MESSAGE appends to $MESSAGE_BUFFER, capped at 1000 lines. Visit it with BUFFER $MESSAGE_BUFFER to see history.

⚠️

Compile-time errors

Each Stmt carries its source line. Unknown commands report "Unknown command: foo (line 27)"; missing ENDPROCEDURE is recorded in parser.compile_diagnostics.

📊

SHOW everything

SHOW BUFFERS, KEYMAPS, KEY_MAP_LISTS, PROCEDURES, VARIABLES, DEFAULTS, SUMMARY, SYSTEM, KEY [name].

"Drop-in DECTPU built-ins, real first-class values, and a multi-window ncurses screen — in a single C++ file."

A faithful TPU you can hack on.

Reference

Command-line commands

Everything below is callable after pressing Ctrl-Z in the editor, or programmatically from a TPU procedure.

Files

CommandDescription
WRITE [file]Save the current buffer
SAVE FILESave the current buffer
GET fileOpen file in a new buffer
INCLUDE fileInsert file at cursor
EXIT / QUITLeave the editor
SPAWN cmdSuspend the editor and run a shell command

Movement & Buffers

CommandDescription
TOP / BOTTOM / ENDBuffer top / bottom
GO TO nJump to line n
GO TO COLUMN nJump to column n
WHAT LINE / WHAT BUFFERReport current state / list buffers
NEXT BUFFER / PREVIOUS BUFFERRotate buffers
BUFFER nameSwitch / create
RELOAD / CHECK_DISKReload from disk / check mtime

Editing

CommandDescription
SELECT / SELECT_RANGEStart / inspect a range
COPY / CUT / PASTEInternal clipboard register
READ_CLIPBOARD / WRITE_CLIPBOARDSystem clipboard (pbcopy / xclip / Win32)
DELETE / REMOVE / RESTORESelection-aware delete & paste-back
BOX SELECT / BOX CUT / BOX COPY / BOX PASTERectangular selection
UNDO / REDO200-snapshot history per buffer
FILLFill SELECT_RANGE within margins
SHIFT LEFT|RIGHT [n]Shift all lines
CHANGE CASE UPPER|LOWEROn the selection or the current word
ERASE_LINE / ERASE_CHARACTER nDelete by line or by character

Buffers & SET

CommandDescription
SET INSERT / OVERSTRIKEText-entry mode
SET MODIFIED|MODIFIABLEBuffer flags
SET NO_WRITE / PERMANENT / SYSTEMProtection flags
SET MAX_LINES nCap buffer length
SET EOB_TEXT sText past last line (default [End of file])
SET JOURNALING fileAppend commands to a journal
SET (BACKUP, ON|OFF)Rename existing file to .bak on save
SET (KEY_MAP_LIST, name [, buf])Per-buffer key-map list
SET (VIDEO, range, BOLD|REVERSE|...)Paint ncurses attributes over a range
SET (STATUS_LINE, win, "TEXT", fmt)Custom per-window status format
SHOW BUFFERS|KEYMAPS|PROCEDURES|VARIABLES|DEFAULTS|SUMMARY|SYSTEM|KEY [name]Open a system buffer with a tabular report

Margins, Tabs & Events

CommandDescription
SET LEFT MARGIN nInsert column for new lines
SET RIGHT MARGIN nWrap column
SET MARGINS lrCombined
SET TAB STOPS n…Custom tab columns
SET (WRAP, ON|OFF)Auto-wrap on type
SET LINE NUMBERToggle the gutter
SET (MOUSE, ON|OFF)Enable mouse events
SET (TIMER, ms, "stmt")Run TPU statement on a timer
SET (PRE_KEY_PROCEDURE, "stmt")Run before each key
SET (POST_KEY_PROCEDURE, "stmt")Run after each key
SET (UNDEFINED_KEY, "stmt")Hook for unbound keys
SET (SHIFT_KEY, key)Secondary GOLD-style prefix

Windows

CommandDescription
CREATE_WINDOW(top, h [, status])New viewport
MAP(win, buf) / UNMAP(win)Attach / detach a buffer
ADJUST_WINDOW(win, dtop, dbot)Resize
SPLIT_WINDOWHorizontal split (Ctrl-O)
SPLIT_WINDOW_VERTICALSide-by-side split
NEXT_WINDOWRotate focus (Ctrl-N)
DELETE_WINDOWRemove the current window

Process & Misc

CommandDescription
SPAWN cmd / DCL cmdSuspend, run shell command
CREATE_PROCESS("cmd", outbuf)Spawn child with pipes
SEND(text [, proc])Write to child stdin
SEND_EOFClose child stdin
JOURNAL_OPEN file / JOURNAL_CLOSEAppend every statement to a journal
RECOVER_BUFFER [file]Replay a journal
LEARN_BEGIN / LEARN_ENDRecord / capture replayable sequence
CALL_USER(sym, arg [, lib])dlopen / LoadLibrary callout
HELP [topic] / HELP_TEXT(topic)17 topics; both buffer + string forms
Keys

Default key bindings

Every binding is a KEY_MAP entry — they're shown here in the default TPU$KEY_MAP_LIST. Override with DEFINE_KEY or per-buffer SET (KEY_MAP_LIST).

Movement
KeyAction
MOVE_VERTICAL / MOVE_HORIZONTAL
Home / EndLine begin / line end
PgUp / PgDnScroll a screen
Backspace / DelERASE_CHARACTER (-1 / +1)
InsertToggle INSERT / OVERSTRIKE
TabInsert tab (uses TAB_STOPS)
EnterSPLIT_LINE
Control keys
KeyAction
Ctrl-ZCommand line
Ctrl-SWRITE_FILE
Ctrl-XEXIT
Ctrl-FSEARCH / live incremental find
Ctrl-VSELECT
Ctrl-WMOVE_TEXT (cut)
Ctrl-YPaste
Ctrl-OSPLIT_WINDOW
Ctrl-NNEXT_WINDOW
GOLD combinations
KeyAction
PF1 / F1GOLD prefix
GOLD+TTop of buffer
GOLD+EEnd of buffer
GOLD+FFind
GOLD+WWrite file
GOLD+QQuit
Function keys
KeyAction
F2HELP buffer
F3FIND
F4DELETE
F6F12Available for DEFINE_KEY
PF1PF4VT-style numeric keypad
Language

The TPU language, made real

Variables, expressions, control flow, error handling, procedures with parameters, and the full DECTPU object model — including arrays and compiled programs as values.

example.tpu
! Search backwards from the cursor for a comment, capitalize it,
! and bail out gracefully if there is no match.

PROCEDURE upcase_prev_comment

    LOCAL pat := LINE_BEGIN + "!" + REMAIN;

    ON_ERROR
        MESSAGE("no comment found above");
        RETURN;
    ENDON_ERROR;

    SET (REVERSE, CURRENT_BUFFER);
    LOCAL r := SEARCH(pat);
    IF NOT r THEN ABORT; ENDIF;

    CHANGE_CASE(r, UPPER);
    POSITION(r);
    MESSAGE("done");

ENDPROCEDURE;

! And as a compiled program value:
prog := COMPILE("MESSAGE(\"hello, \" + CURRENT_BUFFER);");
EXECUTE(prog);

! Arrays:
counts := CREATE_ARRAY;
counts{"hits"} := counts{"hits"} + 1;
Build

One file. Three platforms.

VX/TPU is a single C++17 source. Pick your toolchain.

macOS / Clang

shell
brew install ncurses
clang++ -std=c++17 -O2 tpu.cpp -lncurses -o tpu
./tpu file.txt

Linux / GCC

shell
sudo apt install libncurses-dev
g++ -std=c++17 -O2 tpu.cpp -lncurses -o tpu
./tpu file.txt

Windows / MSVC + PDCurses

cmd / PowerShell
cl /std:c++17 /EHsc tpu.cpp ^
  /I C:\pdcurses ^
  C:\pdcurses\wincon\pdcurses.lib

# In PowerShell:
./tpu.exe file.txt
./tpu.exe --test tests\tpu_tests.tpu

Run the regression suite

shell
./run_tests.sh
==> Building tpu
==> Running tpu_tests.tpu
PASS  1+2
PASS  string concat
PASS  FAO !4ZL pad
...
----------------------------------------
61 passed, 0 failed

Frequently Asked Questions

Curious about how Sector7 can facilitate your application migration? Explore our FAQs for expert insights.

What is VX/EDT and when would I use it?

VX/EDT is Sector7’s faithful reimplementation of the DEC OpenVMS EDT editor for Linux and macOS. It preserves familiar line-mode commands, ncurses screen mode, GOLD-key keypad behaviour, and common qualifiers so teams moving off OpenVMS can keep the same editing workflow on POSIX systems.

For the broader platform picture—languages, runtimes, and production cutover—see Sector7’s overview of OpenVMS to Linux and UNIX migration and the technical tools directory.

Do OpenVMS EDT line-mode commands work the same way in VX/EDT?

Yes. VX/EDT is built around a drop-in compatible command set: navigation, FIND / FNDNXT, SUBSTITUTE with qualifiers such as /GLOBAL and /QUERY, buffer operations, INCLUDE / WRITE, and the usual range syntax (THRU, WHOLE, REST, and so on). Commands remain case-insensitive, matching OpenVMS EDT expectations.

Enter full-screen editing with CHANGE or C; return to the asterisk prompt with Ctrl/Z. The on-page command reference summarises behaviour for quick lookup.

How does the GOLD key work on a PC or Mac keyboard?

On OpenVMS terminals, GOLD is typically F1 / PF1. VX/EDT follows the same model: press GOLD, then the second key (for example GOLD+F2 for BOTTOM, or GOLD plus keypad keys in screen mode).

On laptops without a dedicated function row, use Fn with F1 as needed. The Screen Mode section on this page lists PF keys, cursor GOLD combinations, Ctrl keys, and GOLD+keypad bindings for day-to-day reference.

Where does VX/EDT read EDT.INI from?

At startup VX/EDT checks, in order: the path in the $EDT_INI environment variable (if set), then $HOME/EDT.INI, then $HOME/edt.ini. Lines beginning with !, #, or ; are treated as comments—in both EDT.INI and -command script files.

Use DEFINE KEY and DEFINE MACRO entries to persist PF-key, GOLD, and Ctrl bindings across sessions. The Startup & Configuration section documents invocation flags and a sample EDT.INI.

Can VX/EDT run from a command file or non-interactive workflow?

Yes. Launch with edit <file> -command <script> (or the -command=<script> form) to execute a sequence of EDT commands—useful for scripted edits, repeatable migration steps, or CI-style checks alongside other tooling.

For larger automation and assessment across a codebase, many teams pair editor workflows with LegacyScan and Sector7’s broader toolset bundles.

How do undo and redo work in VX/EDT?

UNDO (U) restores the editor to the state before the last text-changing command, with up to 100 levels of history. Each undo pushes the current state onto a redo stack so REDO can re-apply the last undone change.

Captured state includes buffer contents, named buffers, cursor position, direction, selection anchor, active search string, and delete buffers—mirroring the depth teams expect from OpenVMS EDT-style editing.

What is required to build VX/EDT from source?

VX/EDT ships as a single-file C++17 source module linked against ncurses (available by default on macOS and typical Linux distributions). A POSIX toolchain—clang++ or g++—is sufficient; there are no additional runtime dependencies beyond the OS curses library.

The optional PRINT command expects a working lpr or lp line-printer interface when used. Exact compiler examples appear in the Building VX/EDT section on this page.

Where can I get help with a larger OpenVMS migration beyond the editor?

VX/EDT removes a common friction point—keeping the EDT editing experience on modern platforms—but most production moves also involve languages, system services, databases, and operational cutover. Sector7 has delivered large-scale OpenVMS migrations since the 1980s using proprietary converters and proven methodology.

Explore migration services (including the assessment process and zero code freeze approach), browse the VX/TOOLS technical catalog, and contact us to discuss scope, timelines, and tooling fit.

Transform Your Legacy Software Today!

Get In Touch
Unlock the potential of your legacy software with our expert migration services.