TextWriter 1000

Products: Textwriter 1000
Developer(s): Robert Schimke
Date: 1983
Type: Program
Platform(s): TS 1000

TEXTWRITER 1000 is a full-screen word processor that stores text in a two-dimensional string array B$(Z,32), where Z is the user-defined number of lines and each row holds up to 32 characters. The editor supports cursor movement, word-wrap at the right margin, a cut/copy/paste buffer using a second array M$, and tab stops stored in array E(5). Printing is handled via LPRINT with selectable single or double spacing, paginating automatically every 74 lines. An edit-command interpreter at line 1500 accepts two-letter codes (AL for insert lines, DL for delete lines, AC for append-compress, MP for paste, C for compact/reflow) entered at a prompt.


Program Analysis

Program Structure

The program is divided into clearly functional regions, navigated entirely by GOTO and GOSUB:

  1. Lines 10–113 — Initialisation and main menu (display, new file, save, print)
  2. Lines 115–140 — File dimension setup; allocates B$(Z,32) and E(5)
  3. Lines 145–660 — Main editing loop: keystroke dispatch, character entry, cursor movement, word-wrap, screen scrolling
  4. Lines 700–760 — Page-down (forward scroll by 21 lines)
  5. Lines 800–960 — Subroutines: restore character (800), header print (920), space/erase (940)
  6. Lines 1000–1050 — Page-up (backward scroll by 10 lines)
  7. Lines 1500–2930 — Edit-command interpreter and its operations (insert lines, delete lines, copy block, paste, compact/reflow)
  8. Lines 3000–3030 — Save routine
  9. Lines 4000–5010 — Tab-stop set and jump
  10. Lines 5500–5630 — LPRINT with single/double spacing and pagination

Data Structures

  • B$(Z,32) — Main text buffer; a 2-D string array with Z rows of 32 characters. Dimensioned at runtime after the user specifies the required number of lines.
  • M$(C,32) — Cut/copy buffer; dimensioned on demand when a block-mark command is issued, holding LL+1 lines.
  • E(5) — Numeric array storing up to 5 tab-stop column positions, set interactively.
  • T$ — File title, displayed centred in the menu header.
  • Z$ — Overflow accumulator for characters typed past column 32 (used during word-wrap).

Keystroke Dispatch

The editor reads keystrokes via PAUSE 50000 followed by INKEY$ at line 170. Character codes are checked numerically to distinguish printable from control characters. The dispatch table is:

CodeAction
<64Printable character — stored in B$, cursor advances
112 (p)Move cursor up one line (with page-back if needed)
114 (r)Cursor left / delete (via subroutine 800 + 940)
115 (s)Re-print current cell (used as no-op / refresh)
117 (u)Enter edit-command mode (line 1500)
118 (v)Newline / ENTER — erase current cell and advance
119 (w)Delete character at cursor (space it out)
121 (y)Tab jump (if tab stops set) or newline
224Set tab stop (line 4000)
227Return to main menu (line 42)
229Page down (line 700)

Screen Editing and Cursor Representation

The current cursor position is shown by printing the character at (X, Y-1) in inverse video using CHR$ (CODE B$(W+X,Y)+128) at line 145. W is the window offset (which logical row is at the top of the screen), X is the screen row (1–21), and Y is the column (1–32). Restoring a cell to normal video is handled by subroutine 920/800 which re-prints B$(W+X,Y) without the +128 offset.

Word-Wrap at Column 33

When Y reaches 33 (line 175/500), the program switches to overflow-accumulation mode. Subsequent normal characters are appended to Z$. On a control keystroke, the current line is scanned right-to-left for the last space (line 550–560), the text from that point plus Z$ is moved to the next line (line 575), and the current line is truncated (line 580). This provides a basic word-wrap without requiring the user to manage line breaks manually.

Edit Command Language

Pressing the key with code 117 opens a two-letter command prompt. Commands are parsed at lines 1540–1590:

  • AL[n] — Insert n blank lines at cursor (default from LL)
  • DL[n] — Delete n lines at cursor
  • AC — Append and compact: reflow text by joining short lines
  • A[n] — Insert n spaces at cursor position
  • MP — Paste (mark-paste) the clipboard at cursor
  • C — Compact: remove leading spaces and join continuation lines
  • Numeric string only — defines a block mark of that many lines into M$

Cut/Copy Buffer

Marking a block (entering a number at the edit prompt) stores lines in M$(1..LL+1), dimensioned dynamically at line 2820. The variable LL holds the block size minus one; D and F record the first and last line numbers of the marked region, displayed in the header by subroutine 920 (line 925) when LL <> -1. LL is initialised to -1 at line 10 to signal “no buffer”.

Printing (LPRINT)

Lines 5500–5630 iterate from line LB to LE, calling LPRINT B$(I). Double-spacing adds a blank LPRINT after each line. A line counter LC triggers a form feed (five blank lines, line 5610) every 74 printed lines regardless of spacing mode. The page length of 74 is hardcoded.

Notable Techniques

  • Dynamic DIM: Both B$ and M$ are dimensioned at runtime with user-supplied or computed sizes, a practical approach to managing limited RAM.
  • Inverse cursor via +128: Adding 128 to a character code produces its inverse-video counterpart — a well-known ZX81/TS1000 display trick that avoids any machine code.
  • Window scrolling with W offset: Logical line number is always W+X; changing W by ±10 or ±21 and re-printing lines 1–21 provides smooth paging without moving data.
  • SLOW/FAST switching: The editor uses SLOW for display-intensive sections (printing the screen) and FAST during computation-heavy operations like block moves, reducing flicker and improving speed respectively.
  • Tab stops in a numeric array: Storing up to 5 tab column positions in E(5) and scanning them at line 4080 is a compact alternative to a string-based tab ruler.

Bugs and Anomalies

  • Line 100 sets W=LB-1 unconditionally, but for the display option (menu choice 1) this is immediately overridden by GOTO 112 before W is used, so the assignment is harmless but redundant.
  • At line 251, the check IF W+X=Z THEN GOTO 145 prevents moving past the last allocated line but does not display a warning to the user.
  • Line 4065 loops J=1 TO 6 but E(5) only has indices 1–5; accessing E(6) would cause an error, but the branch at line 4070 (IF J=6 THEN GOTO 230) fires before the subscript is evaluated, so it is safe in practice.
  • The compact/reflow routine at lines 2000–2190 uses Y as both the starting column and a loop variable, which may leave Y in an unexpected state; line 2210 restores it from saved value Q.
  • Line 595 checks IF X=21 THEN GOTO 1020 after a word-wrap to scroll down, but this scroll shifts W by +10 and sets X=12 rather than +1/X=21, which could misplace the cursor relative to the wrapped text.

Content

Appears On

Related Products

Word processor. Capabilities include insert/delete, text compression/realignment and buffer memory for saving portions of text to use elsewhere. Also includes...

Related Articles

Related Content

Image Gallery

TextWriter 1000

Source Code

  10 LET LL=-1
  20 DIM M$(1)
  30 LET Z$=""
  35 LET Y=1
  40 LET W=0
  42 SLOW 
  45 CLS 
  47 LET X=1
  50 PRINT AT 3,8;"%T%E%X%T%W%R%I%T%E%R% %1%0%0%0";AT 5,15-LEN T$/2;T$
  55 PRINT ,,"%M%E%N%U",,,,"1) DISPLAY CURRENT TEXT FILE","2) START NEW FILE","3) SAVE FILE",,,,"%P%R%I%N%T",,,,"4) SINGLE SPACE",,"5) DOUBLE SPACE"
  60 INPUT LN
  70 CLS 
  80 IF LN=2 THEN GOTO 115
  85 IF LN=3 THEN GOTO 3000
  95 PRINT AT 18,0;"ENTER START LINE","LAST TEXT ON ";M;"(";Z;")"
  97 INPUT LB
 100 LET W=LB-1
 102 IF LN=1 THEN GOTO 112
 104 PRINT AT 18,6;"FINAL"
 106 INPUT LE
 110 GOTO 5500
 112 FAST 
 113 CLS 
 114 GOTO 610
 115 PAUSE 120
 117 LET M=0
 118 PRINT AT 20,0;"ENTER LINES REQUIRED"
 119 INPUT Z
 120 DIM B$(Z,32)
 122 CLS 
 125 FAST 
 130 GOSUB 920
 135 DIM E(5)
 137 LET ST=0
 140 FAST 
 145 PRINT AT X,Y-1;CHR$ (CODE B$(W+X,Y)+128)
 160 PAUSE 50000
 170 LET A$=INKEY$
 175 IF Y=33 THEN GOTO 500
 180 IF CODE A$>63 THEN GOTO 310
 185 IF W+X>M THEN LET M=W+X
 190 LET B$(W+X,Y)=A$
 200 PRINT AT X,Y-1;B$(W+X,Y)
 210 LET Y=Y+1
 211 IF Y=33 THEN GOTO 970
 215 GOTO 145
 230 IF CODE A$=121 THEN GOSUB 800
 240 LET Y=1
 250 IF CODE A$=112 THEN LET X=X-2
 251 IF W+X=Z THEN GOTO 145
 252 LET X=X+1
 270 IF X>21 THEN GOTO 1020
 280 IF X<1 AND W>0 THEN GOTO 1000
 285 IF X>21 THEN LET X=21
 287 IF X<1 THEN LET X=1
 290 GOTO 145
 310 LET A=CODE A$
 315 IF A=117 THEN GOTO 1500
 320 IF A<114 THEN GOTO 900
 330 IF A=118 THEN GOTO 420
 340 IF A=115 THEN GOTO 200
 345 IF A=229 THEN GOTO 700
 350 IF A=227 THEN GOTO 42
 355 IF A=121 AND E(1)>1 THEN GOTO 4062
 360 IF A=121 THEN GOTO 230
 365 IF A=224 THEN GOTO 4000
 370 GOSUB 800
 375 IF A=119 THEN GOSUB 940
 380 LET Y=Y-1
 390 IF Y<1 THEN LET X=X-1
 400 IF Y<1 THEN LET Y=32
 410 GOTO 280
 420 GOSUB 940
 440 GOTO 210
 500 IF CODE A$>63 THEN GOTO 525
 510 LET Z$=Z$+A$
 515 IF X<21 THEN PRINT AT X+1,0;Z$
 520 GOTO 160
 525 IF Z$="" THEN GOTO 240
 528 LET T=W+X
 530 LET D$=B$(T)
 540 LET Y=Y-1
 550 IF D$(Y)=" " THEN GOTO 565
 560 GOTO 540
 565 LET YY=LEN (D$(Y+1 TO )+Z$)+2
 570 IF T=Z THEN GOTO 610
 575 LET B$(T+1, TO YY)=D$(Y+1 TO )+Z$
 580 LET B$(T,Y TO )=""
 590 LET Y=YY
 592 LET Z$=""
 593 PRINT AT X,0;B$(T)
 595 IF X=21 THEN GOTO 1020
 600 PRINT B$(T+1)
 605 GOTO 252
 610 LET O=21
 613 IF W+O>Z THEN GOSUB 760
 617 LET R=1
 618 IF A=117 AND W+O<>Z THEN LET R=X
 619 GOSUB 920
 620 PRINT AT R,0;
 621 IF A<>118 AND A<>121 THEN SLOW 
 622 FOR J=R TO O
 625 PRINT B$(W+J)
 630 NEXT J
 660 GOTO 140
 700 IF W+22>Z THEN GOTO 160
 710 LET W=W+21
 720 LET X=1
 730 GOTO 610
 760 CLS 
 770 LET O=Z-W
 780 RETURN 
 800 PRINT AT X,Y-1;B$(W+X,Y)
 810 RETURN 
 900 GOSUB 800
 910 GOTO 250
 920 PRINT AT 0,29;"   "
 922 PRINT AT 0,0;"%T%Y%P%E% %M%O%D%E LINE ";W+1;"             "
 925 IF LL<>-1 THEN PRINT AT 0,19;"M:";D;"-";F
 930 RETURN 
 940 PRINT AT X,Y-1;" "
 950 LET B$(W+X,Y)=" "
 960 RETURN 
 970 IF CODE A$=118 OR CODE A$=115 THEN GOTO 230
 980 GOTO 160
\n1000 LET W=W-10
\n1006 IF W<0 THEN LET W=0
\n1008 LET X=10
\n1010 GOTO 610
\n1020 IF W>Z-21 THEN GOTO 140
\n1025 LET W=W+10
\n1030 LET X=12
\n1050 GOTO 610
\n1500 PRINT AT 0,0;"%E%D%I%T%:%E%N%T%E%R% %A%C%*%/%A%L%*%/%D%L%*%/%C%/%M%M%*%/%M%P% "
\n1520 LET Q=Y
\n1525 LET T=W+X
\n1530 INPUT C$
\n1540 IF C$="" THEN GOTO 610
\n1545 IF C$="MP" THEN GOTO 2890
\n1550 IF C$="C" THEN GOTO 2000
\n1555 LET C=1
\n1560 IF LEN C$>2 THEN LET C=VAL C$(3 TO )
\n1570 IF C$( TO 2)="AL" THEN GOTO 2300
\n1575 IF C$(1)="A" THEN GOTO 2520
\n1580 IF C$(1)="D" THEN GOTO 2450
\n1590 GOTO 2800
\n2000 FOR L=Y TO 32
\n2010 IF CODE B$(T,L)>0 THEN GOTO 2030
\n2020 NEXT L
\n2030 LET B$(T,Y TO )=B$(T,L TO )
\n2040 FOR N=L-Y TO 31
\n2050 IF CODE B$(T,32-N)>0 THEN GOTO 2070
\n2060 NEXT N
\n2065 GOTO 2080
\n2070 IF B$(T,32-N)="-" THEN LET N=N+2
\n2080 LET T=T+1
\n2085 IF T>Z THEN GOTO 2210
\n2090 IF B$(T,1)=" " THEN GOTO 2210
\n2100 FOR Y=N TO 1 STEP -1
\n2110 IF CODE B$(T,Y)=0 THEN GOTO 2150
\n2120 NEXT Y
\n2130 GOTO 2210
\n2150 IF N=32 THEN LET N=33
\n2160 LET B$(T-1,34-N TO )=B$(T, TO Y-1)
\n2170 LET L=Y+1
\n2180 LET Y=1
\n2190 GOTO 2030
\n2210 LET Y=Q
\n2220 IF C$(1)="A" THEN GOTO 2580
\n2230 GOTO 610
\n2250 LET C=LL+1
\n2300 IF Z-M<C THEN GOTO 1500
\n2305 FOR J=M TO T STEP -1
\n2310 LET B$(J+C)=B$(J)
\n2320 NEXT J
\n2330 FOR J=T TO T+C-1
\n2340 LET B$(J)=""
\n2345 NEXT J
\n2350 LET M=M+C
\n2355 IF C$(2)="L" THEN GOSUB 2400
\n2360 IF C$="MP" THEN GOTO 2898
\n2370 IF C$(2)<>"L" THEN GOTO 2610
\n2380 GOTO 610
\n2400 LET B$(T, TO Y-1)=B$(T+C, TO Y-1)
\n2410 LET B$(T+C, TO Y-1)=""
\n2420 RETURN 
\n2450 IF T+C>M+1 THEN LET C=M+1-T
\n2455 FOR K=T TO M-C
\n2480 LET B$(K)=B$(K+C)
\n2490 NEXT K
\n2495 FOR K=K TO M
\n2500 LET B$(K)=""
\n2505 NEXT K
\n2508 LET M=M-C
\n2510 GOTO 610
\n2520 LET P=C
\n2525 LET B=0
\n2540 IF P>33-Y THEN LET P=33-Y
\n2550 FOR J=33-P TO 32
\n2560 IF B$(T,J)<>" " THEN GOTO 2700
\n2570 NEXT J
\n2580 LET T=W+X
\n2583 IF B>0 THEN LET B$(T,Y+P TO )=B$(T,Y TO B-1)
\n2584 IF B>0 THEN GOTO 2590
\n2585 LET B$(T,Y+P TO )=B$(T,Y TO 32-P)
\n2590 LET B$(T,Y TO Y+P-1)=""
\n2600 GOTO 610
\n2610 FOR B=33-P TO Y STEP -1
\n2620 IF B$(T-1,B)=" " THEN GOTO 2640
\n2630 NEXT B
\n2640 LET B$(T)=B$(T-1,B+1 TO )
\n2645 LET L=Y
\n2650 GOTO 2040
\n2700 LET T=T+1
\n2710 LET C=1
\n2720 GOTO 2305
\n2800 LET LL=C-1
\n2820 DIM M$(C,32)
\n2825 LET D=T
\n2827 IF LL<50 THEN SLOW 
\n2828 IF T+LL>Z THEN LET LL=Z-T
\n2830 FOR J=0 TO LL
\n2840 LET M$(J+1)=B$(T+J)
\n2850 IF T+J-W<22 THEN PRINT AT T+J-W,0;CHR$ (CODE B$(T+J,1)+128)
\n2870 NEXT J
\n2872 LET F=T+LL
\n2875 FAST 
\n2878 PRINT AT R,0;
\n2880 GOTO 610
\n2890 IF T+LL>Z THEN LET LL=Z-T
\n2895 IF T<=M THEN GOTO 2250
\n2898 FOR J=0 TO LL
\n2900 LET B$(T+J)=M$(J+1)
\n2920 NEXT J
\n2925 IF T+LL>M THEN LET M=T+LL
\n2930 GOTO 610
\n3000 CLS 
\n3010 PRINT AT 10,5;"ENTER TITLE TO RECORD"
\n3015 INPUT T$
\n3018 CLS 
\n3020 SAVE T$
\n3030 GOTO 30
\n4000 IF Y=1 THEN GOTO 135
\n4005 LET ST=ST+1
\n4010 IF ST>5 THEN GOTO 4040
\n4020 LET E(ST)=Y
\n4030 GOTO 145
\n4040 PRINT AT 0,19;"%5% %T%A%B%S% %M%A%X"
\n4045 PAUSE 60
\n4050 GOSUB 920
\n4055 GOTO 160
\n4062 GOSUB 800
\n4065 FOR J=1 TO 6
\n4070 IF J=6 THEN GOTO 230
\n4080 IF Y<E(J) THEN GOTO 5000
\n4090 NEXT J
\n5000 LET Y=E(J)
\n5010 GOTO 145
\n5500 FAST 
\n5510 LET LF=1
\n5520 IF LN=5 THEN LET LF=2
\n5530 LET LC=0
\n5540 FOR I=LB TO LE
\n5550 LPRINT B$(I)
\n5560 IF LN=5 THEN LPRINT 
\n5570 LET LC=LC+LF
\n5580 IF LC=74 THEN GOSUB 5610
\n5590 NEXT I
\n5600 GOTO 42
\n5610 LPRINT ,,,,
\n5620 LET LC=0
\n5630 RETURN 

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

Scroll to Top