gregg@a.cs.okstate.edu@mandrill.CWRU.Edu (Gregg Wonderly) (10/13/87)
$ WRITE SYS$OUTPUT "Creating ""VI.9""" $ CREATE VI.9 $ DECK/DOLLARS=$$EOD$$ vi$active_count := 0; ENDPROCEDURE; ! ! Move to line in file. vi$active_count holds the line number to GO TO. ! If VI$ACTIVE_COUNT is zero, we move to the end of the file. ! PROCEDURE vi$to_line (cnt) LOCAL this_pos, ! Saved position in case of botch last_line, ! Last line in the buffer win_len; ! Length of CURRENT_WINDOW ON_ERROR vi$message (FAO ("No such line: !SL", VI$ACTIVE_COUNT)); POSITION (this_pos); cnt := 0; RETURN; ENDON_ERROR; this_pos := MARK(NONE); MOVE_HORIZONTAL (-CURRENT_OFFSET); vi$start_pos := MARK (NONE); IF cnt = 0 THEN POSITION (END_OF (CURRENT_BUFFER)); ELSE last_line := GET_INFO (CURRENT_BUFFER, "RECORD_COUNT"); IF cnt > last_line THEN IF last_line > 0 THEN vi$message ("Not that many lines in buffer"); POSITION (this_pos); RETURN (0); ENDIF; ELSE POSITION (BEGINNING_OF (CURRENT_BUFFER)); win_len := GET_INFO (CURRENT_WINDOW, "VISIBLE_LENGTH"); MOVE_VERTICAL (cnt - 1); cnt := 0; ENDIF; ENDIF; IF (MARK (NONE) <> END_OF (CURRENT_BUFFER)) THEN MOVE_VERTICAL (1); MOVE_HORIZONTAL (-1); vi$new_endpos := MARK (NONE); MOVE_HORIZONTAL (-CURRENT_OFFSET); ENDIF; vi$yank_mode := VI$LINE_MODE; RETURN (vi$retpos (this_pos)); ENDPROCEDURE; ! ! Set a marker in the current buffer. ! PROCEDURE vi$_set_mark LOCAL mark_char, mark_name, key_pressed; key_pressed := vi$read_a_key; mark_char := ASCII (key_pressed); IF (INDEX (vi$_lower_chars, mark_char) <> 0) THEN mark_name := "vi$mark_" + mark_char; EXECUTE (COMPILE (mark_name + " := MARK(NONE);")); ELSE vi$MESSAGE ("Invalid marker key!"); ENDIF; ENDPROCEDURE; ! ! Function mapped to "'" and "`". ! PROCEDURE vi$_go_to_marker IF (vi$position (vi$to_marker, 1) <> 0) THEN vi$pos_in_middle (MARK (NONE)); ENDIF; ENDPROCEDURE; ! ! Function to move the marker indicated by the next keystroke. ! PROCEDURE vi$to_marker LOCAL mode_key, pos, mark_name, mark_char, key_pressed; ON_ERROR; vi$message ("Mark not set!"); RETURN (0); ENDON_ERROR; pos := MARK (NONE); mode_key := vi$last_key; key_pressed := vi$read_a_key; mark_char := ASCII (key_pressed); IF (INDEX (vi$_lower_chars+"'`", mark_char) = 0) THEN vi$MESSAGE ("Invalid marker key!"); RETURN (0); ENDIF; IF (key_pressed <> F11) THEN IF (mark_char = "'") OR (mark_char = "`") THEN IF (vi$old_place <> 0) THEN IF (GET_INFO (vi$old_place, "BUFFER") = CURRENT_BUFFER) THEN POSITION (vi$old_place); ELSE MESSAGE ("Previous place not in this buffer!"); RETURN (0); ENDIF; ELSE MESSAGE ("No previous mark to return to!"); RETURN (0); ENDIF; ELSE mark_name := "vi$mark_" + mark_char; EXECUTE (COMPILE ("vi$global_mark := "+mark_name+";")); IF (vi$global_mark <> 0) AND (GET_INFO (vi$global_mark, "BUFFER") = CURRENT_BUFFER) THE N POSITION (vi$global_mark); vi$yank_mode := VI$LINE_MODE; ELSE vi$message ("Invalid mark for this buffer!"); RETURN (0); ENDIF; ENDIF; IF ASCII (mode_key) = "'" THEN MOVE_HORIZONTAL (-CURRENT_OFFSET); POSITION (vi$first_no_space); ENDIF; IF (MARK (NONE) <> END_OF (CURRENT_BUFFER)) THEN MOVE_VERTICAL (1); vi$new_endpos := MARK (NONE); MOVE_VERTICAL (-1); ENDIF; RETURN (vi$retpos (pos)); ENDIF; POSITION (pos); RETURN (0); ENDPROCEDURE; ! ! Maintain the repeat count in vi$active_count. If VI$ACTIVE_COUNT is ZERO, ! and '0' is typed, this means move to beginning of the line. ! PROCEDURE vi$repeat_count IF VI$ACTIVE_COUNT = 0 THEN vi$active_count := INT (ASCII (KEY_NAME (vi$last_key))); IF vi$active_count = 0 THEN vi$position (vi$fol, 0); ENDIF; ELSE vi$active_count := vi$active_count * 10 + INT (ASCII (KEY_NAME (vi$last_key))); ENDIF; ENDPROCEDURE; ! ! The function mapped to <CR>. ! PROCEDURE vi$_next_line POSITION (vi$beg_next); ENDPROCEDURE; ! ! Move the cursor to the beginning of the next line ! PROCEDURE vi$beg_next LOCAL pos; ON_ERROR RETURN (MARK (NONE)); ENDON_ERROR; pos := MARK (NONE); MOVE_VERTICAL (vi$cur_active_count); MOVE_HORIZONTAL (-CURRENT_OFFSET); POSITION (vi$first_no_space); vi$yank_mode := VI$LINE_MODE; vi$new_offset := 1; RETURN (vi$retpos (pos)); ENDPROCEDURE; ! ! This function moves to the first non-blank character of a line ! PROCEDURE vi$first_no_space LOCAL pos, t_range; ON_ERROR ! Ignore string not found messages. ENDON_ERROR; pos := MARK (NONE); MOVE_HORIZONTAL (- CURRENT_OFFSET); IF (LENGTH (CURRENT_LINE) > 0) THEN IF t_range = 0 THEN t_range := SEARCH (ANCHOR & SPAN (vi$no_space) & NOTANY(vi$no_space), FORWARD); ENDIF; IF t_range <> 0 THEN POSITION (END_OF (t_range)); ELSE ! If that fails, then search for a blank line with extra white ! space, and move to the end of the white space. t_range := SEARCH (ANCHOR & SPAN (vi$no_space), FORWARD); IF t_range <> 0 THEN POSITION (END_OF (t_range)); ENDIF; ENDIF; ENDIF; vi$yank_mode := VI$IN_LINE_MODE; RETURN (vi$retpos (pos)); ENDPROCEDURE; ! ! Move by a section in the indicated direction ! PROCEDURE vi$_section (dir) LOCAL ch; ch := vi$read_a_key; IF ((ASCII(ch) = "]") AND (dir = 1)) OR ((ASCII(ch) = "[") AND (dir = -1)) THEN vi$position (vi$section (dir), 1); ELSE vi$beep; ENDIF; ENDPROCEDURE; ! ! Sound a bell. ! PROCEDURE vi$beep LOCAL pos; IF (vi$error_bells = 0) THEN RETURN; ENDIF; pos := CURRENT_WINDOW; SET (BELL, ALL, ON); MESSAGE (""); SET (BELL, ALL, OFF); SET (BELL, BROADCAST, ON); POSITION (pos); ENDPROCEDURE; ! ! Mapped to '}' and '{', moves by a paragraph in the indicated direction. ! PROCEDURE vi$_paragraph(dir) vi$position (vi$paragraph(dir), 1); ENDPROCEDURE; ! ! Mapped to ( moves backward a sentence ! PROCEDURE vi$_begin_sentence vi$position (vi$begin_sentence, 1); ENDPROCEDURE; ! ! Mapped to ) moves forward a sentence ! PROCEDURE vi$_end_sentence vi$position (vi$end_sentence, 1); ENDPROCEDURE; ! ! Move backward a sentence. ! PROCEDURE vi$begin_sentence LOCAL rng, spos, pos; ON_ERROR; ENDON_ERROR; pos := MARK (NONE); MOVE_HORIZONTAL (-1); LOOP; rng := SEARCH ( (("" | " " | " ") & ANY (vi$_upper_chars)), REVERSE, EXACT); EXITIF rng = 0; POSITION (BEGINNING_OF (rng)); IF INDEX (" ", CURRENT_CHARACTER) = 0 THEN MOVE_HORIZONTAL (-1); ENDIF; IF INDEX (" ", CURRENT_CHARACTER) <> 0 THEN IF (CURRENT_CHARACTER = " ") THEN MOVE_HORIZONTAL (-1); IF INDEX (" ", CURRENT_CHARACTER) <> 0 THEN MOVE_HORIZONTAL (-1); IF INDEX ("?.!", CURRENT_CHARACTER) <> 0 THEN MOVE_HORIZONTAL (3); RETURN (vi$retpos (pos)); ENDIF; ENDIF; ELSE MOVE_HORIZONTAL (1); RETURN (vi$retpos (pos)); ENDIF; ENDIF; POSITION (BEGINNING_OF (rng)); MOVE_HORIZONTAL (-1); ENDLOOP; RETURN (0); ENDPROCEDURE; ! ! Move to next paragraph ! PROCEDURE vi$paragraph (dir) RETURN (vi$para_sect (dir, vi$para_pat)); ENDPROCEDURE; ! ! Find next paragraph or section. ! PROCEDURE vi$para_sect (dir, pat) LOCAL loc, direct, pos; pos := MARK (NONE); IF (dir < 0) THEN direct := REVERSE; MOVE_VERTICAL (-1); ELSE direct := FORWARD; MOVE_VERTICAL (1); ENDIF; SET (TIMER, ON, "Searching..."); loc := SEARCH (pat, direct, NO_EXACT); SET (TIMER, OFF); IF (loc <> 0) THEN RETURN (BEGINNING_OF (loc)); ELSE SET (TIMER, ON, "Searching..."); loc := SEARCH (vi$next_blank, direct, NO_EXACT); SET (TIMER, OFF); IF (loc <> 0) THEN RETURN (BEGINNING_OF (loc)); ENDIF; ENDIF; POSITION (pos); RETURN (0); ENDPROCEDURE; ! ! Move to next section ! PROCEDURE vi$section (dir) RETURN (vi$para_sect (dir, vi$sect_pat)); ENDPROCEDURE; ! ! Move forward a sentence. ! PROCEDURE vi$end_sentence LOCAL rng, spos, pos; ON_ERROR; ENDON_ERROR; pos := MARK (NONE); MOVE_HORIZONTAL (1); LOOP; rng := SEARCH (ANY (vi$_upper_chars), FORWARD, EXACT); EXITIF rng = 0; POSITION (BEGINNING_OF (rng)); IF INDEX (" ", CURRENT_CHARACTER) = 0 THEN MOVE_HORIZONTAL (-1); ENDIF; IF INDEX (" ", CURRENT_CHARACTER) <> 0 THEN IF (CURRENT_CHARACTER = " ") THEN MOVE_HORIZONTAL (-1); IF INDEX (" ", CURRENT_CHARACTER) <> 0 THEN MOVE_HORIZONTAL (-1); IF INDEX ("?.!", CURRENT_CHARACTER) <> 0 THEN MOVE_HORIZONTAL (3); RETURN (vi$retpos (pos)); ENDIF; ENDIF; ELSE MOVE_HORIZONTAL (1); RETURN (vi$retpos (pos)); ENDIF; ENDIF; POSITION (BEGINNING_OF (rng)); MOVE_HORIZONTAL (1); ENDLOOP; RETURN (0); ENDPROCEDURE; ! ! This function returns the value in vi$active count. It takes into ! account that when vi$active_count is zero, it should really be ! one. ! PROCEDURE vi$cur_active_count LOCAL resp, old_cnt; old_cnt := vi$active_count; vi$active_count := 0; IF old_cnt <= 0 THEN old_cnt := 1; ENDIF; RETURN (old_cnt); ENDPROCEDURE; ! ! The function mapped to 'p'. ! PROCEDURE vi$put_after (dest_buf) LOCAL source, pos; source := vi$cur_text; IF (GET_INFO (dest_buf, "TYPE") = BUFFER) THEN source := dest_buf; ENDIF; IF (GET_INFO (source, "TYPE") = BUFFER) THEN pos := MARK (NONE); POSITION (BEGINNING_OF (source)); vi$yank_mode := INT (vi$current_line); POSITION (pos); ENDIF; IF (source = "") THEN RETURN; ENDIF; IF (vi$yank_mode = VI$LINE_MODE) THEN IF (MARK(NONE) <> END_OF (CURRENT_BUFFER)) THEN MOVE_VERTICAL (1); ENDIF; ELSE IF (LENGTH (CURRENT_LINE) > 0) THEN MOVE_HORIZONTAL (1); ENDIF; ENDIF; vi$put_here (VI$AFTER, source); ENDPROCEDURE; ! ! The function mapped to 'P'. ! PROCEDURE vi$put_here (here_or_below, dest_buf) LOCAL olen, source, pos; source := vi$cur_text; olen := GET_INFO (CURRENT_BUFFER, "RECORD_COUNT"); IF (GET_INFO (dest_buf, "TYPE") = BUFFER) THEN source := dest_buf; ENDIF; IF (GET_INFO (source, "TYPE") = BUFFER) THEN pos := MARK (NONE); POSITION (BEGINNING_OF (source)); IF (MARK (NONE) = END_OF (source)) THEN RETURN; ENDIF; vi$yank_mode := INT (vi$current_line); ERASE_LINE; POSITION (pos); ELSE IF (source = "") THEN RETURN; ENDIF; ENDIF; IF source = 0 THEN vi$message ("Bad buffer for put!"); RETURN; ENDIF; IF (vi$yank_mode = VI$LINE_MODE) THEN MOVE_HORIZONTAL (-CURRENT_OFFSET); ENDIF; pos := vi$get_undo_start; COPY_TEXT (source); APPEND_LINE; MOVE_HORIZONTAL (-1); vi$undo_end := MARK (NONE); MOVE_HORIZONTAL (1); vi$kill_undo; IF (here_or_below = VI$AFTER) AND (vi$yank_mode = VI$LINE_MODE) THEN MOVE_HORIZONTAL (-CURRENT_OFFSET); ENDIF; vi$undo_start := vi$set_undo_start (pos); ! Put the mode back into the buffer. IF (GET_INFO (source, "TYPE") = BUFFER) THEN POSITION (BEGINNING_OF (source)); COPY_TEXT (STR (vi$yank_mode)); SPLIT_LINE; POSITION (vi$undo_start); ENDIF; IF (here_or_below = VI$AFTER) AND (vi$yank_mode = VI$IN_LINE_MODE) THEN POSITION (vi$undo_end); ENDIF; vi$check_length (olen); ENDPROCEDURE; ! ! Function mapped to 'o'. Note that this makes undo NOT place ! the cursor where is really should be. ! PROCEDURE vi$open_below LOCAL uline; ON_ERROR ! Ignore attempt to move past EOB errors ENDON_ERROR; uline := vi$cur_line_no; MOVE_VERTICAL (1); vi$open_here; vi$undo_line := uline; ENDPROCEDURE; ! ! Function mapped to 'O' ! PROCEDURE vi$open_here LOCAL uline, offs, cnt, epos, spos; uline := vi$cur_line_no; offs := CURRENT_OFFSET; MOVE_HORIZONTAL (- CURRENT_OFFSET); IF (MARK (NONE) <> BEGINNING_OF (CURRENT_BUFFER)) THEN MOVE_HORIZONTAL (-1); spos := MARK (NONE); MOVE_HORIZONTAL (1); ELSE spos := 0; ENDIF; SPLIT_LINE; MOVE_VERTICAL (-1); cnt := vi$while_not_esc; epos := MARK (NONE); IF (cnt <> 0) THEN IF (LENGTH (vi$current_line) > 0) THEN MOVE_HORIZONTAL (1); ENDIF; ENDIF; vi$undo_end := MARK (NONE); IF spos <> 0 THEN POSITION (spos); MOVE_HORIZONTAL (1); ELSE POSITION (BEGINNING_OF (CURRENT_BUFFER)); ENDIF; vi$undo_start := MARK (NONE); POSITION (epos); vi$kill_undo; vi$undo_line := uline; vi$undo_offset := offs; ENDPROCEDURE; ! ! This function guards the right margin, and the end of the buffer so ! that the cursor never is displayed past those boundries. ! PROCEDURE vi$check_rmarg ON_ERROR; ! ignore "Can't return line and end of buffer" messages RETURN; ENDON_ERROR; IF (LENGTH (vi$current_line) > 0) THEN IF (CURRENT_OFFSET = LENGTH (vi$current_line)) THEN MOVE_HORIZONTAL (-1); ENDIF; ENDIF; IF (MARK (NONE) = END_OF (CURRENT_BUFFER)) THEN MOVE_VERTICAL (-1); ENDIF; ENDPROCEDURE; ! ! The function mapped to 'h'. ! PROCEDURE vi$move_left vi$position (vi$left, 0); ENDPROCEDURE; ! ! The function mapped to 'l'. ! PROCEDURE vi$move_right vi$position (vi$right, 0); ENDPROCEDURE; ! ! The function mapped to 'j' ! PROCEDURE vi$move_down LOCAL save_mark; save_mark := 0; IF (vi$active_count >= vi$report) THEN save_mark := 1; ENDIF; vi$position (vi$downline (0), save_mark); ENDPROCEDURE; ! ! The function mapped to 'k'. ! PROCEDURE vi$move_up LOCAL save_mark; save_mark := 0; IF (vi$active_count >= vi$report) THEN save_mark := 1; ENDIF; vi$position (vi$upline, save_mark); ENDPROCEDURE; ! ! The function mapped to 'i'. ! PROCEDURE vi$insert_here LOCAL act_cnt, rnge, ccnt, epos, spos; vi$kill_undo; IF (MARK (NONE) <> BEGINNING_OF (CURRENT_BUFFER)) THEN MOVE_HORIZONTAL (-1); spos := MARK (NONE); MOVE_HORIZONTAL (1); ELSE spos := 0; ENDIF; vi$undo_start := MARK (NONE); ccnt := vi$while_not_esc; vi$undo_end := 0; IF (ccnt > 0) THEN IF (CURRENT_OFFSET = 0) AND ((ccnt > 1) OR (LENGTH (CURRENT_LINE) = 0)) AND (MARK (NONE) <> BEGINNING_OF (CURRENT_BUFFER)) THEN MOVE_HORIZONTAL (-1); epos := MARK (NONE); MOVE_HORIZONTAL (1); ELSE epos := MARK (NONE); ENDIF; ELSE epos := 0; ENDIF; IF epos <> 0 THEN act_cnt := vi$cur_active_count; IF spos <> 0 THEN POSITION (spos); MOVE_HORIZONTAL (1); ELSE POSITION (BEGINNING_OF (CURRENT_BUFFER)); ENDIF; vi$undo_start := MARK (NONE); POSITION (epos); IF (vi$undo_start = 0) OR (epos = 0) THEN vi$message ("Ooops, bad markers in vi$insert_here"); RETURN ; ENDIF; rnge := CREATE_RANGE (vi$undo_start, epos, NONE); LOOP EXITIF act_cnt < 2; MOVE_HORIZONTAL (1); IF rnge = 0 THEN vi$message ("Ooops, generated a bad range in vi$insert_here"); RETURN ; ENDIF; COPY_TEXT (rnge); act_cnt := act_cnt - 1; MOVE_HORIZONTAL (-1); ENDLOOP; vi$undo_end := MARK (NONE); IF (CURRENT_OFFSET = LENGTH (vi$current_line)) THEN MOVE_HORIZONTAL (1); ENDIF; ENDIF; ENDPROCEDURE; ! ! The function mapped to 'I' ! PROCEDURE vi$insert_at_begin MOVE_HORIZONTAL (- CURRENT_OFFSET); vi$_bol; vi$insert_here; ENDPROCEDURE; ! ! The function mapped to 'a' ! PROCEDURE vi$insert_after IF (LENGTH (vi$current_line) > 0) THEN IF (CURRENT_OFFSET < LENGTH(vi$current_line)) THEN MOVE_HORIZONTAL (1); ENDIF; ENDIF; vi$insert_here; ENDPROCEDURE; ! ! A do nothing function ! PROCEDURE vi$_dummy ENDPROCEDURE; ! ! Do the command line input processing ! PROCEDURE vi$while_not_esc LOCAL max_mark, start_pos, max_col; max_col := CURRENT_OFFSET; start_pos := max_col; max_mark := MARK(NONE); vi$update (CURRENT_WINDOW); RETURN (vi$line_edit (max_col, start_pos, max_mark, 0)); ENDPROCEDURE; ! ! Insert text into the buffer using standard VI insertion. ! Used by CHANGE, APPEND, INSERT, and REPLACE functions. ! PROCEDURE vi$line_edit (max_col, start_pos, max_mark, replace) LOCAL chcnt, offset, seen_eol, col, cnt, tabstops, current_mark, desc, start_ins, ins_text, should_wrap, abbrs, rchar, abbrlen, cabbr, pos, in_char; ON_ERROR ENDON_ERROR; IF (vi$show_mode) THEN vi$mess_select (BOLD); MESSAGE (FAO ("!7* INSERT")); vi$mess_select (REVERSE); ENDIF; chcnt := 0; seen_eol := 0; abbrs := EXPAND_NAME ("vi$abbr_", VARIABLES) + " "; cabbr := ""; abbrlen := 0; SET (INSERT, CURRENT_BUFFER); IF (max_col > CURRENT_OFFSET) OR (replace <> 0) THEN SET (OVERSTRIKE, CURRENT_BUFFER); ENDIF; start_ins := MARK (NONE); LOOP LOOP in_char := vi$read_a_key; desc := LOOKUP_KEY (KEY_NAME (in_char), COMMENT, vi$edit_keys); EXITIF (desc <> "reinsert"); IF max_mark <> MARK (NONE) THEN current_mark := MARK (NONE); POSITION (max_mark); MOVE_HORIZONTAL (-1); ERASE (CREATE_RANGE (MARK (NONE), current_mark, NONE)); ENDIF; SET (INSERT, CURRENT_BUFFER); COPY_TEXT (vi$last_insert); APPEND_LINE; max_col := CURRENT_OFFSET; start_pos := CURRENT_OFFSET; max_mark := MARK(NONE); chcnt := chcnt + 1; ENDLOOP; IF (desc = "active_macro") THEN EXECUTE (LOOKUP_KEY (KEY_NAME (in_char), PROGRAM, vi$edit_keys)); ELSE EXITIF desc = "escape"; should_wrap := (vi$wrap_margin <> 0) AND ((CURRENT_OFFSET + vi$wrap_margin) > vi$scr_width); IF (desc <> "eol") AND (desc <> "bword") AND (desc <> "bs") THEN IF (should_wrap) THEN offset := 0; MOVE_HORIZONTAL (-1); LOOP EXITIF (CURRENT_OFFSET = 0); EXITIF (INDEX (" ", CURRENT_CHARACTER) <> 0); MOVE_HORIZONTAL (-1); offset := offset + 1; ENDLOOP; IF (offset <> 0) THEN ERASE_CHARACTER (1); LOOP EXITIF (CURRENT_OFFSET = 0); MOVE_HORIZONTAL (-1); EXITIF ( INDEX (" ", CURRENT_CHARACTER) = 0); ERASE_CHARACTER (1); ENDLOOP; ENDIF; IF (CURRENT_OFFSET <> 0) THEN MOVE_HORIZONTAL (1); SPLIT_LINE; max_col := CURRENT_OFFSET; start_pos := CURRENT_OFFSET; max_mark := MARK(NONE); MOVE_HORIZONTAL (offset); ELSE MOVE_HORIZONTAL (offset); SPLIT_LINE; max_col := CURRENT_OFFSET; start_pos := CURRENT_OFFSET; max_mark := MARK(NONE); ENDIF; ENDIF; vi$update (CURRENT_WINDOW); IF desc = "vquote" THEN in_char := vi$read_a_key; ENDIF; IF in_char = TAB_KEY THEN vi$abbr (abbrs, 0, cabbr, abbrlen); IF (vi$use_tabs = 1) THEN COPY_TEXT (ASCII (9)); ELSE cnt := 0; col := GET_INFO (SCREEN, "CURRENT_COLUMN"); tabstops := GET_INFO (CURRENT_BUFFER, "TAB_STOPS"); IF (GET_INFO (tabstops, "TYPE") <> STRING) THEN LOOP EXITIF (col - ((col / tabstops) * tabstops) = 0); cnt := cnt + 1; col := col + 1; ENDLOOP; chcnt := chcnt + cnt; LOOP EXITIF (cnt < 0); IF (CURRENT_OFFSET = max_col) AND ((replace = 0) OR seen_eol) THE N SET (INSERT, CURRENT_BUFFER); ELSE IF CURRENT_OFFSET > max_col THEN max_col := CURRENT_OFFSET; max_mark := MARK (NONE);; ENDIF; ENDIF; COPY_TEXT (" "); cnt := cnt - 1; ENDLOOP ELSE ! Give up on windows with weird tab stops. COPY_TEXT (ASCII (9)); ENDIF; ENDIF; chcnt := chcnt + 1; ELSE IF (in_char <= CTRL_Z_KEY) AND (in_char >= CTRL_A_KEY) THEN in_char := (in_char - CTRL_A_KEY) / (CTRL_B_KEY - CTRL_A_KEY) + 1; ENDIF; rchar := vi$ascii(in_char); IF (INDEX (vi$_ws, rchar) <> 0) THEN chcnt := chcnt + vi$abbr (abbrs, rchar, cabbr, abbrlen) ; ELSE COPY_TEXT (rchar); IF (INDEX(vi$_upper_chars, rchar) <> 0) THEN cabbr := cabbr + "_"; ENDIF; cabbr := cabbr + rchar; abbrlen := abbrlen + 1; chcnt := chcnt + 1; ENDIF; ENDIF; IF (CURRENT_OFFSET = max_col) AND ((replace = 0) OR seen_eol) THEN SET (INSERT, CURRENT_BUFFER); ELSE IF CURRENT_OFFSET > max_col THEN max_col := CURRENT_OFFSET; max_mark := MARK (NONE); ENDIF; ENDIF; ELSE IF desc = "bs" THEN IF start_pos < CURRENT_OFFSET THEN ! Delete backspace and the character before it. vi$del_a_key; vi$del_a_key; SET (OVERSTRIKE, CURRENT_BUFFER); MOVE_HORIZONTAL (-1); chcnt := chcnt - 1; ENDIF; ELSE IF desc = "eol" THEN IF (max_mark <> MARK (NONE)) AND (replace = 0) THEN current_mark := MARK (NONE); POSITION (max_mark); MOVE_HORIZONTAL (-1); ERASE (CREATE_RANGE (MARK (NONE), current_mark, NONE)); ENDIF; vi$abbr (abbrs, 0, cabbr, abbrlen); SPLIT_LINE; chcnt := chcnt + 1; seen_eol := 1; IF (CURRENT_BUFFER = vi$dcl_buf) AND (vi$send_dcl) THEN MOVE_VERTICAL (-1); vi$send_to_dcl (CURRENT_LINE); MOVE_VERTICAL (1); ENDIF; max_col := CURRENT_OFFSET; start_pos := CURRENT_OFFSET; SET (INSERT, CURRENT_BUFFER); max_mark := MARK(NONE); IF (CURRENT_BUFFER = vi$dcl_buf) AND (vi$send_dcl) THEN EXITIF (1); ENDIF; ELSE IF (desc = "bword") THEN ! Backup over whitespace. LOOP EXITIF start_pos = CURRENT_OFFSET; MOVE_HORIZONTAL (-1); chcnt := chcnt - 1; EXITIF (INDEX (" ", CURRENT_CHARACTER) = 0); SET (OVERSTRIKE, CURRENT_BUFFER); ENDLOOP; ! Backup over noblank words. LOOP EXITIF start_pos = CURRENT_OFFSET; SET (OVERSTRIKE, CURRENT_BUFFER); IF (INDEX (" ", CURRENT_CHARACTER) <> 0) THE N chcnt := chcnt + 1; MOVE_HORIZONTAL (1); EXITIF (1); ENDIF; MOVE_HORIZONTAL (-1); chcnt := chcnt - 1; ENDLOOP; ENDIF; ENDIF; ENDIF; ENDIF; ENDIF; vi$update (CURRENT_WINDOW); ENDLOOP; IF max_mark <> MARK (NONE) THEN current_mark := MARK (NONE); IF (NOT seen_eol) AND (replace <> 0) THEN SET (OVERSTRIKE, CURRENT_BUFFER); COPY_TEXT (SUBSTR (replace, CURRENT_OFFSET + 1, max_col - CURRENT_OFFSET)); POSITION (current_mark); ELSE POSITION (max_mark); IF (MARK(NONE) <> BEGINNING_OF (CURRENT_BUFFER)) THEN MOVE_HORIZONTAL (-1); ENDIF; ERASE (CREATE_RANGE (MARK (NONE), current_mark, NONE)); ENDIF; ENDIF; IF (CURRENT_OFFSET > 0) AND (MARK(NONE) <> BEGINNING_OF (CURRENT_BUFFER)) THEN MOVE_HORIZONTAL (-1); ENDIF; ins_text := CREATE_RANGE (start_ins, MARK (NONE), NONE); ! Save last inserted text to buffer. ERASE (vi$last_insert); pos := MARK (NONE); POSITION (vi$last_insert); COPY_TEXT (ins_text); SPLIT_LINE; POSITION (BEGINNING_OF (vi$last_insert)); POSITION (pos); SET (INSERT, CURRENT_BUFFER); IF (vi$show_mode) THEN MESSAGE (""); ENDIF; RETURN (chcnt); ENDPROCEDURE; ! ! Check to see if 'cabbr' is a known abbreviation, and substitute the ! proper text if it is. ! PROCEDURE vi$abbr (abbrs, rchar, cabbr, abbrlen) LOCAL strg; strg := ""; IF (abbrlen > 0) THEN EDIT (cabbr, UPPER); IF (INDEX (abbrs, "VI$ABBR_"+cabbr+" ") <> 0) THEN vi$global_var := 0; EXECUTE (COMPILE ("vi$global_var := vi$abbr_"+cabbr+";")); IF (vi$global_var <> 0) THEN ERASE_CHARACTER (-abbrlen); strg := vi$global_var; COPY_TEXT (strg); ENDIF; ENDIF; cabbr := ""; abbrlen := 0; ENDIF; IF (rchar <> 0) THEN COPY_TEXT (rchar); ENDIF; RETURN (LENGTH (strg) + (rchar <> 0)); ENDPROCEDURE; ! ! Return a string describing the KEY_NAME passed. For control characters, ! it is "^?" where the '?' is A-Z. Otherwise, the value returned by the ! ASCII() builtin is used. ! PROCEDURE vi$ascii_name (key_n) LOCAL key; key := (key_n - CTRL_A_KEY) / (CTRL_B_KEY - CTRL_A_KEY); IF (key > 31) OR (key < 0) THEN key := ASCII (key_n); ELSE key := "^" + ASCII(key+65); ENDIF; RETURN (key); ENDPROCEDURE; ! ! Perform some mapping of keys to different ASCII values. ! PROCEDURE vi$ascii (key_n) IF key_n = F12 THEN RETURN (ASCII (8)); ENDIF; IF key_n = F11 THEN RETURN (ASCII (27)); ENDIF; IF key_n = PF1 THEN RETURN (ASCII (27)); ENDIF; IF key_n = RET_KEY THEN RETURN (ASCII (13)); ENDIF; IF key_n = TAB_KEY THEN RETURN (ASCII (9)); ENDIF; RETURN (ASCII (key_n)); ENDPROCEDURE; ! ! Move up by screens ! PROCEDURE vi$prev_screen ON_ERROR ENDON_ERROR; MOVE_VERTICAL (-vi$cur_active_count * GET_INFO (CURRENT_WINDOW, "VISIBLE_LENGTH")); vi$position (vi$first_no_space, 0); ENDPROCEDURE; ! ! Move down by screens ! PROCEDURE vi$next_screen ON_ERROR ENDON_ERROR; MOVE_VERTICAL (vi$cur_active_count * (GET_INFO (CURRENT_WINDOW, "VISIBLE_LENGTH") + 2)); vi$position (vi$first_no_space, 0); ENDPROCEDURE; ! ! Scroll forward one screen ! PROCEDURE vi$screen_forward vi$scroll_screen (1); ENDPROCEDURE; ! ! Scroll back one screen ! PROCEDURE vi$screen_backward vi$scroll_screen (-1); ENDPROCEDURE; ! ! Scroll the screen up or down depending on the sign of "how_many_screens" ! The magnitude actually has effect as well, but is never greater than 1 ! in this use. ! PROCEDURE vi$scroll_screen (how_many_screens) LOCAL scroll_window, ! Window to be scrolled this_window, ! Current window this_column, ! Current column in scroll_window this_row, ! Current row in scroll_window old_scroll_top, ! Original value of scroll_top old_scroll_bottom, ! Original value of scroll_bottom old_scroll_amount; ! Original value of scroll_amount ! Trap and ignore messages about move beyond buffer boundaries - ! just move to top or bottom line of buffer ON_ERROR ENDON_ERROR; this_window := CURRENT_WINDOW; scroll_window := this_window; IF vi$active_count <> 0 THEN vi$how_much_scroll := vi$cur_active_count; ENDIF; this_row := GET_INFO (scroll_window, "CURRENT_ROW"); IF this_row = 0 THEN this_row := GET_INFO (scroll_window, "VISIBLE_TOP"); ENDIF; this_column := GET_INFO (scroll_window, "CURRENT_COLUMN"); MOVE_HORIZONTAL (-CURRENT_OFFSET); old_scroll_top := GET_INFO (scroll_window, "SCROLL_TOP"); old_scroll_bottom := GET_INFO (scroll_window, "SCROLL_BOTTOM"); old_scroll_amount := GET_INFO (scroll_window, "SCROLL_AMOUNT"); SET (SCROLLING, scroll_window, ON, this_row - GET_INFO (scroll_window, "VISIBLE_TOP"), GET_INFO (scroll_window, "VISIBLE_BOTTOM") - this_row, 0); MOVE_VERTICAL (how_many_screens * vi$how_much_scroll); vi$update (scroll_window); IF this_window <> CURRENT_WINDOW THEN POSITION (this_window); ENDIF; SET (SCROLLING, scroll_window, ON, old_scroll_top, old_scroll_bottom, old_scroll_amount); ENDPROCEDURE; ! ! Move forward logical words ! PROCEDURE vi$_word_forward vi$position (vi$word_move (1), 0); ENDPROCEDURE; ! ! Move backward logical words ! PROCEDURE vi$_word_back vi$position (vi$word_move(-1), 0); ENDPROCEDURE; ! ! Move by logical word taking into account the repeat count ! PROCEDURE vi$word_move(dir) LOCAL old_pos, pos; old_pos := MARK (NONE); IF vi$active_count <= 0 THEN vi$active_count := 1; ENDIF; LOOP pos := vi$move_logical_word (dir); EXITIF pos = 0; POSITION (pos); vi$active_count := vi$active_count - 1; EXITIF vi$active_count = 0; ENDLOOP; vi$yank_mode := VI$IN_LINE_MODE; RETURN (vi$retpos (old_pos)); ENDPROCEDURE; ! ! Move to end of logical word ! PROCEDURE vi$_word_end vi$position (vi$word_end, 0); ENDPROCEDURE; ! ! Move to end of physical word ! PROCEDURE vi$_full_word_end vi$position (vi$full_word_end, 0); ENDPROCEDURE; ! ! Move to the end of the current word. ! PROCEDURE vi$word_end LOCAL old_pos, pos; old_pos := MARK (NONE); IF vi$active_count <= 0 THEN vi$active_count := 1; ENDIF; LOOP pos := vi$move_logical_end; EXITIF pos = 0; POSITION (pos); vi$active_count := vi$active_count - 1; EXITIF vi$active_count = 0; ENDLOOP; vi$yank_mode := VI$IN_LINE_MODE; RETURN (vi$retpos (old_pos)); ENDPROCEDURE; ! ! Move to the end of a blank (eol is also considered blank) terminated word. ! PROCEDURE vi$full_word_end LOCAL old_pos, pos; old_pos := MARK (NONE); IF vi$active_count <= 0 THEN vi$active_count := 1; ENDIF; LOOP pos := vi$move_full_end; EXITIF pos = 0; POSITION (pos); vi$active_count := vi$active_count - 1; EXITIF vi$active_count = 0; ENDLOOP; vi$yank_mode := VI$IN_LINE_MODE; RETURN (vi$retpos (old_pos)); ENDPROCEDURE; ! ! Move forward by ONE white-space delimited word ! PROCEDURE vi$_full_word_forward vi$position (vi$full_word_move (1), 0); ENDPROCEDURE; ! ! ! Move backward by ONE white-space delimited word ! PROCEDURE vi$_full_word_back vi$position (vi$full_word_move (-1), 0); ENDPROCEDURE; ! ! Move by physical word taking the repeat count into account ! PROCEDURE vi$full_word_move (dir) LOCAL old_pos, pos; old_pos := MARK (NONE); IF vi$active_count <= 0 THEN vi$active_count := 1; ENDIF; LOOP pos := vi$move_full_word (dir); EXITIF pos = 0; POSITION (pos); vi$active_count := vi$active_count - 1; EXITIF vi$active_count = 0; ENDLOOP; vi$yank_mode := VI$IN_LINE_MODE; RETURN (vi$retpos (old_pos)); ENDPROCEDURE; ! ! Move the cursor by BLANK separated words. DIRECTION is either ! +1, or -1 to indicate the direction (forward, or backword respectfully) ! to move ! PROCEDURE vi$move_full_word (direction) LOCAL pos; pos := MARK (NONE); $$EOD$