|
|
@@ -0,0 +1,907 @@ |
|
|
|
|
|
; |
|
|
|
|
|
; vim.asm - minimal modal text editor for the kernal-os-skeleton shell |
|
|
|
|
|
; |
|
|
|
|
|
; Build: |
|
|
|
|
|
; ca65 vim.asm -o vim.o |
|
|
|
|
|
; ld65 -C vim.cfg vim.o -o vim.prg |
|
|
|
|
|
; |
|
|
|
|
|
; From the OS shell type: VIM |
|
|
|
|
|
; All external commands load at $2000 and end with RTS. |
|
|
|
|
|
; |
|
|
|
|
|
; Modes |
|
|
|
|
|
; NORMAL (default) h j k l or cursor keys = move |
|
|
|
|
|
; i = insert before cursor |
|
|
|
|
|
; a = append after cursor |
|
|
|
|
|
; o = open line below |
|
|
|
|
|
; x = delete char under cursor |
|
|
|
|
|
; : = enter command mode |
|
|
|
|
|
; INSERT type text, DEL = backspace, RUN/STOP = back to NORMAL |
|
|
|
|
|
; COMMAND :q quit :w NAME save to disk |
|
|
|
|
|
; RUN/STOP = cancel |
|
|
|
|
|
; |
|
|
|
|
|
; Text model: the 24x40 text area of screen RAM IS the buffer. |
|
|
|
|
|
; Row 24 (bottom line) is the status bar. |
|
|
|
|
|
; |
|
|
|
|
|
|
|
|
|
|
|
.setcpu "6502" |
|
|
|
|
|
|
|
|
|
|
|
; ---- KERNAL ---- |
|
|
|
|
|
GETIN = $FFE4 |
|
|
|
|
|
STOPKEY = $FFE1 |
|
|
|
|
|
CHROUT = $FFD2 |
|
|
|
|
|
SETLFS = $FFBA |
|
|
|
|
|
SETNAM = $FFBD |
|
|
|
|
|
OPEN = $FFC0 |
|
|
|
|
|
CLOSE = $FFC3 |
|
|
|
|
|
CHKOUT = $FFC9 |
|
|
|
|
|
CLRCH = $FFCC |
|
|
|
|
|
CLALL = $FFE7 |
|
|
|
|
|
|
|
|
|
|
|
; ---- hardware ---- |
|
|
|
|
|
SCRRAM = $0400 |
|
|
|
|
|
|
|
|
|
|
|
; ---- layout ---- |
|
|
|
|
|
SCR_COLS = 40 |
|
|
|
|
|
SCR_ROWS = 24 ; rows 0-23 = text, row 24 = status bar |
|
|
|
|
|
|
|
|
|
|
|
; ---- modes ---- |
|
|
|
|
|
MODE_NORMAL = 0 |
|
|
|
|
|
MODE_INSERT = 1 |
|
|
|
|
|
MODE_CMD = 2 |
|
|
|
|
|
|
|
|
|
|
|
; ---- PETSCII ---- |
|
|
|
|
|
CR_CH = $0D |
|
|
|
|
|
DEL_CH = $14 |
|
|
|
|
|
|
|
|
|
|
|
; ---- command buffer ---- |
|
|
|
|
|
CMD_MAX = 20 |
|
|
|
|
|
|
|
|
|
|
|
; ---- save LFN ---- |
|
|
|
|
|
SAVE_LFN = 5 |
|
|
|
|
|
SAVE_DEV = 8 |
|
|
|
|
|
|
|
|
|
|
|
; ---- zero page (user area, safe under OS banking) ---- |
|
|
|
|
|
ZP_LO = $FB ; general destination pointer lo |
|
|
|
|
|
ZP_HI = $FC ; general destination pointer hi |
|
|
|
|
|
STR_LO = $FD ; string source pointer lo |
|
|
|
|
|
STR_HI = $FE ; string source pointer hi |
|
|
|
|
|
ZP_TMP = $02 ; scratch byte |
|
|
|
|
|
|
|
|
|
|
|
; ================================================================ |
|
|
|
|
|
; PRG load address header |
|
|
|
|
|
; ================================================================ |
|
|
|
|
|
.segment "LOADADDR" |
|
|
|
|
|
.word $2000 |
|
|
|
|
|
|
|
|
|
|
|
; ================================================================ |
|
|
|
|
|
; CODE |
|
|
|
|
|
; ================================================================ |
|
|
|
|
|
.segment "CODE" |
|
|
|
|
|
|
|
|
|
|
|
; ---- entry ---- |
|
|
|
|
|
vim_main: |
|
|
|
|
|
jsr CLALL ; close any open channels from shell |
|
|
|
|
|
jsr vim_init |
|
|
|
|
|
jsr full_redraw |
|
|
|
|
|
|
|
|
|
|
|
main_loop: |
|
|
|
|
|
lda quit_flag |
|
|
|
|
|
beq ml_no_quit |
|
|
|
|
|
jmp vim_do_exit |
|
|
|
|
|
ml_no_quit: |
|
|
|
|
|
|
|
|
|
|
|
jsr get_key ; waits for keypress; $FF = RUN/STOP |
|
|
|
|
|
cmp #$FF |
|
|
|
|
|
bne ml_key_ok |
|
|
|
|
|
; RUN/STOP pressed |
|
|
|
|
|
lda cur_mode |
|
|
|
|
|
beq ml_stop_quit ; normal mode: quit |
|
|
|
|
|
lda #MODE_NORMAL ; other modes: back to normal |
|
|
|
|
|
sta cur_mode |
|
|
|
|
|
jsr full_redraw |
|
|
|
|
|
jmp main_loop |
|
|
|
|
|
ml_stop_quit: |
|
|
|
|
|
lda #1 |
|
|
|
|
|
sta quit_flag |
|
|
|
|
|
jmp main_loop |
|
|
|
|
|
ml_key_ok: |
|
|
|
|
|
sta last_key |
|
|
|
|
|
lda cur_mode |
|
|
|
|
|
cmp #MODE_INSERT |
|
|
|
|
|
bne ml_not_insert |
|
|
|
|
|
jmp handle_insert |
|
|
|
|
|
ml_not_insert: |
|
|
|
|
|
cmp #MODE_CMD |
|
|
|
|
|
bne ml_not_cmd |
|
|
|
|
|
jmp handle_cmd |
|
|
|
|
|
ml_not_cmd: |
|
|
|
|
|
; fall through = normal mode |
|
|
|
|
|
|
|
|
|
|
|
; ================================================================ |
|
|
|
|
|
; NORMAL MODE |
|
|
|
|
|
; ================================================================ |
|
|
|
|
|
handle_normal: |
|
|
|
|
|
lda last_key |
|
|
|
|
|
cmp #'H' |
|
|
|
|
|
beq nm_left |
|
|
|
|
|
cmp #$9D ; cursor-left hardware key |
|
|
|
|
|
beq nm_left |
|
|
|
|
|
cmp #'L' |
|
|
|
|
|
beq nm_right |
|
|
|
|
|
cmp #$1D ; cursor-right hardware key |
|
|
|
|
|
beq nm_right |
|
|
|
|
|
cmp #'K' |
|
|
|
|
|
beq nm_up |
|
|
|
|
|
cmp #$91 ; cursor-up hardware key |
|
|
|
|
|
beq nm_up |
|
|
|
|
|
cmp #'J' |
|
|
|
|
|
beq nm_down |
|
|
|
|
|
cmp #$11 ; cursor-down hardware key |
|
|
|
|
|
beq nm_down |
|
|
|
|
|
cmp #'I' |
|
|
|
|
|
beq nm_ins |
|
|
|
|
|
cmp #'A' |
|
|
|
|
|
beq nm_app |
|
|
|
|
|
cmp #'X' |
|
|
|
|
|
beq nm_del |
|
|
|
|
|
cmp #'O' |
|
|
|
|
|
beq nm_open |
|
|
|
|
|
cmp #':' |
|
|
|
|
|
beq nm_cmd |
|
|
|
|
|
jmp nm_done |
|
|
|
|
|
nm_left: |
|
|
|
|
|
jsr cursor_left |
|
|
|
|
|
jmp nm_done |
|
|
|
|
|
nm_right: |
|
|
|
|
|
jsr cursor_right |
|
|
|
|
|
jmp nm_done |
|
|
|
|
|
nm_up: |
|
|
|
|
|
jsr cursor_up |
|
|
|
|
|
jmp nm_done |
|
|
|
|
|
nm_down: |
|
|
|
|
|
jsr cursor_down |
|
|
|
|
|
jmp nm_done |
|
|
|
|
|
nm_ins: |
|
|
|
|
|
lda #MODE_INSERT |
|
|
|
|
|
sta cur_mode |
|
|
|
|
|
jmp nm_done |
|
|
|
|
|
nm_app: |
|
|
|
|
|
jsr cursor_right |
|
|
|
|
|
lda #MODE_INSERT |
|
|
|
|
|
sta cur_mode |
|
|
|
|
|
jmp nm_done |
|
|
|
|
|
nm_del: |
|
|
|
|
|
jsr delete_char |
|
|
|
|
|
jmp nm_done |
|
|
|
|
|
nm_open: |
|
|
|
|
|
jsr open_line_below |
|
|
|
|
|
lda #MODE_INSERT |
|
|
|
|
|
sta cur_mode |
|
|
|
|
|
jmp nm_done |
|
|
|
|
|
nm_cmd: |
|
|
|
|
|
lda #MODE_CMD |
|
|
|
|
|
sta cur_mode |
|
|
|
|
|
lda #0 |
|
|
|
|
|
sta cmd_len |
|
|
|
|
|
nm_done: |
|
|
|
|
|
jsr full_redraw |
|
|
|
|
|
jmp main_loop |
|
|
|
|
|
|
|
|
|
|
|
; ================================================================ |
|
|
|
|
|
; INSERT MODE |
|
|
|
|
|
; ================================================================ |
|
|
|
|
|
handle_insert: |
|
|
|
|
|
lda last_key |
|
|
|
|
|
cmp #CR_CH |
|
|
|
|
|
beq ins_nl |
|
|
|
|
|
cmp #DEL_CH |
|
|
|
|
|
beq ins_bs |
|
|
|
|
|
cmp #$20 ; ignore control chars below $20 |
|
|
|
|
|
bcc ins_done |
|
|
|
|
|
cmp #$7F |
|
|
|
|
|
bcs ins_done |
|
|
|
|
|
jsr insert_char ; A = PETSCII char to insert |
|
|
|
|
|
jsr cursor_right |
|
|
|
|
|
jmp ins_done |
|
|
|
|
|
ins_nl: |
|
|
|
|
|
jsr do_newline |
|
|
|
|
|
jmp ins_done |
|
|
|
|
|
ins_bs: |
|
|
|
|
|
jsr backspace_char |
|
|
|
|
|
ins_done: |
|
|
|
|
|
jsr full_redraw |
|
|
|
|
|
jmp main_loop |
|
|
|
|
|
|
|
|
|
|
|
; ================================================================ |
|
|
|
|
|
; COMMAND MODE |
|
|
|
|
|
; ================================================================ |
|
|
|
|
|
handle_cmd: |
|
|
|
|
|
lda last_key |
|
|
|
|
|
cmp #CR_CH |
|
|
|
|
|
beq cmd_exec |
|
|
|
|
|
cmp #DEL_CH |
|
|
|
|
|
beq cmd_bs |
|
|
|
|
|
cmp #$20 |
|
|
|
|
|
bcc cmd_done |
|
|
|
|
|
cmp #$7F |
|
|
|
|
|
bcs cmd_done |
|
|
|
|
|
ldx cmd_len |
|
|
|
|
|
cpx #CMD_MAX |
|
|
|
|
|
bcs cmd_done |
|
|
|
|
|
sta cmd_buf,x |
|
|
|
|
|
inc cmd_len |
|
|
|
|
|
jmp cmd_done |
|
|
|
|
|
cmd_bs: |
|
|
|
|
|
lda cmd_len |
|
|
|
|
|
beq cmd_done |
|
|
|
|
|
dec cmd_len |
|
|
|
|
|
jmp cmd_done |
|
|
|
|
|
cmd_exec: |
|
|
|
|
|
jsr run_cmd |
|
|
|
|
|
cmd_done: |
|
|
|
|
|
jsr full_redraw |
|
|
|
|
|
jmp main_loop |
|
|
|
|
|
|
|
|
|
|
|
; ================================================================ |
|
|
|
|
|
; EXIT |
|
|
|
|
|
; ================================================================ |
|
|
|
|
|
vim_do_exit: |
|
|
|
|
|
jsr restore_cursor ; de-invert cursor char before leaving |
|
|
|
|
|
rts ; return to kernal-os-skeleton shell |
|
|
|
|
|
|
|
|
|
|
|
; ================================================================ |
|
|
|
|
|
; COMMAND EXECUTION |
|
|
|
|
|
; ================================================================ |
|
|
|
|
|
run_cmd: |
|
|
|
|
|
lda cmd_len |
|
|
|
|
|
beq rc_cancel |
|
|
|
|
|
|
|
|
|
|
|
; --- :Q quit --- |
|
|
|
|
|
cmp #1 |
|
|
|
|
|
bne rc_not_q |
|
|
|
|
|
lda cmd_buf |
|
|
|
|
|
cmp #'Q' |
|
|
|
|
|
bne rc_not_q |
|
|
|
|
|
lda #1 |
|
|
|
|
|
sta quit_flag |
|
|
|
|
|
lda #MODE_NORMAL |
|
|
|
|
|
sta cur_mode |
|
|
|
|
|
rts |
|
|
|
|
|
|
|
|
|
|
|
rc_not_q: |
|
|
|
|
|
; --- :W [NAME] save --- |
|
|
|
|
|
lda cmd_buf |
|
|
|
|
|
cmp #'W' |
|
|
|
|
|
bne rc_unknown |
|
|
|
|
|
jsr do_save |
|
|
|
|
|
lda #MODE_NORMAL |
|
|
|
|
|
sta cur_mode |
|
|
|
|
|
rts |
|
|
|
|
|
|
|
|
|
|
|
rc_unknown: |
|
|
|
|
|
; show "?" in status then return to normal |
|
|
|
|
|
lda #<msg_cmd_err |
|
|
|
|
|
ldy #>msg_cmd_err |
|
|
|
|
|
jsr show_status_text |
|
|
|
|
|
rc_cancel: |
|
|
|
|
|
lda #MODE_NORMAL |
|
|
|
|
|
sta cur_mode |
|
|
|
|
|
rts |
|
|
|
|
|
|
|
|
|
|
|
; ================================================================ |
|
|
|
|
|
; FILE SAVE |
|
|
|
|
|
; do_save: reads cmd_buf "W NAME" and writes text to disk |
|
|
|
|
|
; ================================================================ |
|
|
|
|
|
do_save: |
|
|
|
|
|
; need at least "W N" (3 chars: W, space, one char of name) |
|
|
|
|
|
lda cmd_len |
|
|
|
|
|
cmp #3 |
|
|
|
|
|
bcs ds_len_ok |
|
|
|
|
|
jmp ds_no_name |
|
|
|
|
|
ds_len_ok: |
|
|
|
|
|
lda cmd_buf + 1 |
|
|
|
|
|
cmp #' ' |
|
|
|
|
|
beq ds_space_ok |
|
|
|
|
|
jmp ds_no_name |
|
|
|
|
|
ds_space_ok: |
|
|
|
|
|
|
|
|
|
|
|
; copy filename from cmd_buf[2..] to save_fn |
|
|
|
|
|
ldy #2 |
|
|
|
|
|
ldx #0 |
|
|
|
|
|
ds_copy_name: |
|
|
|
|
|
lda cmd_buf,y |
|
|
|
|
|
beq ds_name_done |
|
|
|
|
|
cmp #' ' |
|
|
|
|
|
beq ds_name_done |
|
|
|
|
|
sta save_fn,x |
|
|
|
|
|
inx |
|
|
|
|
|
iny |
|
|
|
|
|
cpx #15 |
|
|
|
|
|
bcc ds_copy_name |
|
|
|
|
|
ds_name_done: |
|
|
|
|
|
stx save_fn_len |
|
|
|
|
|
lda #0 |
|
|
|
|
|
sta save_fn,x |
|
|
|
|
|
|
|
|
|
|
|
; build "0:NAME,S,W" in full_fn |
|
|
|
|
|
jsr build_save_fname |
|
|
|
|
|
|
|
|
|
|
|
; SETLFS |
|
|
|
|
|
lda #SAVE_LFN |
|
|
|
|
|
ldx #SAVE_DEV |
|
|
|
|
|
ldy #2 |
|
|
|
|
|
jsr SETLFS |
|
|
|
|
|
|
|
|
|
|
|
; SETNAM |
|
|
|
|
|
lda full_fn_len |
|
|
|
|
|
ldx #<full_fn |
|
|
|
|
|
ldy #>full_fn |
|
|
|
|
|
jsr SETNAM |
|
|
|
|
|
|
|
|
|
|
|
jsr OPEN |
|
|
|
|
|
bcc ds_open_ok |
|
|
|
|
|
; open error |
|
|
|
|
|
lda #<msg_disk_err |
|
|
|
|
|
ldy #>msg_disk_err |
|
|
|
|
|
jsr show_status_text |
|
|
|
|
|
rts |
|
|
|
|
|
|
|
|
|
|
|
ds_open_ok: |
|
|
|
|
|
lda #SAVE_LFN |
|
|
|
|
|
jsr CHKOUT |
|
|
|
|
|
bcc ds_write_rows |
|
|
|
|
|
jsr CLRCH |
|
|
|
|
|
lda #SAVE_LFN |
|
|
|
|
|
jsr CLOSE |
|
|
|
|
|
lda #<msg_disk_err |
|
|
|
|
|
ldy #>msg_disk_err |
|
|
|
|
|
jsr show_status_text |
|
|
|
|
|
rts |
|
|
|
|
|
|
|
|
|
|
|
ds_write_rows: |
|
|
|
|
|
lda #0 |
|
|
|
|
|
sta save_row |
|
|
|
|
|
|
|
|
|
|
|
ds_row_loop: |
|
|
|
|
|
ldx save_row |
|
|
|
|
|
lda row_lo,x |
|
|
|
|
|
sta ZP_LO |
|
|
|
|
|
lda row_hi,x |
|
|
|
|
|
sta ZP_HI |
|
|
|
|
|
|
|
|
|
|
|
; find rightmost non-space column |
|
|
|
|
|
ldy #SCR_COLS - 1 |
|
|
|
|
|
ds_find_end: |
|
|
|
|
|
lda (ZP_LO),y |
|
|
|
|
|
cmp #$20 |
|
|
|
|
|
bne ds_row_found |
|
|
|
|
|
tya |
|
|
|
|
|
beq ds_row_empty |
|
|
|
|
|
dey |
|
|
|
|
|
jmp ds_find_end |
|
|
|
|
|
|
|
|
|
|
|
ds_row_empty: |
|
|
|
|
|
; empty row: just write CR |
|
|
|
|
|
lda #CR_CH |
|
|
|
|
|
jsr CHROUT |
|
|
|
|
|
jmp ds_row_done |
|
|
|
|
|
|
|
|
|
|
|
ds_row_found: |
|
|
|
|
|
; write cols 0..Y then CR |
|
|
|
|
|
sty save_col_end |
|
|
|
|
|
ldy #0 |
|
|
|
|
|
ds_write_col: |
|
|
|
|
|
lda (ZP_LO),y |
|
|
|
|
|
jsr screen_to_petscii |
|
|
|
|
|
jsr CHROUT |
|
|
|
|
|
cpy save_col_end |
|
|
|
|
|
beq ds_write_cr |
|
|
|
|
|
iny |
|
|
|
|
|
jmp ds_write_col |
|
|
|
|
|
|
|
|
|
|
|
ds_write_cr: |
|
|
|
|
|
lda #CR_CH |
|
|
|
|
|
jsr CHROUT |
|
|
|
|
|
|
|
|
|
|
|
ds_row_done: |
|
|
|
|
|
inc save_row |
|
|
|
|
|
lda save_row |
|
|
|
|
|
cmp #SCR_ROWS |
|
|
|
|
|
bne ds_row_loop |
|
|
|
|
|
|
|
|
|
|
|
; close |
|
|
|
|
|
jsr CLRCH |
|
|
|
|
|
lda #SAVE_LFN |
|
|
|
|
|
jsr CLOSE |
|
|
|
|
|
|
|
|
|
|
|
lda #<msg_saved |
|
|
|
|
|
ldy #>msg_saved |
|
|
|
|
|
jsr show_status_text |
|
|
|
|
|
rts |
|
|
|
|
|
|
|
|
|
|
|
ds_no_name: |
|
|
|
|
|
lda #<msg_need_name |
|
|
|
|
|
ldy #>msg_need_name |
|
|
|
|
|
jsr show_status_text |
|
|
|
|
|
rts |
|
|
|
|
|
|
|
|
|
|
|
; builds "0:save_fn,S,W" into full_fn, length into full_fn_len |
|
|
|
|
|
build_save_fname: |
|
|
|
|
|
ldx #0 |
|
|
|
|
|
lda #'0' |
|
|
|
|
|
sta full_fn,x |
|
|
|
|
|
inx |
|
|
|
|
|
lda #':' |
|
|
|
|
|
sta full_fn,x |
|
|
|
|
|
inx |
|
|
|
|
|
ldy #0 |
|
|
|
|
|
bsf_loop: |
|
|
|
|
|
lda save_fn,y |
|
|
|
|
|
beq bsf_suffix |
|
|
|
|
|
sta full_fn,x |
|
|
|
|
|
inx |
|
|
|
|
|
iny |
|
|
|
|
|
bne bsf_loop |
|
|
|
|
|
bsf_suffix: |
|
|
|
|
|
lda #',' |
|
|
|
|
|
sta full_fn,x |
|
|
|
|
|
inx |
|
|
|
|
|
lda #'S' |
|
|
|
|
|
sta full_fn,x |
|
|
|
|
|
inx |
|
|
|
|
|
lda #',' |
|
|
|
|
|
sta full_fn,x |
|
|
|
|
|
inx |
|
|
|
|
|
lda #'W' |
|
|
|
|
|
sta full_fn,x |
|
|
|
|
|
inx |
|
|
|
|
|
stx full_fn_len |
|
|
|
|
|
lda #0 |
|
|
|
|
|
sta full_fn,x |
|
|
|
|
|
rts |
|
|
|
|
|
|
|
|
|
|
|
; ================================================================ |
|
|
|
|
|
; CURSOR MOVEMENT |
|
|
|
|
|
; ================================================================ |
|
|
|
|
|
cursor_left: |
|
|
|
|
|
lda cur_col |
|
|
|
|
|
beq cl_wrap |
|
|
|
|
|
dec cur_col |
|
|
|
|
|
rts |
|
|
|
|
|
cl_wrap: |
|
|
|
|
|
lda cur_row |
|
|
|
|
|
beq cl_top |
|
|
|
|
|
dec cur_row |
|
|
|
|
|
lda #SCR_COLS - 1 |
|
|
|
|
|
sta cur_col |
|
|
|
|
|
cl_top: rts |
|
|
|
|
|
|
|
|
|
|
|
cursor_right: |
|
|
|
|
|
lda cur_col |
|
|
|
|
|
cmp #SCR_COLS - 1 |
|
|
|
|
|
bcs cr_wrap |
|
|
|
|
|
inc cur_col |
|
|
|
|
|
rts |
|
|
|
|
|
cr_wrap: |
|
|
|
|
|
lda cur_row |
|
|
|
|
|
cmp #SCR_ROWS - 1 |
|
|
|
|
|
bcs cr_bot |
|
|
|
|
|
inc cur_row |
|
|
|
|
|
lda #0 |
|
|
|
|
|
sta cur_col |
|
|
|
|
|
cr_bot: rts |
|
|
|
|
|
|
|
|
|
|
|
cursor_up: |
|
|
|
|
|
lda cur_row |
|
|
|
|
|
beq cu_top |
|
|
|
|
|
dec cur_row |
|
|
|
|
|
cu_top: rts |
|
|
|
|
|
|
|
|
|
|
|
cursor_down: |
|
|
|
|
|
lda cur_row |
|
|
|
|
|
cmp #SCR_ROWS - 1 |
|
|
|
|
|
bcs cd_bot |
|
|
|
|
|
inc cur_row |
|
|
|
|
|
cd_bot: rts |
|
|
|
|
|
|
|
|
|
|
|
; ================================================================ |
|
|
|
|
|
; TEXT EDITING |
|
|
|
|
|
; ================================================================ |
|
|
|
|
|
|
|
|
|
|
|
; Set ZP_LO/ZP_HI to the screen RAM base for cur_row |
|
|
|
|
|
row_ptr: |
|
|
|
|
|
ldx cur_row |
|
|
|
|
|
lda row_lo,x |
|
|
|
|
|
sta ZP_LO |
|
|
|
|
|
lda row_hi,x |
|
|
|
|
|
sta ZP_HI |
|
|
|
|
|
rts |
|
|
|
|
|
|
|
|
|
|
|
; Insert PETSCII char (in A) at cursor; shift rest of line right (last char lost) |
|
|
|
|
|
insert_char: |
|
|
|
|
|
jsr petscii_to_screen |
|
|
|
|
|
sta ZP_TMP |
|
|
|
|
|
jsr row_ptr |
|
|
|
|
|
ldy #SCR_COLS - 1 |
|
|
|
|
|
ic_shift: |
|
|
|
|
|
cpy cur_col |
|
|
|
|
|
beq ic_write |
|
|
|
|
|
dey |
|
|
|
|
|
lda (ZP_LO),y |
|
|
|
|
|
iny |
|
|
|
|
|
sta (ZP_LO),y |
|
|
|
|
|
dey |
|
|
|
|
|
jmp ic_shift |
|
|
|
|
|
ic_write: |
|
|
|
|
|
lda ZP_TMP |
|
|
|
|
|
ldy cur_col |
|
|
|
|
|
sta (ZP_LO),y |
|
|
|
|
|
rts |
|
|
|
|
|
|
|
|
|
|
|
; Delete char at cursor; shift rest of line left, fill end with space |
|
|
|
|
|
delete_char: |
|
|
|
|
|
jsr row_ptr |
|
|
|
|
|
ldy cur_col |
|
|
|
|
|
dc_shift: |
|
|
|
|
|
cpy #SCR_COLS - 1 |
|
|
|
|
|
beq dc_space |
|
|
|
|
|
iny |
|
|
|
|
|
lda (ZP_LO),y |
|
|
|
|
|
dey |
|
|
|
|
|
sta (ZP_LO),y |
|
|
|
|
|
iny |
|
|
|
|
|
jmp dc_shift |
|
|
|
|
|
dc_space: |
|
|
|
|
|
lda #$20 |
|
|
|
|
|
sta (ZP_LO),y |
|
|
|
|
|
rts |
|
|
|
|
|
|
|
|
|
|
|
; Backspace: move cursor left then delete |
|
|
|
|
|
backspace_char: |
|
|
|
|
|
lda cur_col |
|
|
|
|
|
beq bs_done |
|
|
|
|
|
jsr cursor_left |
|
|
|
|
|
jsr delete_char |
|
|
|
|
|
bs_done:rts |
|
|
|
|
|
|
|
|
|
|
|
; RETURN in insert mode: move to col 0 of next row |
|
|
|
|
|
do_newline: |
|
|
|
|
|
lda cur_row |
|
|
|
|
|
cmp #SCR_ROWS - 1 |
|
|
|
|
|
bcs nl_done |
|
|
|
|
|
inc cur_row |
|
|
|
|
|
lda #0 |
|
|
|
|
|
sta cur_col |
|
|
|
|
|
nl_done:rts |
|
|
|
|
|
|
|
|
|
|
|
; Open new line below: advance row, clear it, col = 0 |
|
|
|
|
|
open_line_below: |
|
|
|
|
|
lda cur_row |
|
|
|
|
|
cmp #SCR_ROWS - 1 |
|
|
|
|
|
bcs ol_done |
|
|
|
|
|
inc cur_row |
|
|
|
|
|
lda #0 |
|
|
|
|
|
sta cur_col |
|
|
|
|
|
jsr clear_current_row |
|
|
|
|
|
ol_done:rts |
|
|
|
|
|
|
|
|
|
|
|
clear_current_row: |
|
|
|
|
|
jsr row_ptr |
|
|
|
|
|
ldy #0 |
|
|
|
|
|
lda #$20 |
|
|
|
|
|
ccr_lp: sta (ZP_LO),y |
|
|
|
|
|
iny |
|
|
|
|
|
cpy #SCR_COLS |
|
|
|
|
|
bne ccr_lp |
|
|
|
|
|
rts |
|
|
|
|
|
|
|
|
|
|
|
; Clear all 24 text rows to spaces |
|
|
|
|
|
clear_text: |
|
|
|
|
|
lda #0 |
|
|
|
|
|
sta ZP_TMP |
|
|
|
|
|
ct_loop: |
|
|
|
|
|
ldx ZP_TMP |
|
|
|
|
|
lda row_lo,x |
|
|
|
|
|
sta ZP_LO |
|
|
|
|
|
lda row_hi,x |
|
|
|
|
|
sta ZP_HI |
|
|
|
|
|
ldy #0 |
|
|
|
|
|
lda #$20 |
|
|
|
|
|
ct_row: sta (ZP_LO),y |
|
|
|
|
|
iny |
|
|
|
|
|
cpy #SCR_COLS |
|
|
|
|
|
bne ct_row |
|
|
|
|
|
inc ZP_TMP |
|
|
|
|
|
lda ZP_TMP |
|
|
|
|
|
cmp #SCR_ROWS |
|
|
|
|
|
bne ct_loop |
|
|
|
|
|
rts |
|
|
|
|
|
|
|
|
|
|
|
; ================================================================ |
|
|
|
|
|
; SCREEN RENDERING |
|
|
|
|
|
; ================================================================ |
|
|
|
|
|
|
|
|
|
|
|
; Restore the saved char at (prev_row, prev_col) |
|
|
|
|
|
restore_cursor: |
|
|
|
|
|
ldx prev_row |
|
|
|
|
|
lda row_lo,x |
|
|
|
|
|
clc |
|
|
|
|
|
adc prev_col |
|
|
|
|
|
sta ZP_LO |
|
|
|
|
|
lda row_hi,x |
|
|
|
|
|
adc #0 |
|
|
|
|
|
sta ZP_HI |
|
|
|
|
|
lda prev_char |
|
|
|
|
|
ldy #0 |
|
|
|
|
|
sta (ZP_LO),y |
|
|
|
|
|
rts |
|
|
|
|
|
|
|
|
|
|
|
; Show cursor by inverting char at (cur_row, cur_col); saves old char |
|
|
|
|
|
show_cursor: |
|
|
|
|
|
ldx cur_row |
|
|
|
|
|
lda row_lo,x |
|
|
|
|
|
clc |
|
|
|
|
|
adc cur_col |
|
|
|
|
|
sta ZP_LO |
|
|
|
|
|
lda row_hi,x |
|
|
|
|
|
adc #0 |
|
|
|
|
|
sta ZP_HI |
|
|
|
|
|
ldy #0 |
|
|
|
|
|
lda (ZP_LO),y |
|
|
|
|
|
sta prev_char |
|
|
|
|
|
ora #$80 ; set bit 7 = reversed character |
|
|
|
|
|
sta (ZP_LO),y |
|
|
|
|
|
lda cur_row |
|
|
|
|
|
sta prev_row |
|
|
|
|
|
lda cur_col |
|
|
|
|
|
sta prev_col |
|
|
|
|
|
rts |
|
|
|
|
|
|
|
|
|
|
|
; Draw status bar at row 24 |
|
|
|
|
|
draw_status: |
|
|
|
|
|
; clear status row |
|
|
|
|
|
lda row_lo + 24 |
|
|
|
|
|
sta ZP_LO |
|
|
|
|
|
lda row_hi + 24 |
|
|
|
|
|
sta ZP_HI |
|
|
|
|
|
ldy #0 |
|
|
|
|
|
lda #$20 |
|
|
|
|
|
dstat_clr: |
|
|
|
|
|
sta (ZP_LO),y |
|
|
|
|
|
iny |
|
|
|
|
|
cpy #SCR_COLS |
|
|
|
|
|
bne dstat_clr |
|
|
|
|
|
|
|
|
|
|
|
lda cur_mode |
|
|
|
|
|
cmp #MODE_INSERT |
|
|
|
|
|
beq dstat_ins |
|
|
|
|
|
cmp #MODE_CMD |
|
|
|
|
|
beq dstat_cmd |
|
|
|
|
|
|
|
|
|
|
|
; NORMAL |
|
|
|
|
|
lda #<str_normal |
|
|
|
|
|
ldy #>str_normal |
|
|
|
|
|
jsr write_str_to_status |
|
|
|
|
|
rts |
|
|
|
|
|
|
|
|
|
|
|
dstat_ins: |
|
|
|
|
|
lda #<str_insert |
|
|
|
|
|
ldy #>str_insert |
|
|
|
|
|
jsr write_str_to_status |
|
|
|
|
|
rts |
|
|
|
|
|
|
|
|
|
|
|
dstat_cmd: |
|
|
|
|
|
; write ":" then cmd_buf |
|
|
|
|
|
lda row_lo + 24 |
|
|
|
|
|
sta ZP_LO |
|
|
|
|
|
lda row_hi + 24 |
|
|
|
|
|
sta ZP_HI |
|
|
|
|
|
lda #$3A ; screen code for ':' |
|
|
|
|
|
ldy #0 |
|
|
|
|
|
sta (ZP_LO),y |
|
|
|
|
|
iny |
|
|
|
|
|
ldx #0 |
|
|
|
|
|
dstat_cmd_lp: |
|
|
|
|
|
cpx cmd_len |
|
|
|
|
|
beq dstat_done |
|
|
|
|
|
lda cmd_buf,x |
|
|
|
|
|
jsr petscii_to_screen |
|
|
|
|
|
sta (ZP_LO),y |
|
|
|
|
|
iny |
|
|
|
|
|
inx |
|
|
|
|
|
cpy #SCR_COLS |
|
|
|
|
|
bcc dstat_cmd_lp |
|
|
|
|
|
dstat_done: |
|
|
|
|
|
rts |
|
|
|
|
|
|
|
|
|
|
|
; Write null-terminated PETSCII string (A=lo, Y=hi) to status row |
|
|
|
|
|
write_str_to_status: |
|
|
|
|
|
sta STR_LO |
|
|
|
|
|
sty STR_HI |
|
|
|
|
|
lda row_lo + 24 |
|
|
|
|
|
sta ZP_LO |
|
|
|
|
|
lda row_hi + 24 |
|
|
|
|
|
sta ZP_HI |
|
|
|
|
|
ldy #0 |
|
|
|
|
|
wss_lp: |
|
|
|
|
|
lda (STR_LO),y |
|
|
|
|
|
beq wss_done |
|
|
|
|
|
jsr petscii_to_screen |
|
|
|
|
|
sta (ZP_LO),y |
|
|
|
|
|
iny |
|
|
|
|
|
cpy #SCR_COLS |
|
|
|
|
|
bcc wss_lp |
|
|
|
|
|
wss_done: |
|
|
|
|
|
rts |
|
|
|
|
|
|
|
|
|
|
|
; Copy a PETSCII string directly to status (no screen-code conversion) |
|
|
|
|
|
; Used for messages that already have screen codes (msg_saved etc.) |
|
|
|
|
|
; Actually we just reuse write_str_to_status since it converts |
|
|
|
|
|
show_status_text: |
|
|
|
|
|
jsr write_str_to_status |
|
|
|
|
|
rts |
|
|
|
|
|
|
|
|
|
|
|
; Restore cursor, redraw cursor, redraw status bar |
|
|
|
|
|
full_redraw: |
|
|
|
|
|
jsr restore_cursor |
|
|
|
|
|
jsr show_cursor |
|
|
|
|
|
jsr draw_status |
|
|
|
|
|
rts |
|
|
|
|
|
|
|
|
|
|
|
; ================================================================ |
|
|
|
|
|
; INIT |
|
|
|
|
|
; ================================================================ |
|
|
|
|
|
vim_init: |
|
|
|
|
|
lda #0 |
|
|
|
|
|
sta cur_row |
|
|
|
|
|
sta cur_col |
|
|
|
|
|
sta prev_row |
|
|
|
|
|
sta prev_col |
|
|
|
|
|
sta cur_mode |
|
|
|
|
|
sta cmd_len |
|
|
|
|
|
sta quit_flag |
|
|
|
|
|
sta save_row |
|
|
|
|
|
sta save_col_end |
|
|
|
|
|
lda #$20 ; cursor starts on a space |
|
|
|
|
|
sta prev_char |
|
|
|
|
|
jsr clear_text |
|
|
|
|
|
rts |
|
|
|
|
|
|
|
|
|
|
|
; ================================================================ |
|
|
|
|
|
; KEY INPUT |
|
|
|
|
|
; ================================================================ |
|
|
|
|
|
get_key: |
|
|
|
|
|
gk_loop: |
|
|
|
|
|
jsr STOPKEY |
|
|
|
|
|
bne gk_getin |
|
|
|
|
|
lda #$FF ; RUN/STOP = special exit code |
|
|
|
|
|
rts |
|
|
|
|
|
gk_getin: |
|
|
|
|
|
jsr GETIN |
|
|
|
|
|
beq gk_loop ; no key yet, keep polling |
|
|
|
|
|
rts |
|
|
|
|
|
|
|
|
|
|
|
; ================================================================ |
|
|
|
|
|
; CHARACTER CONVERSION |
|
|
|
|
|
; ================================================================ |
|
|
|
|
|
|
|
|
|
|
|
; PETSCII → screen code |
|
|
|
|
|
; $41-$5A (A-Z unshifted) → $01-$1A (subtract $40) |
|
|
|
|
|
; $61-$7A (a-z lowercase) → $01-$1A (subtract $60) |
|
|
|
|
|
; $20-$3F (space,nums,punct) → same |
|
|
|
|
|
; others: pass through |
|
|
|
|
|
petscii_to_screen: |
|
|
|
|
|
cmp #$41 |
|
|
|
|
|
bcc pts_pass |
|
|
|
|
|
cmp #$5B |
|
|
|
|
|
bcc pts_upper |
|
|
|
|
|
cmp #$61 |
|
|
|
|
|
bcc pts_pass |
|
|
|
|
|
cmp #$7B |
|
|
|
|
|
bcc pts_lower |
|
|
|
|
|
pts_pass: |
|
|
|
|
|
rts |
|
|
|
|
|
pts_upper: |
|
|
|
|
|
sec |
|
|
|
|
|
sbc #$40 |
|
|
|
|
|
rts |
|
|
|
|
|
pts_lower: |
|
|
|
|
|
sec |
|
|
|
|
|
sbc #$60 |
|
|
|
|
|
rts |
|
|
|
|
|
|
|
|
|
|
|
; screen code → PETSCII (inverse of above) |
|
|
|
|
|
; $01-$1A → $41-$5A (add $40) |
|
|
|
|
|
; $20-$3F → same |
|
|
|
|
|
; $00 → '@' |
|
|
|
|
|
; others: return space $20 |
|
|
|
|
|
screen_to_petscii: |
|
|
|
|
|
cmp #$01 |
|
|
|
|
|
bcc stp_at |
|
|
|
|
|
cmp #$1B |
|
|
|
|
|
bcc stp_letter |
|
|
|
|
|
cmp #$20 |
|
|
|
|
|
bcc stp_space |
|
|
|
|
|
cmp #$40 |
|
|
|
|
|
bcc stp_pass |
|
|
|
|
|
stp_space: |
|
|
|
|
|
lda #$20 |
|
|
|
|
|
rts |
|
|
|
|
|
stp_at: |
|
|
|
|
|
lda #$40 ; '@' |
|
|
|
|
|
rts |
|
|
|
|
|
stp_letter: |
|
|
|
|
|
clc |
|
|
|
|
|
adc #$40 |
|
|
|
|
|
rts |
|
|
|
|
|
stp_pass: |
|
|
|
|
|
rts |
|
|
|
|
|
|
|
|
|
|
|
; ================================================================ |
|
|
|
|
|
; RODATA |
|
|
|
|
|
; ================================================================ |
|
|
|
|
|
.segment "RODATA" |
|
|
|
|
|
|
|
|
|
|
|
str_normal: |
|
|
|
|
|
.byte "NORMAL (hjkl=move i=ins x=del :=cmd)", 0 |
|
|
|
|
|
|
|
|
|
|
|
str_insert: |
|
|
|
|
|
.byte "INSERT (type text, DEL=bksp, STOP=normal)", 0 |
|
|
|
|
|
|
|
|
|
|
|
msg_cmd_err: |
|
|
|
|
|
.byte "? unknown command", 0 |
|
|
|
|
|
|
|
|
|
|
|
msg_saved: |
|
|
|
|
|
.byte "saved.", 0 |
|
|
|
|
|
|
|
|
|
|
|
msg_disk_err: |
|
|
|
|
|
.byte "disk error.", 0 |
|
|
|
|
|
|
|
|
|
|
|
msg_need_name: |
|
|
|
|
|
.byte "usage: :w filename", 0 |
|
|
|
|
|
|
|
|
|
|
|
; Row-base lookup tables (25 entries: rows 0-23 = text, row 24 = status) |
|
|
|
|
|
row_lo: |
|
|
|
|
|
.byte <(SCRRAM + 0*40), <(SCRRAM + 1*40), <(SCRRAM + 2*40) |
|
|
|
|
|
.byte <(SCRRAM + 3*40), <(SCRRAM + 4*40), <(SCRRAM + 5*40) |
|
|
|
|
|
.byte <(SCRRAM + 6*40), <(SCRRAM + 7*40), <(SCRRAM + 8*40) |
|
|
|
|
|
.byte <(SCRRAM + 9*40), <(SCRRAM + 10*40), <(SCRRAM + 11*40) |
|
|
|
|
|
.byte <(SCRRAM + 12*40), <(SCRRAM + 13*40), <(SCRRAM + 14*40) |
|
|
|
|
|
.byte <(SCRRAM + 15*40), <(SCRRAM + 16*40), <(SCRRAM + 17*40) |
|
|
|
|
|
.byte <(SCRRAM + 18*40), <(SCRRAM + 19*40), <(SCRRAM + 20*40) |
|
|
|
|
|
.byte <(SCRRAM + 21*40), <(SCRRAM + 22*40), <(SCRRAM + 23*40) |
|
|
|
|
|
.byte <(SCRRAM + 24*40) |
|
|
|
|
|
|
|
|
|
|
|
row_hi: |
|
|
|
|
|
.byte >(SCRRAM + 0*40), >(SCRRAM + 1*40), >(SCRRAM + 2*40) |
|
|
|
|
|
.byte >(SCRRAM + 3*40), >(SCRRAM + 4*40), >(SCRRAM + 5*40) |
|
|
|
|
|
.byte >(SCRRAM + 6*40), >(SCRRAM + 7*40), >(SCRRAM + 8*40) |
|
|
|
|
|
.byte >(SCRRAM + 9*40), >(SCRRAM + 10*40), >(SCRRAM + 11*40) |
|
|
|
|
|
.byte >(SCRRAM + 12*40), >(SCRRAM + 13*40), >(SCRRAM + 14*40) |
|
|
|
|
|
.byte >(SCRRAM + 15*40), >(SCRRAM + 16*40), >(SCRRAM + 17*40) |
|
|
|
|
|
.byte >(SCRRAM + 18*40), >(SCRRAM + 19*40), >(SCRRAM + 20*40) |
|
|
|
|
|
.byte >(SCRRAM + 21*40), >(SCRRAM + 22*40), >(SCRRAM + 23*40) |
|
|
|
|
|
.byte >(SCRRAM + 24*40) |
|
|
|
|
|
|
|
|
|
|
|
; ================================================================ |
|
|
|
|
|
; BSS (zero-initialised by the OS / KERNAL CINT on cold start; |
|
|
|
|
|
; vim_init zeros what it cares about explicitly) |
|
|
|
|
|
; ================================================================ |
|
|
|
|
|
.segment "BSS" |
|
|
|
|
|
|
|
|
|
|
|
cur_row: .res 1 |
|
|
|
|
|
cur_col: .res 1 |
|
|
|
|
|
prev_row: .res 1 |
|
|
|
|
|
prev_col: .res 1 |
|
|
|
|
|
prev_char: .res 1 ; screen code saved before cursor inversion |
|
|
|
|
|
cur_mode: .res 1 |
|
|
|
|
|
cmd_len: .res 1 |
|
|
|
|
|
cmd_buf: .res CMD_MAX + 1 |
|
|
|
|
|
last_key: .res 1 |
|
|
|
|
|
quit_flag: .res 1 |
|
|
|
|
|
save_row: .res 1 |
|
|
|
|
|
save_col_end: .res 1 |
|
|
|
|
|
save_fn: .res 16 ; extracted filename (no path) |
|
|
|
|
|
save_fn_len: .res 1 |
|
|
|
|
|
full_fn: .res 24 ; "0:filename,S,W" |
|
|
|
|
|
full_fn_len: .res 1 |