GetLineStack
From Pickwiki
Jump to navigationJump to searchBack to BasicSource
SUBROUTINE GET.LINE(X,XXLENGTH,DISP.LEN,XXDATA,RTN.CHAR)
************************************************************************
* Program: GET.LINE.STACK
* Author : Ian [[McGowan]]
* Date : 6/24/89
* Edited : 16:49:22 Nov 19 1998 By MCGOWAN
* Comment: Get a line of data with editing keys
************************************************************************
* Date By Desc
* -------- ---- ----------------------------------------------------
*10/02/95* IAN Attempt to fix 'turd' bug -- JIM
*10/02/95 IAN Add CTRL-B for back -- JIM
*09/14/95 IAN Add CTRL-W for delete word -- JIM
*01/02/94 IAN Trap HOME and END key, Also add del word and line -- JIM
*01/25/94 IAN CTRL-D exits -- JIM
*08/22/97 IAN Add wyse support, make more emacs like
************************************************************************
* X = X POS
* XXLENGTH = MAX ALLOWED LENGTH
* DISP.LEN = MAX DISPLAYED XXLENGTH
* XXDATA = ON INPUT VARIABLE XXDATA
* = ON OUTPUT RETURNED STRING
* RTN.CHAR = SEQ(CHAR PRESSED TO EXIT)
* Important globals
* CP = Cursor Position, Y coordinate on the screen 0 -> DISP.LEN
* CH.PTR = Pointer into string being edited 1 -> XXLENGTH
* POS = Pointer to first char currently displayed 1 -> XXLENGTH
* ASC.CH = The numeric value of the key just entered
INIT:
EQU INSERT TO '1',REPLACE TO '-1',BEEP TO CHAR(7)
EQU ESC TO CHAR(27),AM TO CHAR(254)
EQU NUL TO '',TRUE TO 1,FALSE TO 0,SPACE TO ' '
TERM=UPCASE(GETENV("TERM"))
IF INDEX(TERM,'WY',1) THEN TERM='W'
PROMPT NUL
ECHO OFF
MODE = REPLACE ; TEMP.XXDATA =XXDATA
BASE = @(X) ; MASK = 'L#':DISP.LEN
PRINT BASE:
CURR.LEN = LEN(XXDATA)
GOSUB GO.END
RTN.CHAR=''
MAIN:
LOOP
PRINT @(X+CP):
CH=IN()
ASC.CH = SEQ(CH)
EXIT.FLAG=FALSE
BEGIN CASE
CASE ASC.CH = 1
GOSUB GO.BEGIN
CASE ASC.CH = 2
GOSUB LEFT
CASE ASC.CH = 4
GOSUB DEL
CASE ASC.CH = 5
GOSUB GO.END
CASE ASC.CH = 6
GOSUB RIGHT
CASE ASC.CH = 8 AND TERM='W'
GOSUB LEFT
CASE ASC.CH = 8
GOSUB BACK
CASE ASC.CH = 9
GOSUB FORWARD.WORD
CASE ASC.CH = 10 AND TERM='W'
RTN.CHAR=2
EXIT.FLAG=TRUE
CASE ASC.CH = 10
GOSUB DEL.TO.END
CASE ASC.CH=11 AND TERM='W'
RTN.CHAR=1
EXIT.FLAG=TRUE
CASE ASC.CH=12 AND TERM='W'
GOSUB RIGHT
CASE ASC.CH = 13
EXIT.FLAG = TRUE
RTN.CHAR=13
CASE ASC.CH = 14
RTN.CHAR=2
EXIT.FLAG=TRUE
CASE ASC.CH = 16
RTN.CHAR=1
EXIT.FLAG=TRUE
CASE ASC.CH = 18
GOSUB INSRT
CASE ASC.CH = 23
GOSUB DELETE.WORD
CASE ASC.CH = 24
GOSUB FORWARD.WORD
CASE ASC.CH = 25
XXDATA = ''
EXIT.FLAG=TRUE
RTN.CHAR=13
CASE ASC.CH = 26
GOSUB BACK.WORD
CASE ASC.CH = 27
GOSUB ESC.KEY
CASE ASC.CH < 27
PRINT @(0):ASC.CH:
CASE ASC.CH = 127
GOSUB BACK
CASE 1
GOSUB ORD
END CASE
CURR.LEN = LEN(XXDATA)
UNTIL EXIT.FLAG DO
REPEAT
IF XXDATA[CURR.LEN,1] = SPACE THEN XXDATA = XXDATA[1,CURR.LEN-1]
ECHO ON ; PRINT BASE:XXDATA MASK
RETURN
ORD:
* Ordinary key pressed
IF CH.PTR # XXLENGTH+1 THEN
IF MODE = INSERT THEN
IF CURR.LEN = XXLENGTH THEN
PRINT BEEP:
GOTO SKIP1
END ELSE
XXDATA = XXDATA[1,CH.PTR-1]:CH:XXDATA[CH.PTR,CURR.LEN]
END
END ELSE
XXDATA = XXDATA[1,CH.PTR-1]:CH:XXDATA[CH.PTR+1,CURR.LEN]
END
CH.PTR = CH.PTR + 1
IF CP # DISP.LEN THEN
PRINT @(X+CP):CH:
IF MODE = INSERT THEN
PRINT XXDATA[CH.PTR,DISP.LEN-CP-1]:
END
CP = CP + 1
END ELSE
POS = POS + 1
PRINT BASE:XXDATA[POS,DISP.LEN] MASK:
END
END ELSE
PRINT BEEP:
END
SKIP1:
RETURN
RIGHT:
* There are 3 situations here -
* 1 We're pressing the right arrow thru existing text (CH.PTR = CURR.LEN)
* 2 We've typed text and are at the end when we press right (CH.PTR > CURR.LEN)
* 3 We're in the middle of text, pressing the right arrow (CH.PTR < CURR.LEN)
IF CH.PTR < XXLENGTH THEN
IF CH.PTR > CURR.LEN THEN PRINT BEEP: ; GOTO SKIP2
IF CH.PTR = CURR.LEN THEN
* If the last char is not a space make it one
IF XXDATA[CURR.LEN,1] # SPACE THEN
XXDATA = XXDATA:SPACE
IF CP # DISP.LEN THEN PRINT @(X+CP+1):SPACE:
CURR.LEN = CURR.LEN + 1
END ELSE
PRINT BEEP:
GOTO SKIP2
END
END
CH.PTR = CH.PTR + 1
IF CP # DISP.LEN THEN
* We're not at the end of display so just move the cursor
CP = CP + 1
END ELSE
* We are at the end of the display so leave cursor where
* it is and scroll through line
POS = POS + 1
PRINT BASE:XXDATA[POS,DISP.LEN] MASK:
END
END ELSE
PRINT BEEP:
END
SKIP2:
RETURN
FORWARD.WORD:
* Tab key pressed - move forwards a word
IF CH.PTR >= CURR.LEN THEN
PRINT BEEP:
END ELSE
LOOP
CH.PTR = CH.PTR + 1
CP = CP + 1
UNTIL XXDATA[CH.PTR,1] = SPACE OR CH.PTR = CURR.LEN DO
REPEAT
IF CH.PTR # CURR.LEN THEN
LOOP
CH.PTR = CH.PTR + 1
CP = CP + 1
UNTIL XXDATA[CH.PTR,1] # SPACE OR CH.PTR = CURR.LEN DO
REPEAT
END
IF CP > DISP.LEN THEN
CP = DISP.LEN
POS = CH.PTR - DISP.LEN
PRINT BASE:XXDATA[POS,DISP.LEN] MASK:
END
END
RETURN
LEFT:
* If we're not at the start of data, move left
IF CH.PTR # 1 THEN
CH.PTR = CH.PTR - 1
IF CP # 0 THEN
* We're not at the start of the display so just move the cursor
CP = CP - 1
END ELSE
* We are at the start of the display so leave cursor and scroll
POS = POS - 1
PRINT BASE:XXDATA[POS,DISP.LEN] MASK:
END
END ELSE
PRINT BEEP:
END
RETURN
DEL:
* Delete the character at the cursor and redisplay from this point
XXDATA = XXDATA[1,CH.PTR-1]:XXDATA[CH.PTR+1,CURR.LEN]
CURR.LEN = CURR.LEN - 1
PRINT BASE:XXDATA[POS,DISP.LEN] MASK:
RETURN
BACK:
* Backspace key pressed
IF CH.PTR # 1 THEN
CH.PTR = CH.PTR - 1
XXDATA = XXDATA[1,CH.PTR-1]:XXDATA[CH.PTR+1,CURR.LEN]
CURR.LEN = CURR.LEN - 1
IF CP # 0 THEN
CP = CP - 1
END ELSE
POS = POS - 1
END
PRINT BASE:XXDATA[POS,DISP.LEN] MASK:
END ELSE
PRINT BEEP:
END
RETURN
INSRT:
* Toggle between insert and replace modes
MODE = -MODE
RETURN
ESC.KEY:
* ESC pressed, or extended key
* Get next char of extended command
ALLOW = 0
EXT.KEY=IN()
EXT = SEQ(EXT.KEY)
EXT.KEY = OCONV(EXT.KEY,'MCU')
BEGIN CASE
CASE EXT.KEY = 'D'
GOSUB DELETE.WORD
CASE EXT.KEY = '[' OR EXT.KEY = 'O'
EXT.KEY=IN()
BEGIN CASE
CASE EXT.KEY = 'C'
GOSUB RIGHT
CASE EXT.KEY = 'D'
GOSUB LEFT
CASE EXT.KEY = 'A'
RTN.CHAR=1
EXIT.FLAG=TRUE
CASE EXT.KEY = 'B'
RTN.CHAR=2
EXIT.FLAG=TRUE
END CASE
END CASE
RETURN ; * From ESC key
BACK.WORD:
* Shift tab pressed - go back a word
IF CH.PTR = 1 THEN
PRINT BEEP:
END ELSE
* 2 situations - either we're in a word already or
* we're at the start of a word
* If in a word - loop to the start of the word
* otherwise skip spaces, and then move to start of word
IF XXDATA[CH.PTR-1,1] # SPACE THEN
LOOP
UNTIL XXDATA[CH.PTR-1,1] = SPACE OR CH.PTR = 1 DO
CH.PTR = CH.PTR - 1
CP = CP - 1
REPEAT
END ELSE
* Skip spaces
LOOP
UNTIL XXDATA[CH.PTR-1,1] # SPACE OR CH.PTR = 1 DO
CH.PTR = CH.PTR - 1
CP = CP - 1
REPEAT
IF CH.PTR > 1 THEN
* At word end - move to start of word
LOOP
UNTIL XXDATA[CH.PTR-1,1] = SPACE OR CH.PTR = 1 DO
CH.PTR = CH.PTR - 1
CP = CP - 1
REPEAT
END
END
IF CP < 0 THEN
CP = 0
POS = CH.PTR
PRINT BASE:XXDATA[POS,DISP.LEN] MASK:
END
END
RETURN
DEL.TO.END:
* Delete from cursor to end of line
IF CH.PTR = 1 THEN
XXDATA = ''
CP = 0
POS = 1
END ELSE
XXDATA = XXDATA[1,CH.PTR-1]
END
CURR.LEN = LEN(XXDATA)
PRINT BASE:XXDATA[POS,DISP.LEN] MASK:
RETURN
DELETE.WORD:
* Delete to space at right of cursor
IF CH.PTR >= CURR.LEN THEN
PRINT BEEP:
END ELSE
C = CH.PTR
LOOP
C = C + 1
UNTIL XXDATA[C,1] = SPACE OR C = CURR.LEN DO
REPEAT
XXDATA = XXDATA[1,CH.PTR-1]:XXDATA[C+1,CURR.LEN]
CURR.LEN = CURR.LEN - C + CH.PTR - 1
PRINT BASE:XXDATA[POS,DISP.LEN] MASK:
END
RETURN
GO.BEGIN:
* Go to the start of data and redisplay
CP = 0
CH.PTR = 1
POS = 1
PRINT BASE:XXDATA MASK:
RETURN
GO.END:
* Move to the end of data and redisplay
IF XXDATA[CURR.LEN,1] # SPACE THEN
XXDATA = XXDATA:SPACE
CURR.LEN = CURR.LEN + 1
END
IF CURR.LEN < DISP.LEN THEN
CP = CURR.LEN - 1
POS = 1
END ELSE
CP = DISP.LEN - 1
POS = CURR.LEN - DISP.LEN + 1
END
CH.PTR = CURR.LEN
PRINT BASE:XXDATA[POS,DISP.LEN] MASK:
RETURN