📄 edit.asm
字号:
; EDIT.ASM
; (c) 1989, 1990 Ashok P. Nadkarni
;
; This module contains the line editing functions of CMDEDIT.
PUBLIC get_kbd_line
PUBLIC auto_recall
PUBLIC expand_fnkey
INCLUDE common.inc
INCLUDE ascii.inc
INCLUDE BIOS.INC
INCLUDE DOS.INC
INCLUDE GENERAL.INC
CSEG SEGMENT PARA PUBLIC 'CODE'
CSEG ENDS
DGROUP GROUP CSEG
ASSUME CS:DGROUP, DS:DGROUP, SS:DGROUP, ES:DGROUP
CSEG SEGMENT PARA PUBLIC 'CODE'
EXTRN linebuf:BYTE
EXTRN lastchar:WORD
EXTRN caller_cursor:WORD
EXTRN dot:WORD
EXTRN edit_mode:BYTE
EXTRN omode_cursor:WORD
EXTRN sym_stk:WORD
EXTRN LINEBUF_END:ABS
tempchar db ? ;Temporary storage
auto_recall db 0 ;By default no auto recall
auto_recall_on db ? ;1 if auto-recall in effect,
; else 0
continue_recall db ? ;auto-recall state variable
fnkey_tab db 'S','F',0 ;Used to look for function key
; definitions.
fnkey_exec_char db '@' ;If the last character a fn key
; definition is this, the key is
; executed immediately
; Must be IDENTICAL to the string in CMDCONF.C including the
; terminating '\0' byte. This must be followed immediately by ctrl_key_defs.
cmdedit_keymap_id db 'CMDEDIT key map',0
; ctrl_key_redefs is used to allow the cmdconf program to remap the control
; keys. Each entry corresponds to a control key. It must immediately follow
; cmdedit_keymap_id.
ctrl_key_redefs LABEL WORD
x = 0
REPT 32 ;32 control keys
DW x
x = x + 1
ENDM
EXTRN disp_line:PROC
EXTRN hist_back:PROC
EXTRN hist_fwd:PROC
EXTRN hist_bck_match:PROC
EXTRN hist_fwd_match:PROC
EXTRN remember:PROC
EXTRN execute_auto_recall:PROC
EXTRN insert_at_dot:PROC
EXTRN erase_to_dot:PROC
EXTRN isalphnum:PROC
EXTRN set_disp_marks:PROC
EXTRN bell:PROC
EXTRN line_to_scr:PROC
EXTRN isspace:PROC
EXTRN xlate_lower:PROC
EXTRN expand_var:PROC
EXTRN ismacsym:PROC
EXTRN get_symbol:PROC
;number of command keys
NUM_CMD_KEYS EQU (cmd_key_jumps-cmd_key_table)/2
;+
; FUNCTION : get_kbd_line
;
; Gets a line from the user and stores it in linebuf. The length
; of the line is stored in global linelen. The name is a misnomer
; because the line is from standard input, not necessarily from
; the keyboard.
;
; Parameters:
; None.
;
; Returns:
; Nothing.
; Register(s) destroyed:
;-
get_kbd_line proc near
@save si,di
mov al,auto_recall
mov auto_recall_on,al ;Indicate if auto-recall is enabled
mov continue_recall,1 ;Init auto-recall memory
; Main editing loop
@get_kbd_line_10:
mov al,continue_recall
and auto_recall_on,al ;Indicate if we should keep
; auto-recalling
mov continue_recall,0 ;Reset the flag. It will be set
; for the default actions keys.
call near ptr disp_line ;Show current line
call near ptr getkey ;get next key from the user
mov si,ax ;si holds the character
cmp ax,32 ;Control character ?
jge @get_kbd_line_15 ;No, then check if fn key
mov di,si ;DI used to calculate
add di,di ; offset into table
mov ax,ctrl_key_redefs[di] ;Mapping of key
mov si,ax
cmp ax,32 ;Control char ?
jge @get_kbd_line_15 ;No, then check if fn key
mov di,si ;DI used to calculate
add di,di ; offset into table
jmp ctrl_key_table[di] ;Branch according to control char
@get_kbd_line_15: ;Check if function key
cmp ax,256+59 ;>= F1 ?
jb @get_kbd_line_20 ;No, then check next table
cmp ax,256+68 ;<= F10
jg @get_kbd_line_20 ;Not fn key
jmp @fn_key ;Handle the function key
@get_kbd_line_20:
cmp ax,256+84 ;>= Shift-F1 ?
jb @get_kbd_line_25 ;No, then check next table
cmp ax,256+93 ;<= Shift-F10
jg @get_kbd_line_25 ;
jmp @sfn_key ;Handle the shifted function key
@get_kbd_line_25:
mov cx,NUM_CMD_KEYS ;size and...
mov bx,offset DGROUP:cmd_key_table ;beginning of jump table
@get_kbd_line_30: ;Loop begin
cmp ax,cs:[bx] ;Is this the key ?
je @get_kbd_line_40 ;Hurrah, found
inc bx ;point to next key
inc bx
loop @get_kbd_line_30 ;If more keys, repeat
jmp short @default_action ;key not in table
@get_kbd_line_40: ;Jump to location associated with
jmp word ptr cs:[bx+(2*NUM_CMD_KEYS)] ;key
@quote: ;Insert next char
; without interpreting it
call near ptr getkey
@default_action: ;Insert the character (in AX)
call near ptr store_char
jc @get_kbd_line_10 ;No room for char, keep looping
mov al,auto_recall_on ;Are we auto-recalling ?
or al,al
jz @get_kbd_line_10 ;No
call near ptr execute_auto_recall
jc @get_kbd_line_10 ;If carry set, no matching
; string in history buffer
mov continue_recall,1 ;Else indicate auto-recall is
; still to go on
jmp short @get_kbd_line_10
@char_left: ;Cursor one char left
call near ptr char_left ;char_left will return to top
jmp @get_kbd_line_10
; of editing loop
@char_right: ;Cursor one char right
call near ptr char_right ;char_right will return to top
jmp @get_kbd_line_10
; of editing loop
@word_left: ;Cursor one word left
call near ptr word_left
jmp @get_kbd_line_10
@word_right: ;Cursor one word right
call near ptr word_right
jmp @get_kbd_line_10
@bol: ;Beginning of line
call near ptr go_bol
jmp @get_kbd_line_10
@eol: ;End of line
call near ptr go_eol
jmp @get_kbd_line_10
@prev_line: ;Get previous history line
mov ax,offset DGROUP:hist_back
@history_line:
call ax
mov ax,lastchar
mov dot,ax ;Leave cursor at end of line
@history_search:
jnc @history_line_done ;Line found
call near ptr bell ;No line
@history_line_done:
jmp @get_kbd_line_10
@next_line: ;Get next history line
mov ax,offset DGROUP:hist_fwd
jmp short @history_line
@search_back: ;Search back thru history buffer
mov ax,offset DGROUP:hist_bck_match
@search:
mov di,dot ;Save current dot
call ax
mov dot,di ;Restore it
jmp short @history_search
@search_forw: ;Search forward thru history buffer
mov ax,offset DGROUP:hist_fwd_match
jmp short @search
@filename: ;Try to find a matching filename
call near ptr match_file
cmp auto_recall_on,1 ;Autorecall ongoing?
je short @del_eol ;Yes, then delete to end of line
jmp @get_kbd_line_10
@del_left: ;Delete char before cursor
mov ax,offset dgroup:char_left
jmp short @delete
@del_right: ;Delete char at cursor
mov ax,offset dgroup:char_right
jmp short @delete
@del_prev_word: ;Delete upto word beginning
mov ax,offset dgroup:word_left
jmp short @delete
@del_next_word: ;Delete to start of next word
mov ax,offset dgroup:word_right
jmp short @delete
@del_bol: ;Delete to beginning of line
mov ax,offset dgroup:go_bol
jmp short @delete
@toggle_insert:
mov ax,1
xor al,edit_mode ;Toggle edit mode
mov edit_mode,al
xchg ax,bx
add bx,bx ;Word offset
mov cx,omode_cursor[bx] ;cx<-cursor shape
mov ah,01h ;Set cursor size function
IF TOGGLE_CURSOR
int 10h ;BIOS
ENDIF
jmp @get_kbd_line_10 ;Repeat editing loop
@abort_and_store: ;Erases current line but remembers
; it in the history buffer
call near ptr remember
; Fall through to erase line
@erase_line:
call near ptr go_bol ;Move dot to beginning of line
; fall thru to delete to end of line
@del_eol: ;Delete to end of line
mov ax,offset dgroup:go_eol
@delete: ;General purpose delete
mov si,dot ;Remember the dot
call ax ;Move dot to new position
xchg si,ax
call near ptr erase_to_dot ;Delete characters between ax and dot
jmp @get_kbd_line_10
@autorecall:
xor auto_recall,1 ;Toggle auto recall mode
jmp @get_kbd_line_10
@vars:
; Expand the variables on the line.
call near ptr expand_var
jmp @get_kbd_line_10 ;Ignore return status from expand_var
@inline_back:
@inline_forw:
@ignore:
jmp @get_kbd_line_10 ;Ignore the character
ctrl_key_table LABEL WORD
dw @ignore ;NUL or ^@
dw @bol ;^A
dw @char_left ;^B
dw @ignore ;^C
dw @del_right ;^D
dw @eol ;^E
dw @char_right ;^F
dw @abort_and_store ;^G
dw @del_left ;^H
dw @filename ;^I
dw @vars ;^J might have to be @ignore in order for input
; redirection to work properly but try for
; var expansion anyway.
dw @del_eol ;^K
dw @del_prev_word ;^L
dw @done_editing ;^M
dw @next_line ;^N
dw @del_eol_exec ;^O
dw @ignore ;^P - don't use, filtered by get key call ?
dw @quote ;^Q
dw @search_back ;^R
dw @ignore ;^S - don't use, does not work properly
dw @ignore ;^T
dw @prev_line ;^U
dw @search_forw ;^V
dw @del_next_word ;^W
dw @del_bol ;^X
dw @autorecall ;^Y
dw @default_action ;^Z
dw @erase_line ;^[ or ESC
dw @inline_back ;^\
dw @inline_forw ;^]
dw @done_wipeout ;^^
dw @ignore ;^_
cmd_key_table: ;table of command keys
dw 127 ;DEL
dw 327 ;HOME
dw 328 ;UP
dw 331 ;LEFT
dw 333 ;RIGHT
dw 335 ;END
dw 336 ;DOWN
dw 338 ;INS
dw 339 ;KDEL
dw 371 ;CTLLEFT
dw 372 ;CTLRIGHT
cmd_key_jumps:
dw @del_left ;DEL
dw @bol ;HOME
dw @prev_line ;UP
dw @char_left ;LEFT
dw @char_right ;RIGHT
dw @eol ;END
dw @next_line ;DOWN
dw @toggle_insert ;INS
dw @del_right ;KDEL
dw @word_left ;CTLLEFT
dw @word_right ;CTLRIGHT
@sfn_key:
; A shifted function key has been struck.
; (Treat same as an unshifted function key).
@fn_key:
; A function key has been struck.
call near ptr expand_fnkey
jc @fn_key_20 ;Error or no expansion
or dx,dx ;Line to be executed
; immediately ?
je short @done_editing_2 ;Yes, all done
@fn_key_20:
jmp @get_kbd_line_10 ;else keep editing
@del_eol_exec: ;Deletes characters from the dot
; to end of the line and then
; executes the line
mov si,dot ;Remember the dot
call go_eol
xchg si,ax
call near ptr erase_to_dot
jmp short @done_editing
@done_wipeout:
; The line is executed. However it is not stored in the history buffer and
; is also removed from the screen (this is a little klugy).
mov ax,offset DGROUP:linebuf
mov dot,ax
mov dx,lastchar
mov lastchar,ax ;Temporarily pretend line
; is empty
xchg ax,dx
push ax
call near ptr set_disp_marks
call disp_line
pop ax
mov lastchar,ax ;Restore line length
jmp short @get_kbd_line_90
@done_editing:
call near ptr remember ;Store in history buffer
; Picks up line from global linebuf
@done_editing_2:
call near ptr disp_line ;Necessry for @del_eol_exec,
; might as well do for others
mov ax,lastchar
mov dot,ax ;Set dot to end of line
call near ptr line_to_scr ;Set cursor beyond last character
@get_kbd_line_90:
@DispCh CR ;Do a carraige return because
; some applications like EDLIN
; only do a LF to go to next line
; @DispCh LF ;Go onto next line
; all done
@get_kbd_line_99:
@restore
ret
get_kbd_line endp
getkey proc near
@GetKey 0
mov ah,0
or al,al
jne @114 ;not '\0'
mov ah,0Bh
int 21h ;check if key available
or al,al
jz @113 ;no character available
@GetKey 0
mov ah,1
jmp short @114
@113:
xor ax,ax
@114:
ret
getkey endp
;+
; FUNCTION : expand_fnkey
;
; Inserts the expansion corresponding to a symbol key into the
; linebuffer. If the buffer is too small, only as many characters as
; possible are inserted and the function returns an error. The
; function also returns an error if the symbols is not defined. The
; function also updates the displayed line. The function also checks
; if the line is to be executed immediately or not, based on the last
; character of the fn key expansion.
;
; Parameters:
; AX = function key character, must be between (256+59)-(256+68)
; function keys and (256+84)-(256+93) for shifted functin keys.
;
; Returns:
; CF = 0 if no error, else 1
; If CF is 1, then AX is 0 if symbol not found or non-zero
; if symbol found but no room in line.
; AX = 1 if symbol was present
; 0 if symbol was not found.
; DX = 0 if the line is to be executed immediately
; non-0 otherwise
; DX is only valid if CF=0 and AX=1
; Register(s) destroyed:
; <TBA>
;-
expand_fnkey proc near
@save si,di
push bp
mov bp,sp
sub sp,LINEBUF_SIZE
exp_buf equ <byte ptr [bp-LINEBUF_SIZE]>
mov si,offset DGROUP:fnkey_tab ;SI->'SFn'
mov dx,3 ;DX<-length of string
mov di,si
sub ax,256+59
cmp ax,10 ;Is it a function key
jnb @expand_fnkey_10 ;No, shifted function key
inc si ;SI->'Fn'
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -