This program implements a full-screen text editor for the ZX81/TS1000, storing up to 2,880 characters of text in the string array A$(2880) and displaying a 22×32 window into that buffer on screen. The editor supports cursor movement in four directions (including word-wrap logic), insert, delete, carriage return, and tab-like jumps of 8 positions, all driven by Sinclair shifted-key codes detected via INKEY$. A blinking cursor is simulated in the GOSUB 5000 subroutine by printing a block graphic and immediately overprinting with the actual buffer character at the current position. The buffer is paged: variable A tracks the index of the first character in the current display window, advancing or retreating in steps of 32 (one screen row) as the cursor moves off screen. An auxiliary 32-character string D$ is used for the “clear to end of line” function, and a HELP menu at line 3000 documents all key bindings.
Program Analysis
Program Structure
The program is organised into a set of clearly separated functional blocks:
- Lines 10–70: Initialisation — allocates
A$(2880)as the text buffer, sets cursor position variables, and allocatesD$(32)as a scratch line buffer. - Line 300: Display refresh —
PRINT AT 0,0;A$(A TO A+703)renders the current 22-row window (22 × 32 = 704 characters). - Lines 100–999: Main dispatch loop — calls the keyboard subroutine at 5000 and uses a chain of
IF CODE B$=… THEN GOTOtests to route each keypress to its handler. - Lines 1000–1900: Individual key handlers (carriage return, backspace, cursor movement, insert, delete, tab-right, end-of-screen, end-of-line).
- Lines 3000–3099: Help menu display.
- Lines 3500–3570: Tape save routine.
- Lines 5000–5040: Keyboard input / cursor blink subroutine.
- Lines 6000–6060: Line-wrap subroutine called when
Yexceeds 31. - Lines 7000–7040: Standalone screen dump subroutine (not called from the main loop; likely a debugging aid).
- Line 9998–9999: Program self-save and restart.
Buffer and Window Model
The text buffer is the 2,880-character string A$. The display window always shows 704 characters (22 rows × 32 columns) starting at index A. The absolute buffer index of the cursor is B. Screen row and column are tracked in X and Y respectively. Scrolling is achieved by incrementing or decrementing A by 32 (one row), keeping X clamped to 0–21. This means the editor can hold 2880 ÷ 32 = 90 screen-rows of text, far exceeding what can be displayed at once.
The boundary guard at line 5020 warns the user when B exceeds 2816 (i.e., within the last 64 characters of the buffer), printing an inverse-video “NO MORE TEXT CAN BE ENTERED” message.
Key Dispatch Table
| Code | Key | Handler | Action |
|---|---|---|---|
| 19 | SHIFT+B | 1800 | Jump to beginning (A, last position in window) |
| 115 | SHIFT+5 / cursor left | 1000 | Overtype with buffer char / cursor left |
| 221 | SHIFT+T | 1900 | Clear to end of line |
| 114 | SHIFT+6 / cursor right-ish | 1100 | Backspace / cursor left |
| 216 | SHIFT+H | 3000 | Help menu |
| 16 | SHIFT+I | 1200 | Insert blank at cursor |
| 225 | SHIFT+S | 3500 | Save to tape |
| 228 | SHIFT+D | 1300 | Delete character at cursor |
| 23 | SHIFT+? | 20 | Restart (go to beginning) |
| 113 | SHIFT+7 / cursor down | 1400 | Move cursor down one row |
| 112 | SHIFT+8 / cursor up | 1500 | Move cursor up one row |
| 118 | ENTER | 1600 | Carriage return (move to start of next line) |
| 220 | SHIFT+N | 1700 | Move right 8 positions (tab) |
| 218 | SHIFT+? | 191 | Replace with space graphic "\ '" |
Cursor Blink Technique
The subroutine at line 5000 implements a software cursor blink without machine code. Line 5010 uses two consecutive PRINT AT clauses in a single statement: first it prints the block graphic "\. " (▖, a lower-left quarter block) at position (X,Y) to act as a visible cursor marker, then immediately overprints the actual buffer character A$(B) at the same position, creating a flicker effect as the display refreshes. The INKEY$ poll at line 5000 is non-blocking, looping back until a key is held down.
Insert and Delete
Insert (line 1200) uses ZX81 string slicing to open a gap: LET A$=A$( TO B-1)+" "+A$(B TO 2879). This concatenates everything before the cursor with a space and everything from the cursor onward, dropping the last character to keep the total length at 2880. Delete (line 1300) does the reverse: LET A$=A$( TO B-1)+A$(B+1 TO 2880)+" ", removing the character at B and appending a trailing space. Both operations are O(n) in buffer size and will be noticeably slow on real hardware as the buffer fills.
Clear to End of Line
Line 1900 uses LET A$(B TO B+31-Y)=D$(Y+1 TO 32), where D$ is a 32-character string (initialised by DIM D$(32) which fills it with spaces). This overwrites from the cursor position to the end of the current 32-character row with spaces in a single slice assignment — an efficient use of string array slicing.
Carriage Return Behaviour
The ENTER key handler (line 1600) does not insert a newline character into the buffer. Instead it simply advances B to the start of the next row by computing B=B+32-Y, then calls the line 1420 column-overflow handler. This means the editor is a fixed-width, grid-based word processor rather than a stream-oriented text editor — lines are always exactly 32 characters wide.
Content
Source Code
10 DIM A$(2880)
20 LET X=0
30 LET Y=0
40 LET A=1
50 LET B=1
60 DIM D$(32)
70 GOTO 300
100 SLOW
102 GOSUB 5000
103 FAST
105 IF CODE B$=19 THEN GOTO 1800
110 IF CODE B$=115 THEN GOTO 1000
115 IF CODE B$=221 THEN GOTO 1900
120 IF CODE B$=114 THEN GOTO 1100
125 IF CODE B$=216 THEN GOTO 3000
130 IF CODE B$=16 THEN GOTO 1200
135 IF CODE B$=225 THEN GOTO 3500
140 IF CODE B$=228 THEN GOTO 1300
150 IF CODE B$=23 THEN GOTO 20
160 IF CODE B$=113 THEN GOTO 1400
170 IF CODE B$=112 THEN GOTO 1500
180 IF CODE B$=118 THEN GOTO 1600
190 IF CODE B$=220 THEN GOTO 1700
191 IF CODE B$=218 THEN LET B$=" '"
200 LET A$(B)=B$
210 LET B=B+1
220 LET Y=Y+1
230 IF Y>31 THEN GOSUB 6000
300 PRINT AT 0,0;A$(A TO A+703)
999 GOTO 100
1000 LET B$=A$(B)
1010 IF X=21 AND Y=31 THEN GOTO 1030
1020 GOTO 200
1030 LET Y=-1
1040 LET A=A+32
1050 LET B$=A$(B)
1060 GOTO 200
1100 IF B=1 THEN GOTO 100
1105 LET B$=A$(B)
1110 LET B=B-1
1120 LET Y=Y-1
1130 IF Y<0 THEN GOTO 1150
1140 GOTO 300
1150 LET Y=31
1160 LET X=X-1
1170 IF X<0 THEN GOTO 1190
1180 GOTO 300
1190 LET X=0
1192 IF A<32 THEN GOTO 300
1194 LET A=A-32
1199 GOTO 300
1200 LET A$=A$( TO B-1)+" "+A$(B TO 2879)
1210 GOTO 300
1300 LET A$=A$( TO B-1)+A$(B+1 TO 2880)+" "
1310 GOTO 300
1400 LET X=X+1
1410 LET B=B+32
1420 IF X=22 THEN GOTO 1440
1430 GOTO 300
1440 LET A=A+32
1450 LET X=21
1460 GOTO 300
1500 IF B<33 THEN GOTO 300
1510 LET B=B-32
1520 IF X=0 THEN GOTO 1550
1530 LET X=X-1
1540 GOTO 300
1550 LET A=A-32
1560 GOTO 300
1600 LET B=B+32-Y
1610 LET X=X+1
1620 LET Y=0
1630 GOTO 1420
1700 LET B=B+8
1710 LET Y=Y+8
1720 IF Y>31 THEN GOTO 1740
1730 GOTO 300
1740 LET Y=Y-32
1750 LET X=X+1
1760 GOTO 1420
1800 LET B=A+703
1810 LET X=21
1820 LET Y=31
1830 GOTO 300
1900 LET A$(B TO B+31-Y)=D$(Y+1 TO 32)
1910 GOTO 300
3000 CLS
3005 PRINT " HELP MENU"
3010 PRINT ,,"SHIFT <5>","CURSOR LEFT"
3015 PRINT "SHIFT <6>","CURSOR DOWN"
3020 PRINT "SHIFT <7>","CURSOR UP"
3025 PRINT "SHIFT <8>","CURSOR RIGHT"
3030 PRINT "SHIFT <B>","BEGINNING TEXT"
3035 PRINT "SHIFT <N>","END OF SCREEN"
3040 PRINT "SHIFT <Y>","RIGHT 8 POS."
3045 PRINT "SHIFT <T>","CLEAR END LINE"
3050 PRINT "SHIFT <I>","INSERT BLANK"
3055 PRINT "SHIFT <D>","DELETE R. CHAR."
3060 PRINT "SHIFT <H>","HELP MENU"
3065 PRINT "SHIFT <S>","SAVE ON TAPE"
3070 PRINT "ENTER","CARR. RET."
3080 PRINT ,,"IF PROGRAM BREAKS, <GOTO 20> FOR BEGINNING OF TEXT. <GOTO 300> FOR LAST CURSOR POSITION. DO NOT PRESS THE <BREAK> KEY FORSPACE BETWEEN CHARACTERS."
3097 INPUT Z$
3098 CLS
3099 GOTO 300
3500 CLS
3510 PRINT ,,"SET UP RECORDER AND ENTER NAME OF FILE. FILE WILL BE SAVED WHEN<ENTER KEY IS PRESSED."
3520 SLOW
3530 INPUT Y$
3540 SAVE Y$
3550 FAST
3560 CLS
3570 GOTO 300
5000 LET B$=INKEY$
5010 PRINT AT X,Y;". ";AT X,Y;A$(B)
5020 IF B>2816 THEN PRINT AT 21,0;"% %N%O% %M%O%R%E% %T%E%X%T% %C%A%N% %B%E% %E%N%T%E%R%E%D% "
5030 IF B$="" THEN GOTO 5000
5040 RETURN
6000 LET X=X+1
6010 LET Y=0
6020 IF X=22 THEN GOTO 6040
6030 RETURN
6040 LET X=21
6050 LET A=A+32
6060 RETURN
7000 FAST
7010 CLS
7020 PRINT A$(A TO A+703)
7030 SLOW
7040 RETURN
9998 SAVE "SYNTEX%T"
9999 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

