; ======================================================================
; lib-set-01 INPUT TEXT EDITOR / r010e INSERT-LENGTH NATIVE CORRECTION CANDIDATE (UNASSEMBLED)
; Alex Barragan and ChatGPT (Sol), 2026-10-20.
;
; Public INP_EDIT, caller-owned RAM buffer, NUL terminated. It edits text
; and returns the actual terminating event. It does NOT parse U32 or B9.
; Independent of VT20 and caller's Menu group; KBD_* is a runtime dep.
;
; Entry, registers (UA=14h, SX=1, SY=1, SZ=0, valid SYS540 stack):
; $10/11 = writable RAM buffer address, $12 = capacity INCLUDING NUL;
; $13 = viewport width (1..32), $14 = LCD start position (0..127),
;          with (position mod 32)+width <= 32;
; $15 = character class (0 printable ASCII, 1 decimal digits, 2 hex);
; $16 = UP/DOWN policy (0 ignore, 1 terminate);
; $17 = initial byte length (0..capacity-1), buffer[len] must be NUL;
; $18 = initial cursor (FFh = beginning, else 0..len);
; $19 = initial mode (0 insert, 1 overwrite).
; Return $0=0 normal terminating key, 1 MENU, 2 BRK, 3 BAD_CONFIG;
;        $8=actual decoded terminating key (00 for BRK/invalid),
;        $9=final length; edited data and terminating NUL stay in buffer.
; FK1..FK4, EXE, MENU, BRK always terminate in one press/release;
; UP/DOWN only when enabled. Menu aliases and 'q' remain text input.
; LEFT/RIGHT, BS=08h, DEL=11h, INS=12h (owner r010b native diagnostic)
; perform editing. INS toggles insert/overwrite. Full insertion shows
; a transient '!' in the window without changing backing storage.
; On success: starts KBD card-local session, resets it on EVERY exit
; before the caller may resume host CRTKY/Menu. No auto-repeat.
; No non-field LCD text is changed. Portable CH08 S003 SYS540 cursor: custom
; underline render / TM idle blink, never dependent on PB C-ROM cursor.
; With no raw key, nonblocking K540_RAW+SYS540_POLL keeps blink alive;
; when ready K540_GET performs the existing full press/release handoff.
; Private scratch RAM INP_*=27E0..27ECh, caller supplies its own field.
; Clobbers all working registers, IX/IY/IZ and CPU flags; non-reentrant.
; Key mappings, cursor rendering, ABI and RAM use require native tests
; on each model with one identical ROM. No native PASS asserted.
; ======================================================================
INP_EDIT:
        PST     UA,&H14
        PRE     IX,INP_PTR
        STW     $10,(IX+$SX)
        PRE     IX,INP_CAP
        ST      $12,(IX+$SX)
        PRE     IX,INP_WIDTH
        ST      $13,(IX+$SX)
        PRE     IX,INP_POS
        ST      $14,(IX+$SX)
        PRE     IX,INP_CLASS
        ST      $15,(IX+$SX)
        PRE     IX,INP_UPDN
        ST      $16,(IX+$SX)
        PRE     IX,INP_LEN
        ST      $17,(IX+$SX)
        PRE     IX,INP_MODE
        ST      $19,(IX+$SX)
; Cursor default is at BEGINNING, NOT at end of existing input.
        LD      $0,$18
        SBC     $0,&HFF
        JR      NZ,INP_CUR_ARG
        LD      $18,0
INP_CUR_ARG:
        PRE     IX,INP_CUR
        ST      $18,(IX+$SX)
        PRE     IX,INP_LEFT
        LD      $0,0
        ST      $0,(IX+$SX)
; Reject malformed descriptor before writing any caller buffer bytes.
        AN      $12,$12
        JP      Z,INP_BAD
        LD      $0,$17
        SBC     $0,$12
        JP      NC,INP_BAD
        AN      $13,$13
        JP      Z,INP_BAD
        LD      $0,$13
        SBC     $0,33
        JP      NC,INP_BAD
        LD      $0,$14
        SBC     $0,128
        JP      NC,INP_BAD
        LD      $0,$14
        AN      $0,&H1F
        AD      $0,$13
        SBC     $0,33
        JP      NC,INP_BAD
        LD      $0,$15
        SBC     $0,3
        JP      NC,INP_BAD
        LD      $0,$16
        SBC     $0,2
        JP      NC,INP_BAD
        LD      $0,$19
        SBC     $0,2
        JP      NC,INP_BAD
        LD      $0,$18
        SBC     $0,$17
        JP      C,INP_CHKNUL
        JP      Z,INP_CHKNUL
        JP      INP_BAD
INP_CHKNUL:
        LD      $22,$17
        CAL     INP_READ
        AN      $16,$16
        JP      NZ,INP_BAD
        CAL     KBD_INIT
        CAL     SYS540_INIT
        CAL     INP_DRAW
INP_WAIT:
; Chapter 08 portable nonblocking cursor idle loop: KBD_EVENT blocks,
; so never enter it while no physical key is down.
        CAL     K540_RAW
        AN      $17,$17
        JP      NZ,INP_READY
        CAL     SYS540_POLL
        AN      $18,$18
        JP      Z,INP_WAIT
        CAL     SYS540_TOGGLE
        JP      INP_WAIT
INP_READY:
        CAL     KBD_EVENT
        SBC     $17,K540_EV_BRK
        JP      Z,INP_BRK
        SBC     $17,K540_EV_MENU
        JP      Z,INP_MENU
        SBC     $17,K540_EV_CHAR
        JP      NZ,INP_WAIT
        PRE     IX,INP_KEY
        ST      $0,(IX+$SX)
        LD      $12,$0
        SBC     $12,KEYEXE
        JP      Z,INP_KEYEXIT
        SBC     $12,KEYF1
        JP      Z,INP_KEYEXIT
        SBC     $12,KEYF2
        JP      Z,INP_KEYEXIT
        SBC     $12,KEYF3
        JP      Z,INP_KEYEXIT
        SBC     $12,KEYF4
        JP      Z,INP_KEYEXIT
        SBC     $12,KEYUP
        JP      Z,INP_UPKEY
        SBC     $12,KEYDN
        JP      Z,INP_UPKEY
        SBC     $12,KEYLEFT
        JP      Z,INP_GOLEFT
        SBC     $12,KEYRIGHT
        JP      Z,INP_GORIGHT
        SBC     $12,&H08
        JP      Z,INP_BSPACE
        SBC     $12,KEYDEL
        JP      Z,INP_DELETE
        SBC     $12,KEYINS
        JP      Z,INP_TOGGLE
; Printable classification and optional mechanical field restriction.
        LD      $12,$0
        SBC     $12,&H20
        JP      C,INP_WAIT
        SBC     $12,&H7F
        JP      NC,INP_WAIT
        PRE     IX,INP_CLASS
        LD      $15,(IX+$SX)
        AN      $15,$15
        JP      Z,INP_ACCEPT
        LD      $12,$0
        SBC     $12,&H30
        JP      C,INP_WAIT
        SBC     $12,&H3A
        JP      C,INP_ACCEPT
        LD      $12,$15
        SBC     $12,2
        JP      NZ,INP_WAIT
        LD      $12,$0
        SBC     $12,&H41
        JP      C,INP_HEXLOW
        SBC     $12,&H47
        JP      C,INP_ACCEPT
INP_HEXLOW:
        LD      $12,$0
        SBC     $12,&H61
        JP      C,INP_WAIT
        SBC     $12,&H67
        JP      NC,INP_WAIT
INP_ACCEPT:
        PRE     IX,INP_CUR
        LD      $23,(IX+$SX)
        PRE     IX,INP_LEN
        LD      $24,(IX+$SX)
        PRE     IX,INP_MODE
        LD      $15,(IX+$SX)
        AN      $15,$15
        JP      Z,INP_INSERT
        JP      INP_OVERWRITE
INP_INSERT:
        PRE     IX,INP_CAP
        LD      $12,(IX+$SX)
        SB      $12,$SY
        SBC     $24,$12
        JP      NC,INP_FULL
; Shift [cursor..len] including original NUL one cell to the right.
; Descending copy is safe even when source and destination overlap.
        LD      $25,$24
INP_SHIFT_R:
        LD      $22,$25
        CAL     INP_READ
        AD      $22,$SY
        CAL     INP_WRITE
        SBC     $25,$23
        JP      Z,INP_SHIFT_DONE
        SB      $25,$SY
        JP      INP_SHIFT_R
INP_SHIFT_DONE:
; The shifted NUL now resides at old length+1.  Always advance the
; *logical* length, even when insertion was before the old last byte.
; Keep $24 in step with INP_LEN so the common putkey path cannot
; accidentally restore the old length when cursor+1 == old length.
        AD      $24,$SY
        PRE     IX,INP_LEN
        ST      $24,(IX+$SX)
        JP      INP_PUTKEY
INP_OVERWRITE:
        SBC     $23,$24
        JP      C,INP_PUTKEY
; At end: overwrite extends text only when spare capacity remains.
        PRE     IX,INP_CAP
        LD      $12,(IX+$SX)
        SB      $12,$SY
        SBC     $24,$12
        JP      NC,INP_FULL
        LD      $22,$23
        AD      $22,$SY
        LD      $16,0
        CAL     INP_WRITE
INP_PUTKEY:
        PRE     IX,INP_KEY
        LD      $16,(IX+$SX)
        LD      $22,$23
        CAL     INP_WRITE
        AD      $23,$SY
        PRE     IX,INP_CUR
        ST      $23,(IX+$SX)
        SBC     $23,$24
        JP      C,INP_REPAINT
        PRE     IX,INP_LEN
        ST      $23,(IX+$SX)
INP_REPAINT:
        CAL     INP_DRAW
        JP      INP_WAIT
INP_GOLEFT:
        PRE     IX,INP_CUR
        LD      $0,(IX+$SX)
        AN      $0,$0
        JP      Z,INP_WAIT
        SB      $0,$SY
        ST      $0,(IX+$SX)
        JP      INP_REPAINT
INP_GORIGHT:
        PRE     IX,INP_CUR
        LD      $0,(IX+$SX)
        PRE     IX,INP_LEN
        LD      $12,(IX+$SX)
        SBC     $0,$12
        JP      NC,INP_WAIT
        AD      $0,$SY
        PRE     IX,INP_CUR
        ST      $0,(IX+$SX)
        JP      INP_REPAINT
INP_BSPACE:
        PRE     IX,INP_CUR
        LD      $23,(IX+$SX)
        AN      $23,$23
        JP      Z,INP_WAIT
        LD      $24,$23
        SB      $24,$SY
        JP      INP_SHIFT_L
INP_DELETE:
        PRE     IX,INP_CUR
        LD      $24,(IX+$SX)
        PRE     IX,INP_LEN
        LD      $12,(IX+$SX)
        SBC     $24,$12
        JP      NC,INP_WAIT
        LD      $23,$24
        AD      $23,$SY
INP_SHIFT_L:
; On backspace: source starts at old cursor, destination cursor-1.
; On delete: source starts at old cursor+1, destination old cursor.
        PRE     IX,INP_LEN
        LD      $25,(IX+$SX)
INP_SLEFT:
        LD      $22,$23
        CAL     INP_READ
        LD      $22,$24
        CAL     INP_WRITE
        SBC     $23,$25
        JP      Z,INP_LDONE
        AD      $23,$SY
        AD      $24,$SY
        JP      INP_SLEFT
INP_LDONE:
        PRE     IX,INP_LEN
        LD      $0,(IX+$SX)
        SB      $0,$SY
        ST      $0,(IX+$SX)
; Backspace moves the cursor left, delete leaves it where it was.
        PRE     IX,INP_KEY
        LD      $12,(IX+$SX)
        SBC     $12,&H08
        JP      NZ,INP_REPAINT
        PRE     IX,INP_CUR
        LD      $0,(IX+$SX)
        SB      $0,$SY
        ST      $0,(IX+$SX)
        JP      INP_REPAINT
INP_TOGGLE:
; Explicit modes and labels rather than a blind XOR; easy to probe natively.
        PRE     IX,INP_MODE
        LD      $0,(IX+$SX)
        AN      $0,$0
        JP      Z,INP_MOD_OVER
        LD      $0,0       ; overwrite -> insert
        JP      INP_MOD_STORE
INP_MOD_OVER:
        LD      $0,1       ; insert -> overwrite
INP_MOD_STORE:
        ST      $0,(IX+$SX)
        JP      INP_REPAINT
INP_UPKEY:
        PRE     IX,INP_UPDN
        LD      $12,(IX+$SX)
        AN      $12,$12
        JP      Z,INP_WAIT
        JP      INP_KEYEXIT
INP_KEYEXIT:
        LD      $15,0
        JP      INP_FINISH
INP_MENU:
        PRE     IX,INP_KEY
        LD      $12,KEYMENU
        ST      $12,(IX+$SX)
        LD      $15,1
        JP      INP_FINISH
INP_BRK:
        LD      $15,2
        PRE     IX,INP_KEY
        LD      $12,0
        ST      $12,(IX+$SX)
INP_FINISH:
        PRE     IX,INP_EXIT
        ST      $15,(IX+$SX)
        CAL     SYS540_STOP
        CAL     KBD_RESET
        PRE     IX,INP_KEY
        LD      $8,(IX+$SX)
        PRE     IX,INP_LEN
        LD      $9,(IX+$SX)
        PRE     IX,INP_EXIT
        LD      $0,(IX+$SX)
        RTN
INP_BAD:
        LD      $0,3
        LD      $8,0
        LD      $9,0
        RTN
INP_FULL:
; Brief non-destructive on-screen feedback, restored on next repaint.
        CAL     INP_DRAW
        CAL     INP_SETPOS
        LD      $16,&H21
        CAL     PUTC
        CAL     INP_CURSOR
        JP      INP_WAIT

; Update window origin only when cursor would leave the visible window.
INP_DRAW:
; CH08 cursor overlay must restore its underlying glyph before repaint.
        CAL     SYS540_HIDE
        PRE     IX,INP_CUR
        LD      $0,(IX+$SX)
        PRE     IX,INP_LEFT
        LD      $1,(IX+$SX)
        SBC     $0,$1
        JR      NC,INP_CRIGHT
        PRE     IX,INP_CUR
        LD      $0,(IX+$SX)
        PRE     IX,INP_LEFT
        ST      $0,(IX+$SX)
INP_CRIGHT:
        PRE     IX,INP_CUR
        LD      $0,(IX+$SX)
        PRE     IX,INP_LEFT
        LD      $1,(IX+$SX)
        SB      $0,$1
        PRE     IX,INP_WIDTH
        LD      $2,(IX+$SX)
        SBC     $0,$2
        JR      C,INP_RENDER
        PRE     IX,INP_CUR
        LD      $0,(IX+$SX)
        SB      $0,$2
        AD      $0,$SY
        PRE     IX,INP_LEFT
        ST      $0,(IX+$SX)
INP_RENDER:
        PRE     IX,INP_POS
        LD      $6,(IX+$SX)
        PRE     IX,INP_WIDTH
        LD      $24,(IX+$SX)
        PRE     IX,INP_LEFT
        LD      $23,(IX+$SX)
INP_RLOOP:
        PRE     IX,INP_LEN
        LD      $12,(IX+$SX)
        SBC     $23,$12
        JR      NC,INP_RSPACE
        LD      $22,$23
        CAL     INP_READ
        JR      INP_RPUT
INP_RSPACE:
        LD      $16,&H20
INP_RPUT:
; PUTC may cross platform firmware; preserve loop counters.
        PHS     $23
        PHS     $24
        CAL     PUTC
        PPS     $24
        PPS     $23
        AD      $23,$SY
        SB      $24,$SY
        JP      NZ,INP_RLOOP
INP_CURSOR:
; Overlay '_' must be placed over the REAL glyph at cursor position;
; SYS540_PLACE atomically hides the old overlay, moves and repaints.
        CAL     INP_SETPOS
        PRE     IX,INP_CUR
        LD      $22,(IX+$SX)
        PRE     IX,INP_LEN
        LD      $12,(IX+$SX)
        SBC     $22,$12
        JP      NC,INP_CBLANK
        CAL     INP_READ
        JP      INP_CPLACE
INP_CBLANK:
        LD      $16,&H20
INP_CPLACE:
        CAL     SYS540_PLACE
        RTN
INP_SETPOS:
        PRE     IX,INP_CUR
        LD      $6,(IX+$SX)
        PRE     IX,INP_LEFT
        LD      $0,(IX+$SX)
        SB      $6,$0
        PRE     IX,INP_POS
        LD      $0,(IX+$SX)
        AD      $6,$0
        RTN

; Private single-indexed RAM operations; read/write leave index $22
; untouched so callers may shift overlapping regions safely.
INP_READ:
        PRE     IX,INP_PTR
        LDW     $20,(IX+$SX)
        LDW     $2,0
        LD      $2,$22
        ADW     $20,$2
        PRE     IX,$20
        LD      $16,(IX+$SX)
        RTN
INP_WRITE:
        PRE     IX,INP_PTR
        LDW     $20,(IX+$SX)
        LDW     $2,0
        LD      $2,$22
        ADW     $20,$2
        PRE     IX,$20
        ST      $16,(IX+$SX)
        RTN
