.module Editor
;; Pointer to the start of the variable being edited (size bytes).
.var uword VarStartAddress
;; Pointer to the start of the variable's data.
.var uword DataStartAddress
;; Pointer to the character sitting under the cursor.
.var uword CursorAddress
;; Pointer to the character that appears in the top-left of the editor (top line).
.var uword TopOfScreenLineAddress
;; Pointer to the byte after the last character in the variable.
EndAddress = iMathPtr2
;; Pointer to the byte after the largest possible EndAddress value (do not make the variable bigger than this!).
MaximumEndAddress = iMathPtr3
.var ubyte[24*10] OldConsole.Buffer
.var ubyte OldConsole.Cursor.X
.var ubyte OldConsole.Cursor.Y
;; Edit a text variable.
;; Pointer to variable data (size bytes).
;; Pointer to VAT entry.
;; All registers.
Edit
ld (VarStartAddress),de
.bcall _EditProg
ld hl,(MaximumEndAddress)
ld de,(EndAddress)
or a
sbc hl,de
jr nz,+
.bcall _CloseProg
ret ; Out of memory?
+
ld hl,Console.Buffer
ld de,OldConsole.Buffer
ld bc,SizeOf(OldConsole.Buffer)
ldir
ld a,(Console.Cursor.X)
ld (OldConsole.Cursor.X),a
ld a,(Console.Cursor.Y)
ld (OldConsole.Cursor.Y),a
ld hl,(EndAddress)
ld (hl),'\n' ; EOF marker.
inc hl
ld (EndAddress),hl
ld hl,(VarStartAddress)
inc hl
inc hl
ld (DataStartAddress),hl
ld (TopOfScreenLineAddress),hl
ld (CursorAddress),hl
xor a
ld (Cursor.X),a
ld (Cursor.Y),a
inc a
call RepaintAll
RestartEditKeyLoop
call Console.Cursor.ResetBlink
EditKeyLoop
call Console.Cursor.GetChar
call Console.PutMapNoWriteBuffer
push hl
call Keypad.GetChar
pop hl
jr nz,EditKeyLoop
push af
call Console.RestoreCurrentCharacter
pop af
InjectKey
jp p,NotExtendedKey
; [->] Right cursor key.
cp Emerson.Keyboard.KeyCode.Right
jr nz,+
call Cursor.MoveRight
jr RestartEditKeyLoop
+
; [<-] Left cursor key.
cp Emerson.Keyboard.KeyCode.Left
jr nz,+
call Cursor.MoveLeft
jr RestartEditKeyLoop
+
; [v] Down cursor key.
cp Emerson.Keyboard.KeyCode.Down
jr nz,+
call Cursor.MoveDown
jr RestartEditKeyLoop
+
; [^] Up cursor key.
cp Emerson.Keyboard.KeyCode.Up
jr nz,+
call Cursor.MoveUp
jr RestartEditKeyLoop
+
; [Page Down] key.
cp Emerson.Keyboard.KeyCode.PageDown
jr nz,+
call Cursor.PageDown
jr RestartEditKeyLoop
+
; [Page Up] key.
cp Emerson.Keyboard.KeyCode.PageUp
jr nz,+
call Cursor.PageUp
jr RestartEditKeyLoop
+
; [End] key.
cp Emerson.Keyboard.KeyCode.End
jr nz,+
call Cursor.MoveEnd
jr RestartEditKeyLoop
+
; [Home] key.
cp Emerson.Keyboard.KeyCode.Home
jr nz,+
call Cursor.MoveHome
jr RestartEditKeyLoop
+
cp Emerson.Keyboard.KeyCode.Escape
jp z,Quit
jp RestartEditKeyLoop ; It's an extended key, but I don't know it...
NotExtendedKey
; Translate \r -> \n
cp '\r' \ jr nz,+
ld a,'\n'
+
; Backspace key.
cp '\b' \ jr nz,NotBackspace
ld hl,(DataStartAddress)
ld de,(CursorAddress)
or a
sbc hl,de
jp z,RestartEditKeyLoop ; Can't backspace from char 0.
ld hl,(EndAddress)
ld de,(CursorAddress)
or a
sbc hl,de
ld b,h
ld c,l
ld hl,(CursorAddress)
ld de,(CursorAddress)
dec de
ldir
ld hl,(EndAddress)
dec hl
ld (EndAddress),hl
ld ix,(VarStartAddress)
ld l,(ix+0) \ ld h,(ix+1)
dec hl
ld (ix+0),l \ ld (ix+1),h
ld a,Emerson.Keyboard.KeyCode.Left
cp 128 ; ssf
jp InjectKey
NotBackspace
; Insert a character.
ld hl,(MaximumEndAddress)
ld de,(EndAddress)
or a
sbc hl,de
jp z,RestartEditKeyLoop ; Not enough room.
; Enlarge the variable.
ld ix,(VarStartAddress)
ld e,(ix+0) \ ld d,(ix+1)
inc de
ld (ix+0),e \ ld (ix+1),d
ld de,(EndAddress)
inc de
ld (EndAddress),de
dec de
ld h,d
ld l,e
dec hl
; hl->old last character.
; de->new last character.
push hl
ld bc,(CursorAddress)
or a
sbc hl,bc
ld b,h
ld c,l
inc bc
pop hl
; bc->length from cursor->end of file.
lddr
; Insert the character proper.
ld hl,(CursorAddress)
ld (hl),a
ld a,Emerson.Keyboard.KeyCode.Right
cp 128 ; ssf
jp InjectKey
Quit
ld hl,(EndAddress)
dec hl
ld (EndAddress),hl
.bcall _CloseProg
; Restore the original text buffer and cursor position to the display.
ld hl,OldConsole.Buffer
xor a
ld (Console.Cursor.X),a
ld (Console.Cursor.Y),a
- ld a,(hl)
inc hl
call Console.PutMap
ld a,(Console.Cursor.X)
inc a
ld (Console.Cursor.X),a
cp 24
jr nz,-
xor a
ld (Console.Cursor.X),a
ld a,(Console.Cursor.Y)
inc a
ld (Console.Cursor.Y),a
cp 10
jr nz,-
ld a,(OldConsole.Cursor.X)
ld (Console.Cursor.X),a
ld a,(OldConsole.Cursor.Y)
ld (Console.Cursor.Y),a
ret
;; Repaints the entire screen.
;; This does not clear the screen first.
RepaintAllNoClear
xor a
ld (Console.Cursor.X),a
ld (Console.Cursor.Y),a
jr +
;; Repaints the entire screen.
;; This clears the screen first.
RepaintAll
call Console.Clear
+
xor a
ld (Cursor.IsOnScreen),a
ld hl,(TopOfScreenLineAddress)
ld de,(CursorAddress)
ld bc,(EndAddress)
RepaintLoop
ld a,(hl)
or a
push hl
sbc hl,de
pop hl
jr nz,+
push af
ld a,1
ld (Cursor.IsOnScreen),a
ld a,(Console.Cursor.X)
ld (Editor.Cursor.X),a
ld a,(Console.Cursor.Y)
ld (Editor.Cursor.Y),a
pop af
+ or a
push hl
sbc hl,bc
pop hl
jr nz,+
; End of file.
- ld a,' '
call PutChar
jr nz,-
jr FinishedRepainting
+
call PutChar
inc hl
jr nz,RepaintLoop
FinishedRepainting
ld a,(Editor.Cursor.X)
ld (Console.Cursor.X),a
ld a,(Editor.Cursor.Y)
ld (Console.Cursor.Y),a
ret
;; Puts a character on the display.
;; The charcter to write.
;; z if the cursor has just moved off the screen; nz if it's still on it.
PutChar
cp '\n'
jr nz,+
- ld a,' '
call Console.PutMap
ld a,(Console.Cursor.X)
inc a
ld (Console.Cursor.X),a
cp 24
jr nz,-
xor a
ld (Console.Cursor.X),a
ld a,(Console.Cursor.Y)
inc a
cp 10
ret z
ld (Console.Cursor.Y),a
inc a
ret
+ call Console.PutMap
ld a,(Console.Cursor.X)
inc a
cp 24
jr z,+
ld (Console.Cursor.X),a
xor a
inc a
ret
+ xor a
ld (Console.Cursor.X),a
ld a,(Console.Cursor.Y)
inc a
cp 10
ret z
ld (Console.Cursor.Y),a
ret
;; Checks whether you are at the end of the file.
;; z if you are; nz if you aren't.
;; f.
AtEnd
push hl
push de
ld de,(CursorAddress)
ld hl,(EndAddress)
scf
sbc hl,de
pop de
pop hl
ret
;; Checks whether you are at the start of the file.
;; z if you are; nz if you aren't.
;; f.
AtStart
push hl
push de
ld de,(CursorAddress)
ld hl,(DataStartAddress)
or a
sbc hl,de
pop de
pop hl
ret
;; Scrolls the screen up a line.
ScrollUp
ld hl,(TopOfScreenLineAddress)
ld de,(DataStartAddress)
ld b,24
- dec hl
or a
push hl
sbc hl,de
pop hl
jr nz,+
ld (TopOfScreenLineAddress),hl
jr FinishedScrollingUp
+
ld a,(hl)
cp '\n'
jr z,+
djnz -
ld (TopOfScreenLineAddress),hl
jr FinishedScrollingUp
+
; So, there's an irritating carriage return somewhere along the way.
; Find the start of the previous FULL line.
- dec hl
ld a,(hl)
cp '\n'
jr z,+
or a
push hl
sbc hl,de
pop hl
jr nz,-
dec hl
+ inc hl
ld (TopOfScreenLineAddress),hl
; Find the last 24 character multiple before the final line feed.
-- ld b,24
- ld a,(hl)
cp '\n'
jr z,+
inc hl
djnz -
ld (TopOfScreenLineAddress),hl
jr --
+
FinishedScrollingUp
ret
;; Scrolls the screen down a line.
ScrollDown
ld b,24
ld hl,(TopOfScreenLineAddress)
- ld a,(hl)
inc hl
cp '\n'
jr z,+
djnz -
+ ld (TopOfScreenLineAddress),hl
ret
.module Cursor
;; The X-coordinate of the editor's cursor.
.var ubyte X
;; The Y-coordinate of the editor's cursor.
.var ubyte Y
;; Zero if the cursor is on screen, false otherwise.
.var ubyte IsOnScreen
;; Moves the cursor right one character.
;; Triggers a repaint.
;; All registers.
MoveRight
ld hl,(CursorAddress)
inc hl
push hl
ld de,(EndAddress)
or a
sbc hl,de
pop hl
ret z
ld (CursorAddress),hl
call RepaintAllNoClear
ld a,(Cursor.IsOnScreen)
or a
ret nz
jp ScrollDown
;; Moves the cursor left one character.
;; Triggers a repaint.
;; All registers.
MoveLeft
ld hl,(CursorAddress)
ld de,(DataStartAddress)
or a
sbc hl,de
ret z
ld hl,(CursorAddress)
dec hl
ld (CursorAddress),hl
call RepaintAllNoClear
ld a,(Cursor.IsOnScreen)
or a
ret nz
jp ScrollUp
;; Moves the cursor to the end of a line.
;; Triggers a repaint.
;; All registers.
MoveEnd
ld hl,(CursorAddress)
ld de,(EndAddress)
scf
sbc hl,de
ret z
- ld de,(CursorAddress)
ld hl,(EndAddress)
scf
sbc hl,de
jr z,FoundEnd
ld a,(de)
cp '\n'
jr z,FoundEnd
inc de
ld (CursorAddress),de
jr -
FoundEnd
;; Scrolls the screen down until the cursor is visible.
ScrollDownToCursor
- call RepaintAllNoClear
ld a,(Cursor.IsOnScreen)
or a
ret nz
call ScrollDown
jr -
;; Moves the cursor to the start of a line.
;; Triggers a repaint.
;; All registers.
MoveHome
ld hl,(CursorAddress)
ld de,(DataStartAddress)
or a
sbc hl,de
ret z
- ld de,(CursorAddress)
ld hl,(DataStartAddress)
or a
sbc hl,de
jr z,FoundHome
dec de
ld a,(de)
cp '\n'
jr z,FoundHome
ld (CursorAddress),de
jr -
FoundHome
;; Scrolls the screen up until the cursor is visible.
ScrollUpToCursor
- call RepaintAllNoClear
ld a,(Cursor.IsOnScreen)
or a
ret nz
call ScrollUp
jr -
;; Moves the cursor down a line.
;; Triggers a repaint.
;; All registers.
MoveDown
ld a,(X)
ld b,a
ld a,24
sub b
ld b,a
- call AtEnd
jr z,FoundLineBelowStart
ld hl,(CursorAddress)
ld a,(hl)
inc hl
ld (CursorAddress),hl
cp '\n'
jr z,FoundLineBelowStart
djnz -
FoundLineBelowStart
ld a,(X)
or a
jr z,FoundColumnBelowStart
ld b,a
- call AtEnd
jr z,FoundColumnBelowStart
ld hl,(CursorAddress)
inc hl
ld (CursorAddress),hl
ld a,(hl)
cp '\n'
jr z,FoundColumnBelowStart
djnz -
FoundColumnBelowStart
jr ScrollDownToCursor
;; Moves the cursor up a line.
;; Triggers a repaint.
;; All registers.
MoveUp
ld a,(X)
ld c,a
or a
jr z,+
ld b,a
- call AtStart
jr z,+
ld hl,(CursorAddress)
dec hl
ld (CursorAddress),hl
djnz -
+ call AtStart
jr z,+
ld hl,(CursorAddress)
dec hl
ld (CursorAddress),hl
+ push bc
call ScrollUpToCursor
pop bc
; At this point, we're at the end of the previous line.
ld hl,(CursorAddress)
ld a,(X)
- cp c
jr z,ScrollUpToCursor
jr c,ScrollUpToCursor
call AtStart
jr z,ScrollUpToCursor
dec hl
dec a
ld (CursorAddress),hl
jr -
;; Moves down a page of text.
PageDown
ld b,10
- push bc
call MoveDown
pop bc
djnz -
ret
;; Moves up a page of text.
PageUp
ld b,10
- push bc
call MoveUp
pop bc
djnz -
ret
.endmodule
.endmodule