--- title: "Baby Syntext" id: 57574 type: "computer_media" slug: "baby-syntext" url: "http://localhost/computer_media/baby-syntext/" markdown_url: "http://localhost/computer_media/baby-syntext.md" published_at: "2024-10-05T22:15:13+00:00" modified_at: "2026-04-03T07:58:21+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/10/baby-syntext.png" excerpt: "A surprisingly capable full-screen text editor stores 2,880 characters in a string array, with cursor movement, insert, delete, and tape save — all without machine code." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 1000" slug: "ts1000" taxonomy: "post_tag" url: "http://localhost/tag/ts1000/" model: - name: "Timex/Sinclair 1000" slug: "ts-1000" taxonomy: "model" url: "http://localhost/model/ts-1000/" genre: - name: "Word Processor" slug: "word-processor" taxonomy: "genre" url: "http://localhost/type/word-processor/" media_contents: - id: 56721 title: "Synchro-Sette April 1983" type: "computer_media" url: "http://localhost/computer_media/synchro-sette-april-1983/" media_type: "Program" mediadate: "April 1983" images: - url: "http://localhost/wp-content/uploads/2024/10/baby-syntext.png" - url: "http://localhost/wp-content/uploads/2024/10/baby-syntext-2.png" media_type_tags: "Word Processor" --- # Baby Syntext 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: 1. **Lines 10–70:** Initialisation — allocates `A$(2880)` as the text buffer, sets cursor position variables, and allocates `D$(32)` as a scratch line buffer. 2. **Line 300:** Display refresh — `PRINT AT 0,0;A$(A TO A+703)` renders the current 22-row window (22 × 32 = 704 characters). 3. **Lines 100–999:** Main dispatch loop — calls the keyboard subroutine at 5000 and uses a chain of `IF CODE B$=… THEN GOTO` tests to route each keypress to its handler. 4. **Lines 1000–1900:** Individual key handlers (carriage return, backspace, cursor movement, insert, delete, tab-right, end-of-screen, end-of-line). 5. **Lines 3000–3099:** Help menu display. 6. **Lines 3500–3570:** Tape save routine. 7. **Lines 5000–5040:** Keyboard input / cursor blink subroutine. 8. **Lines 6000–6060:** Line-wrap subroutine called when `Y` exceeds 31. 9. **Lines 7000–7040:** Standalone screen dump subroutine (not called from the main loop; likely a debugging aid). 10. **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. ## 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 ","BEGINNING TEXT" 3035 PRINT "SHIFT ","END OF SCREEN" 3040 PRINT "SHIFT ","RIGHT 8 POS." 3045 PRINT "SHIFT ","CLEAR END LINE" 3050 PRINT "SHIFT ","INSERT BLANK" 3055 PRINT "SHIFT ","DELETE R. CHAR." 3060 PRINT "SHIFT ","HELP MENU" 3065 PRINT "SHIFT ","SAVE ON TAPE" 3070 PRINT "ENTER","CARR. RET." 3080 PRINT ,,"IF PROGRAM BREAKS, FOR BEGINNING OF TEXT. FOR LAST CURSOR POSITION. DO NOT PRESS THE 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 WHEN2816 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 ```