6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sun Nov 10, 2024 7:43 pm

All times are UTC




Post new topic Reply to topic  [ 3 posts ] 
Author Message
PostPosted: Fri Nov 23, 2018 3:47 am 
Offline

Joined: Sun Jul 28, 2013 12:59 am
Posts: 235
There was some semi-recent interest in the design of a "visual" block (or screen?) editor, and I stumbled across an intact copy of my first block editor and some trace of its evolution since that initial version, and I thought I'd share. Maybe someone will find it helpful, or at least interesting.

Some background: This was for a standalone x86 PC Forth implementation along the Loeliger model, with some influence from cmForth and Pygmy Forth, and is probably very idiosyncratic, but the basic ideas should tend to apply anywhere. Blocks are 1k, so there's no concept of a "screen" of source text separate from a block.

The original block editor appears to have had the ability to copy a line at a time within a block, to erase a line, and to replace a line entirely. There was no editing within a line, it was a pure replacement operation.

Code:
( Block editor) HEX   VARIABLE CURBLOCK
: LINE ( n - a) DUP 10 >= 6 AND - 40 *   CURBLOCK @ BLOCK + ;
: showline ( a - a+40) 40   BEGIN DUP IF 1- SWAP
   DUP C@ CHROUT   1+   SWAP WHILE DROP ;
: showlines ( a - a+400) 10    BEGIN DUP IF 1-   0F OVER -
   DUP 0A < IF 20 ECHO THEN .   7C ECHO   SWAP showline SWAP
   7C ECHO   CR   WHILE 2DROP ;
: SHOW DECIMAL   CLRSCR   0 LINE showlines ;
: COPY ( src dst) LINE SWAP   LINE SWAP   UPDATE
   40 CMOVE   SHOW ;
: (CLEAR) ( a) UPDATE   2020 SWAP   20 WBLOCKFLOOD ;
: CLEAR ( n) LINE (CLEAR) SHOW ;
: CLEARALL 10   BEGIN DUP IF 1-   DUP CLEAR   WHILE DROP ;
: REPLACE ( n) LINE   CR INLINE   DUP (CLEAR)   TIB @ SWAP
   TIB# @ 40 MIN   CMOVE   0 TIB# !   SHOW ;
: EDIT ( n) CURBLOCK ! SHOW ;

From what I recall, editing code with this was a struggle. Especially since INLINE only had backspace for input editing. For that matter, navigating between blocks was more difficult than I particularly wanted. Moving blocks around was painful, moving lines of text between blocks even more so, and for some reason I seem to recall only having one disk in use for Forth at the time, hence part of why the code is so terse and dense within the block.

At some point I realized that I could make a simple loop to watch the keyboard for page-up, page-down, and escape, and use this to navigate through the available blocks without having to constantly re-type "<number> EDIT" all the time. And being able to switch between two arbitrary blocks can be very handy, either because you're using "shadow blocks" for documentation, or because you're trying to figure out some problem that requires looking at two widely-separate parts of the system, or because you have a key that copies the contents of one block to the other. I seem to no longer have the original version of this "block browser", but the remaining part is still interesting:

Code:
( block browser ) HEX   VARIABLE saveblock
: showblock 0 0 GOTOXY   0 LINE showlines
    ." Block " CURBLOCK @ . ."     " CR ;
: nextblock CURBLOCK DUP @ 1+ SWAP ! ;
: prevblock CURBLOCK DUP @ 1- 0 MAX SWAP ! ;
: swapblock saveblock @ CURBLOCK @ saveblock ! CURBLOCK ! ;
: storeblock CURBLOCK @ saveblock ! ;
: copyblock CURBLOCK @ BLOCK saveblock @ BLOCK UPDATE
   400 CMOVE ;

: check ( c a) 2DUP W@ <> IF 6 + EXIT THEN
   SWAP R> 2DROP 2 + @ EXECUTE 0 ;
: checkall ( c a) BEGIN DUP W@ IF check WHILE 2DROP 1 ;

The dispatch logic in check and checkall is more than a bit sketchy, especially the way that check can force a return from checkall. The toplevel logic that went with this would have been in the same block, and probably looked somewhat like this (written "off the cuff", and not tested):

Code:
VARIABLE browsetable DICTTOP DUP @ 4 - SWAP !
4900 W, ' prevblock ,  5100 W, ' nextblock ,  3F00 W, ' swapblock ,
0 W,
: browse DECIMAL CLRSCR BEGIN showblock SKEY browsetable checkall UNTIL ;

Note that the browsetable format is 16 bits of SKEY result followed by a 32-bit execution token, followed by a zero in place of the SKEY (EKEY by any other name?) value. From here it doesn't take much to come to the concept of a dedicated "exit" key, maintaining a position within the current block, using GOTOXY to set the cursor to that position, having "printable" keypress events insert text into the block, and so on. It's a bit less than three more blocks of code (spread out over four in my case). A later version of the editor used a linked-list, so that new keys could be defined later on. The same mechanism was then used for a rewrite of INLINE, though it did not progress to the point of any input editing beyond backspace.

If I were to do it all over today, I'd probably start with a toplevel control structure derived from the third version of the editor and basic display of and navigation within and between blocks, then immediately the editing bits. No point to writing a line-oriented editor when I can go straight to one that I find more comfortable to work with... Also, I'd probably take the time to add better input editing to INLINE, and possibly even an input history...


Top
 Profile  
Reply with quote  
PostPosted: Fri Nov 23, 2018 9:02 pm 
Offline

Joined: Sat Aug 21, 2010 7:52 am
Posts: 231
Location: Arlington VA
In PETTIL I kept things as simple as possible. The PET is hardwarily incapable of displaying 1024 characters at once, but 1000 is close enough. It's also cassette-based, but I wanted it to feel like Forthy virtual memory, which is why it uses a RAM buffering scheme. There are two bits of metadata associated with each BLOCK. One says whether it is rlencoded (or not) and the other bit says whether it is screen (1000 bytes of screencode + 3 bytes of linewrap info) or data (1024 bytes of anything).

For the screen editor itself, it is just an infinite loop that calls CHRIN. I trap the jiffy IRQ and see if the user pressed the STOP key. This flashes the screen and waits for the next keystroke, which is treated as an editor command. The screen unflashes and the command executes. STOP-Q is "quit", it reverts the IRQ to its normal value. The editor is really just the PET screen editor, thinly wrapped. The whole thing, excluding the commands to delete and insert lines, move to a different screen, display a help/info screen, etc... is about 70 bytes of code!


Top
 Profile  
Reply with quote  
PostPosted: Mon Nov 26, 2018 2:03 am 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 894
In Fleet Forth, I kept things simple by making the screen editor an extention of the Starting Forth editor that uses the Commodore 64 screen editor. LIST lists a block with a colon after each line number. XED is a defining word.
Code:
SCR# 3A
0: // XED
1: HEX
2: EDITOR DEFINITIONS
3: : XED  ( N -- )
4:    CREATE C, DOES>  ( -- )
5:    C@ C/L * R# !
6:    0 TEXT C/L PAD C!
7:    IBUF BUFMOVE (R)
8:    >ASSEM
9:    1D # LDA,
A:    4 # LDY,  C6 STY,
B:    BEGIN,
C:       276 ,Y STA,  DEY,
D:    0= UNTIL,
E:    >FORTH  QUIT ; -2 ALLOT
F:

The assembly code between >ASSEM and >FORTH stuffs four right shift keys into the C64 keyboard buffer and isn't needed, it just makes it more convenient for me. XED is used to define Fleet Forth's screen editor words.
Code:
SCR# 3B
0: // XED WORDS 0: - F:  10: - 15:
1: HEX
2: EDITOR DEFINITIONS
3:  0 XED 0:    1 XED 1:    2 XED 2:
4:  3 XED 3:    4 XED 4:    5 XED 5:
5:  6 XED 6:    7 XED 7:    8 XED 8:
6:  9 XED 9:   0A XED A:   0B XED B:
7: 0C XED C:   0D XED D:   0E XED E:
8: 0F XED F:   0A XED 10:  0B XED 11:
9: 0C XED 12:  0D XED 13:  0E XED 14:
A: 0F XED 15:
B: FORTH DEFINITIONS
C:
D:
E:
F:


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 3 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: