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$