Zed Text

This file is part of and Timex Sinclair Public Domain Library Tape 1005. Download the collection to get this file.
Date: 198x
Type: Program
Platform(s): TS 1000

This program implements a full-featured text editor for the ZX81/TS1000, storing document text in a single string variable T$ and operating through a macro-command interpreter. Commands are entered as letter-prefixed macro strings where the letter selects a GOSUB target via a dispatch table array F(26) indexed by character code, allowing one-letter command codes (A=Append, C=Cursor, D=Delete, J=Justify, M=Memory, P=Print, R=Reset, S=Save, T=Test, X=Execute, Z=Stop) to route to the appropriate subroutine. The editor supports multi-page documents (640 characters per page), cursor movement with blinking via inverse-video toggling, word-wrap justification, and repeat-execution of macros via the X command. Text is stored and manipulated entirely as substring operations on T$, with memory usage reported by PEEKing the ZX81 system variables for RAMTOP and the display file pointer.


Program Analysis

Program Structure

The program is organized into an initialization block, a central macro-decode loop, and a suite of command subroutines. Initialization (lines 10–235) populates the dispatch table, then jumps to the title-screen/menu renderer at line 3670 before entering the macro interpreter at line 1000.

Line rangePurpose
10–150Build dispatch table F(26)
200–235Initialize editor state variables, jump to splash screen
1000–1230Macro decode loop
2000–2140A – Append text
2200–2390C – Cursor movement and display
2500–2590D – Delete
2800–2960J – Justify (word-wrap)
3000–3025K – LIST (mapped but labelled K & L in menu)
3100–3150M – Memory test
3300–3390P – Print page
3500–3520R – Reset (RUN)
3600–3665S – Save to tape
3670–3710Splash screen / menu, then enter decode loop
3800–3820T – Test (load sample text)
3900–3970X – Multiple/repeat execution
4000–4040Z – Stop

Dispatch Table via F(26)

Lines 10–150 initialize the array F(26) with line numbers corresponding to each command subroutine. The macro decoder (line 1200) calls GOSUB F(CODE K$-37), where K$ is the command letter. Since CODE "A" on the ZX81 is 38, subtracting 37 gives index 1 for A, 3 for C, 4 for D, and so on up to 26 for Z. Any letter without an entry in F has a default value of 0, causing a harmless GOSUB 0 to a non-existent line — a known ZX81 no-op technique.

Note that line 80 reads RAND F(12)=3000 rather than LET F(12)=3000. This is a typo or corruption; RANDOMIZE with a conditional expression will silently evaluate as a numeric statement and set the random seed, so F(12) (the L command) is never actually assigned 3000 and remains 0.

Macro Decode Loop

The loop at lines 1000–1230 accepts a line of input in M$, then scans for characters whose CODE falls in the range 38–63 (the letters A–Z on the ZX81 character set). The letter found becomes the command key K$; the digits before it become the numeric repeat count N; the characters between the letter and the next quote become the string argument W$. After the GOSUB dispatch, the parser resumes scanning for the next command in the same input string, allowing multiple commands per input line.

Text Storage and Editing

The entire document is held in the string T$. The current insert/cursor position is tracked by the integer CI. Pages are 640 characters wide (20 lines × 32 columns). Substring slicing with T$(x TO y) handles all insertions, deletions, and page extractions.

  • Append (A): Inserts N repetitions of W$ at position CI, at the start, or at the end of T$ depending on whether CI is 0, equal to LEN T$, or in between.
  • Cursor (C): Moves CI by N characters; special arguments "0" and "1" jump to page start or end of text. Cursor blinking at lines 2310–2340 loops 10 times printing the normal then inverse character.
  • Delete (D): Removes N characters from position CI using four conditional substring cases; then calls the cursor routine with N=-1 to refresh display.
  • Justify (J): Scans 32-character blocks looking for a space near position 32 to use as a word-wrap break, padding into a fixed-length DIM H$(32) to normalize the line.

Memory Reporting

The M command (lines 3100–3150) reports free space for text by reading ZX81 system variables directly: PEEK 16386 + 256*PEEK 16387 gives RAMTOP, and PEEK 16412 + 256*PEEK 16413 gives the current stack/string area pointer, with the difference being available bytes.

Notable Techniques

  • FAST / SLOW mode switching around INPUT and PRINT operations to balance display stability with execution speed.
  • GOSUB F(CODE K$-37) — a compact computed GOSUB that replaces a long IF/THEN chain for 26 possible commands.
  • The splash screen at lines 3680–3685 uses ZX81 block-graphic escape sequences to draw a decorative banner.
  • Line 55 places F(9)=3670, pointing the I command (index 9: letter I = CODE 46, 46−37=9) back to the splash/menu screen, implementing a “show menu” function.
  • The X (multiple execution) command at lines 3900–3970 re-enters the decode loop at line 1040, bypassing the INPUT, to replay the current macro N times by resetting D and I.
  • Line 4030 contains SAVE "1024" — the inverse-digit escape in the filename acts as an auto-run marker for the ZX81 tape loader.

Bugs and Anomalies

  • Line 80: RAND F(12)=3000 should be LET F(12)=3000. The L command (index 12) is therefore never registered, so the K/L listing command is inaccessible via the dispatch table despite having its subroutine at line 3000.
  • The Justify routine (lines 2820–2960) references variable V$ as both a 32-character slice of T$ and later re-DIMs H$; however, V$(I2) at line 2860 treats the previously assigned string V$ as an array, which will work on a ZX81 only if V$ is exactly 32 characters — the logic is fragile for short documents.
  • The cursor blink loop (lines 2310–2340) uses J=CODE T$(CI)+128 to compute the inverse character, relying on the ZX81 inverse-video bit (bit 7). If CI points beyond the end of T$, this will cause an error.

Content

Appears On

Assembled by Tim Ward from many sources. Contains programs 10211 – 10251.

Related Products

Related Articles

Related Content

Image Gallery

Source Code

  10 DIM F(26)
  20 LET F(1)=2000
  30 LET F(3)=2200
  40 LET F(4)=2500
  50 LET F(6)=2600
  55 LET F(9)=3670
  60 LET F(10)=2800
  70 LET F(11)=3000
  80 RAND F(12)=3000
  90 LET F(13)=3100
 100 LET F(16)=3300
 110 LET F(18)=3500
 120 LET F(19)=3600
 130 LET F(20)=3800
 140 LET F(24)=3900
 150 LET F(26)=4000
 200 LET T$=""
 210 LET CI=0
 220 LET CPN=1
 230 LET XC=0
 235 GOTO 3670
 1000 REM %M%A%C%R%O% %D%E%C%O%D%E
 1010 LET D=0
 1020 LET I=1
 1025 FAST 
 1030 INPUT M$
 1040 LET L=LEN M$
 1050 IF M$(L)<>"""" THEN LET M$=M$+""""
 1060 LET L=LEN M$
 1070 LET A=CODE M$(I)
 1080 IF A>=38 AND A<=63 THEN GOTO 1110
 1090 LET I=I+1
 1100 GOTO 1070
 1110 LET I0=I
 1120 LET K$=M$(I)
 1130 IF I0=D+1 THEN LET N=0
 1140 IF I0<>D+1 THEN LET N=VAL M$(D+1 TO I0-1)
 1150 LET I=I+1
 1160 IF M$(I)<>"""" THEN GOTO 1150
 1180 LET D=I
 1190 LET W$=M$(I0+1 TO D-1)
 1200 GOSUB F(CODE K$-37)
 1210 IF I=L THEN GOTO 1000
 1220 LET I=I+1
 1230 GOTO 1070
 2000 REM %A%P%P%E%N%D
 2010 IF N=0 THEN LET N=1
 2020 LET U$=""
 2030 FOR Q=1 TO N
 2040 LET U$=U$+W$
 2050 NEXT Q
 2060 IF CI=0 THEN GOTO 2110
 2070 IF CI=LEN T$ THEN GOTO 2130
 2080 IF CI>0 AND CI<LEN T$ THEN LET T$=T$( TO CI)+U$+T$(CI+1 TO )
 2090 LET CI=CI+LEN U$
 2100 RETURN 
 2110 LET T$=U$+T$
 2120 GOTO 2090
 2130 LET T$=T$+U$
 2140 GOTO 2090
 2200 REM %C%U%R%S%O%R
 2210 IF W$="0" THEN GOTO 2360
 2215 IF W$="1" THEN GOTO 2380
 2220 LET CI=CI+N
 2230 IF CI>LEN T$ THEN LET CI=LEN T$
 2240 IF CI<=0 THEN GOTO 2360
 2250 LET PN=INT ((CI-1)/640)
 2255 IF PN<>CPN-1 THEN RETURN 
 2260 LET CP=CI-640*PN
 2270 LET LN=INT ((CP-1)/32)
 2280 LET CN=CP-32*LN-1
 2290 LET J=CODE T$(CI)+128
 2300 IF J>=256 THEN LET J=J-256
 2310 FOR Y=1 TO 10
 2320 PRINT AT LN,CN;T$(CI)
 2330 PRINT AT LN,CN;CHR$ J
 2340 NEXT Y
 2350 RETURN 
 2360 LET CI=640*(CPN-1)
 2370 RETURN 
 2380 LET CI=LEN T$
 2390 RETURN 
 2500 REM %D%E%L%E%T%E
 2510 IF N=0 THEN LET N=1
 2520 LET L0=LEN T$
 2530 IF CI<=1 AND N>=L0 THEN LET T$=""
 2540 IF CI<=1 AND N<L0 THEN LET T$=T$(N+1 TO )
 2550 IF CI>1 AND CI+N-1>=L0 THEN LET T$=T$( TO CI-1)
 2560 IF CI>1 AND CI+N-1<L0 THEN LET T$=T$( TO CI-1)+T$(CI+N TO )
 2570 LET N=-1
 2580 GOSUB 2200
 2590 RETURN 
 2800 REM %J%U%S%T%I%F%Y
 2810 LET CI=1
 2820 IF CI+31>LEN T$ THEN RETURN 
 2830 LET V$=T$(CI+31)
 2835 IF CI+32>LEN T$ THEN RETURN 
 2840 IF T$(CI+32)=" " THEN LET T$=T$( TO CI+31)+T$(CI+33 TO )
 2850 LET I2=32
 2860 IF V$(I2)=" " THEN GOTO 2920
 2870 LET I2=I2-1
 2880 IF I2=0 THEN GOTO 2900
 2890 GOTO 2860
 2900 LET CI=CI+32
 2910 GOTO 2820
 2920 DIM H$(32)
 2930 LET H$=V$( TO I2)
 2940 LET T$=T$( TO CI-1)+H$+T$(CI+I2 TO )
 2950 LET CI=CI+32
 2960 GOTO 2820
 3000 REM %K% %A%N%D% %L
 3005 CLS 
 3010 IF W$="" THEN LET N=1
 3015 IF W$<>"" THEN LET N=VAL W$
 3020 LIST N
 3025 RETURN 
 3100 REM %M%E%M%O%R%Y
 3110 CLS 
 3120 PRINT AT 5,0;"SPACE FOR TEXT IS ";
 3130 PRINT PEEK 16386+256*PEEK 16387-PEEK 16412-256*PEEK 16413;
 3140 PRINT " BYTES"
 3150 RETURN 
 3300 REM %P%R%I%N%T
 3310 CLS 
 3315 SLOW 
 3320 IF N=0 THEN LET N=CPN
 3330 LET CPN=N
 3340 LET H=640*N
 3350 IF LEN T$<H THEN LET H=LEN T$
 3360 PRINT T$(640*N-639 TO H)
 3370 PRINT AT 21,0;"PAGE ";CPN
 3375 LET N=0
 3380 GOSUB 2200
 3390 RETURN 
 3500 REM %R%E%S%E%T
 3510 RUN 
 3520 RETURN 
 3600 REM %S%A%V%E
 3610 CLS 
 3620 PRINT "%S%A%V%E"
 3630 PRINT 
 3635 PRINT "INPUT PROGRAM NAME, DEFAULT NAME IS ""%T"""
 3640 PRINT 
 3645 PRINT "START TAPE PLAYER"
 3650 INPUT V$
 3655 IF V$="" THEN LET V$="T"
 3660 SAVE V$
 3665 GOTO 10
 3670 CLS 
 3680 PRINT "########  .''''.     :  :    .''''. '.  .'  :   "
 3681 PRINT "  ,,## :......: .''''.: '':''''' :......:  '..'  '':''''' "
 3682 PRINT " ,,##~~ :    . :   :  :   . :   .  .''.   :  . "
 3683 PRINT ",,##~~   '....'  '....':   '..'  '....' .'  '.  '..'"
 3684 PRINT "##~~"
 3685 PRINT "################################################################"
 3686 PRINT 
 3687 PRINT 
 3690 PRINT "A  APPEND        C  CURSOR"
 3691 PRINT 
 3692 PRINT "D  DELETE        I  INFO (MENU)"
 3693 PRINT 
 3694 PRINT "J  JUSTIFY       M  MEMORY TEST"
 3695 PRINT 
 3696 PRINT "P  PRINT         R  RESET"
 3697 PRINT 
 3698 PRINT "S  SAVE          T  TEST"
 3699 PRINT 
 3700 PRINT "X  EXECUTE * N   Z  STOP"
 3710 GOTO 1000
 3800 REM %T%E%S%T
 3810 LET T$="TO       SEE A WORLD IN A GRAIN OF SAND AND A HEAVEN IN A WILD FLOWER, HOLD INFINITY IN THE PALM OF YOUR HAND AND ETERNITY IN AN HOUR."
 3820 RETURN 
 3900 REM %M%U%L%T%I%P%L%E% %E%X%E%C%U%T%I%O%N% %X
 3910 IF XC=N-1 OR N<=1 THEN GOTO 3960
 3920 LET XC=XC+1
 3930 LET D=0
 3940 LET I=1
 3950 GOTO 1040
 3960 LET XC=0
 3970 RETURN 
 4000 REM %S%T%O%P
 4010 STOP 
 4020 CLEAR 
 4030 SAVE "1024%4"
 4040 RUN 

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

People

No people associated with this content.

Scroll to Top