[comp.os.vms] VI in TPU part 6/14

gregg@a.cs.okstate.edu (Gregg Wonderly) (10/21/87)

$!=============================================================================
$! VAX/VMS archive file created by VMS_SHAR V-4.03 05-Aug-1987
$! which was written by Michael Bednarek (U3369429@ucsvc.dn.mu.oz.au)
$! To unpack, simply save and execute (@) this file.
$!
$! This archive was created by GREGG
$!      on Tuesday 20-OCT-1987 22:28:18.30
$!
$! It contains the following 1 file:
$! VI.4
$!=============================================================================
$ Set Symbol/Scope=(NoLocal,NoGlobal)
$ Version=F$GetSYI("VERSION") ! See what VMS version we have here:
$ If Version.ges."V4.4" then goto Version_OK
$ Write SYS$Output "Sorry, you are running VMS ",Version, -
                ", but this procedure requires V4.4 or higher."
$ Exit 44
$Version_OK: CR[0,8]=13
$ Pass_or_Failed="failed!,passed."
$ Goto Start
$Convert_File:
$ Read/Time_Out=0/Error=No_Error1/Prompt="creating ''File_is'" SYS$Command ddd
$No_Error1: Define/User_Mode SYS$Output NL:
$ Edit/TPU/NoSection/NoDisplay/Command=SYS$Input/Output='File_is' -
        VMS_SHAR_DUMMY.DUMMY
f:=Get_Info(Command_Line,"File_Name");b:=Create_Buffer("",f);
o:=Get_Info(Command_Line,"Output_File");Set (Output_File,b,o);
Position (Beginning_of(b));Loop x:=Erase_Character(1); Loop ExitIf x<>"V";
Move_Vertical(1);x:=Erase_Character(1);Append_Line;Move_Horizontal
(-Current_Offset);EndLoop;Move_Vertical(1);ExitIf Mark(None)=End_of(b)
EndLoop;Exit;
$ Delete VMS_SHAR_DUMMY.DUMMY;*
$ Checksum 'File_is
$ Success=F$Element(Check_Sum_is.eq.CHECKSUM$CHECKSUM,",",Pass_or_Failed)+CR
$ Read/Time_Out=0/Error=No_Error2/Prompt=" CHECKSUM ''Success'" SYS$Command ddd
$No_Error2: Return
$Start:
$ File_is="VI.4"
$ Check_Sum_is=1494879195
$ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY
X!
X!
X!                   The VI EDITOR written in VAXTPU
X!
X!   Written by Gregg Wonderly
X!   Mathematics Department
X!   Oklahoma State University
X!   Stillwater Oklahoma, 74078
X!
X!   internet: gregg@nemo.math.okstate.edu
X!   uucp: okstate!nemo.math.okstate.edu!gregg
X!
X!   Version number 1, edit 482, 11-OCT-1987 13:55:35.87
X!
X!   This program is the property of the author, and you should refrain
X!   from trying to make a profit from it (that's not nice).
X!
X!   You can pass it around freely, as you should have gotten it for free.
X!   All I ask is that you give credit where credit is due.
X!
X!
X!
X!   Initialize TPU for VI emulation.
X!
XPROCEDURE vi$init_vars
X    LOCAL
X        i;
X
X    message_buffer := 0;
X    message_window := 0;
X
X    command_buffer := 0;
X    command_window := 0;
X
X    show_buffer := 0;
X    info_window := 0;
X
X    choice_buffer := 0;
X    choice_window := 0;
X
X    vi$last_mapped := 0;
X    vi$last_insert := 0;
X
X    vi$bracket_chars := "{}()[]";       ! The recognized brackets.
X
X    ! interline movement that is backwards, or different than the others
X
X    vi$abbr_ := "";
X    vi$back_moves := "bB0FT^(";
X    vi$weird_moves := "ft$DeE%";
X    vi$weird2_moves := "h";
X    vi$dot_keys := "iIdpPDxXaAcCoOrRSs<>";
X
X    vi$_lower_chars := "abcdefghijklmnopqrstuvwxyz";
X    vi$_upper_chars := "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
X    vi$_letter_chars := vi$_lower_chars + vi$_upper_chars;
X    vi$_numeric_chars := "0123456789";
X    vi$_alpha_chars := vi$_letter_chars + "_" + vi$_numeric_chars;
X    vi$_sym_chars := vi$_alpha_chars + "$";
X    vi$_ctl_chars := "";
X    i := 0;
X    LOOP
X        EXITIF (i = 32);
X        vi$_ctl_chars := vi$_ctl_chars + ASCII (i);
X        i := i + 1;
X    ENDLOOP;
X
X    vi$_space_chars := "    " + vi$_ctl_chars;
X    vi$_punct_chars := "!@`~#$%^&*()-=+{}[];:'""\|,.?/><";
X    vi$_ex_separs := ",     ";
X    vi$_ascii_chars := "";
X    vi$_ws := ",./?;:'""\|[]{}-=+)(*&^%$#@!~`" + vi$_space_chars;
X    vi$no_space := " " + ASCII(9) + ASCII (10) + ASCII(11) + ASCII(13);
X    i := 0;
X    LOOP
X        EXITIF (i = 256);
X        vi$_ascii_chars := vi$_ascii_chars + ASCII (i);
X        i := i + 1;
X    ENDLOOP;
X
X    vi$pch := " ";
X    i := 32;
X    LOOP
X        EXITIF (i = 256);
X        vi$pch := vi$pch + ASCII (i);
X        i := i + 1;
X    ENDLOOP;
X
X    vi$m_level := 0;
X    vi$in_learn := 0;
X    vi$playing_back := 0;
X
X    vi$dcl_buf := 0;
X    vi$dcl_process := 0;
X    vi$send_dcl := 1;
X
X    vi$tag_buf := 0;
X    vi$tag_files := "tags";
X    vi$tag_case := EXACT;
X    vi$in_ws := 0;
X    vi$in_global := 0;
X    vi$in_occlusion := 0;
X    vi$old_occ_win := 0;
X    vi$occluding_win := 0;
X    vi$error_bells := 1;
X    vi$show_mode := 0;
X
X    vi$tmp_key_buf := 0;
X
X    vi$last_mess := "";
X
X    vi$max_offset := 0;
X    vi$new_offset := 1;
X
X    vi$old_place := 0;
X    vi$select_pos := 0;
X
X    vi$term_vt200 := 0;
X    vi$scr_width := 0;
X    vi$scr_length := 0;
X
X    vi$next_blank := "" & LINE_BEGIN & LINE_END;
X    vi$para_str := "P ";
X    vi$para_pat := "" & LINE_BEGIN & (".P");
X    vi$sect_str := "CHHLPG+c";
X    vi$sect_pat := "" & LINE_BEGIN & (".CH"| ".HL"| ".PG"| "{");
X    vi$last_cmd := 0;
X    vi$last_filter := 0;
X
X    vi$replace_separ := 0;
X    vi$replace_source := 0;
X    vi$replace_dest := 0;
X
X    VI$DELETE_TYPE  := 1;
X    VI$CHANGE_TYPE  := 2;
X    VI$OTHER_TYPE   := 3;
X    VI$YANK_TYPE    := 4;
X    VI$FILTER_TYPE  := 5;
X    VI$SHIFT_TYPE   := 6;
X    vi$command_type := VI$OTHER_TYPE;
X
X    vi$cu_cwd           := 1;
X    vi$cu_trnlnm_job    := 2;
X    vi$cu_trnlnm_proc   := 3;
X    vi$cu_trnlnm_sys    := 4;
X    vi$cu_trnlnm_group  := 5;
X    vi$cu_getmsg        := 6;
X    vi$cu_set_sysdisk   := 7;
X    vi$cu_sleep         := 8;
X    vi$cu_pasthru_on    := 9;
X    vi$cu_pasthru_off   := 10;
X
X    vi$filter_proc := 0;
X    vi$filter_buf := 0;
X
X    vi$push_key_buf := 0;
X
X    vi$ex_mode_buffer := 0;
X    vi$global_var := 0;
X    vi$macro_active := "$$active_macro$$";
X    vi$_find_pat := 0;
X    vi$wrap_scan := 1;
X
X    vi$last_key := 0;
X    vi$last_keys := 0;
X    vi$cur_keys := 0;
X    vi$key_buf := 0;
X    vi$min_update := 1;
X    vi$tab_amount := 8;
X    vi$shift_width := 4;
X    vi$spaces := "                                                    ";
X    vi$use_tabs := 1;
X    vi$in_show_match := 0;
X    vi$report := 5;
X    vi$auto_write := 0;
X    vi$ignore_case := EXACT;
X    vi$wrap_margin := 0;
X    vi$magic := 1;
X    vi$undo_map := 1;
X
X    vi$undo_line_str := 0;
X    vi$undo_line_mark := 0;
X    vi$undo_line := 0;
X    vi$undo_offset := 0;
X
X    vi$how_much_scroll := 12;
X
X    vi$search_string := 0;
X    vi$last_search_dir := 1;
X
X    vi$undo_start := 0;
X    vi$undo_end := 0;
X    vi$undo_buffer := 0;
X    vi$undo_valid := 0;
X
X    VI$HERE := 0;
X    VI$AFTER := 1;
X
X    VI$LINE_MODE := 1;
X    VI$IN_LINE_MODE := 2;
X
X    vi$cur_level := 0;
X
X    vi$global_mark := 0;
X    vi$yank_mode := 0;
X    vi$temp_buf := 0;
X    vi$cur_text := "";      ! Where text to PUT comes from.
X
X    ! The ten deletion buffers.
X
X    vi$del_buf_1 := 0; vi$del_buf_2 := 0; vi$del_buf_3 := 0;
X    vi$del_buf_4 := 0; vi$del_buf_5 := 0; vi$del_buf_6 := 0;
X    vi$del_buf_7 := 0; vi$del_buf_8 := 0; vi$del_buf_9 := 0;
X
X    ! Named buffers accessible from the keyboard characters.
X
X    vi$ins_buf_a := 0; vi$ins_buf_b := 0; vi$ins_buf_c := 0;
X    vi$ins_buf_d := 0; vi$ins_buf_e := 0; vi$ins_buf_f := 0;
X    vi$ins_buf_g := 0; vi$ins_buf_h := 0; vi$ins_buf_i := 0;
X    vi$ins_buf_j := 0; vi$ins_buf_k := 0; vi$ins_buf_l := 0;
X    vi$ins_buf_m := 0; vi$ins_buf_n := 0; vi$ins_buf_o := 0;
X    vi$ins_buf_p := 0; vi$ins_buf_q := 0; vi$ins_buf_r := 0;
X    vi$ins_buf_s := 0; vi$ins_buf_t := 0; vi$ins_buf_u := 0;
X    vi$ins_buf_v := 0; vi$ins_buf_w := 0; vi$ins_buf_x := 0;
X    vi$ins_buf_y := 0; vi$ins_buf_z := 0;
X
X    ! The 26 marks available
X
X    vi$mark_a := 0; vi$mark_b := 0; vi$mark_c := 0; vi$mark_d := 0;
X    vi$mark_e := 0; vi$mark_f := 0; vi$mark_g := 0; vi$mark_h := 0;
X    vi$mark_i := 0; vi$mark_j := 0; vi$mark_k := 0; vi$mark_l := 0;
X    vi$mark_m := 0; vi$mark_n := 0; vi$mark_o := 0; vi$mark_p := 0;
X    vi$mark_q := 0; vi$mark_r := 0; vi$mark_s := 0; vi$mark_t := 0;
X    vi$mark_u := 0; vi$mark_v := 0; vi$mark_w := 0; vi$mark_x := 0;
X    vi$mark_y := 0; vi$mark_z := 0;
X
X    vi$endpos := 0;
X    vi$new_endpos := 0;
X    vi$start_pos := 0;
X
X    VI$ALPHA_TYPE := 1;
X    VI$PUNCT_TYPE := 2;
X    VI$SPACE_TYPE := 3;
X    VI$EOL_TYPE := 4;
X
X    vi$temp_buf_num := 1;
X    vi$last_s_func := 0;
X    vi$last_s_char := 0;
X
X    vi$active_count := 0;
X    vi$cmd_keys := "c_keys";
X    vi$move_keys := "m_keys";
X    vi$edit_keys := "e_keys";
X
XENDPROCEDURE;
X
X!
X!   Map all of the key bindings into the proper key maps.
X!
X!       The "c_keys" map is used for command mode key processing.
X!       The "e_keys" map is used during line editing.
X!       The "m_keys" map is used to determine movement associated with
X!                    a particular key.
X!
XPROCEDURE vi$init_keys
X
X    ! Define all of the command mode keys.
X
X    vi$cmd_keys := CREATE_KEY_MAP ("c_keys");
X
X    DEFINE_KEY ("vi$make_full_screen", KP0, "", vi$cmd_keys);
X    DEFINE_KEY ("vi$delete_window", KP1, "", vi$cmd_keys);
X    DEFINE_KEY ("vi$split_here", KP2, "", vi$cmd_keys);
X    DEFINE_KEY ("vi$next_window", KP3, "", vi$cmd_keys);
X    DEFINE_KEY ("vi$shrink_window(vi$cur_active_count)", KP4,
X            "", vi$cmd_keys);
X    DEFINE_KEY ("vi$enlarge_window(vi$cur_active_count)", KP5,
X            "", vi$cmd_keys);
X    DEFINE_KEY ("vi$previous_window", KP6, "", vi$cmd_keys);
X
X    DEFINE_KEY ("vi$prev_screen", CTRL_B_KEY, "vi$prev_screen", vi$cmd_keys);
X    DEFINE_KEY ("vi$screen_forward", CTRL_D_KEY,
X        "vi$screen_forward", vi$cmd_keys);
X    DEFINE_KEY ("vi$pull_push_line (1)", CTRL_E_KEY,
X        "vi$pull_push_line (1)", vi$cmd_keys);
X    DEFINE_KEY ("vi$next_screen", CTRL_F_KEY, "vi$next_screen", vi$cmd_keys);
X    DEFINE_KEY ("vi$what_line", CTRL_G_KEY, "vi$what_line", vi$cmd_keys);
X    DEFINE_KEY ("vi$move_left", CTRL_H_KEY, "vi$move_left", vi$cmd_keys);
X    DEFINE_KEY ("refresh", CTRL_L_KEY, "refresh", vi$cmd_keys);
X    DEFINE_KEY ("vi$_next_line", CTRL_N_KEY, "vi$_next_line", vi$cmd_keys);
X    DEFINE_KEY ("vi$do_macro('k0', 0)", CTRL_P_KEY,
X        "vi$do_macro('k0', 0)", vi$cmd_keys);
X    DEFINE_KEY ("vi$remember", CTRL_R_KEY, "vi$remember", vi$cmd_keys);
X    DEFINE_KEY ("vi$screen_backward", CTRL_U_KEY,
X        "vi$screen_backward", vi$cmd_keys);
X    DEFINE_KEY ("vi$send_to_dcl (CURRENT_LINE)", CTRL_X_KEY,
X        "vi$send_to_dcl (CURRENT_LINE)", vi$cmd_keys);
X    DEFINE_KEY ("vi$pull_push_line (-1)", CTRL_Y_KEY,
X        "vi$pull_push_line (-1)", vi$cmd_keys);
X    DEFINE_KEY ("vi$to_tag(0)", KEY_NAME(ASCII(29)),
X        "vi$to_tag(0)", vi$cmd_keys);
X    DEFINE_KEY ("vi$move_prev_buf", KEY_NAME(ASCII(30)),
X        "vi$move_prev_buf", vi$cmd_keys);
X    DEFINE_KEY ("vi$do_help('')", PF2, "vi$do_help('')", vi$cmd_keys);
X    DEFINE_KEY ("vi$on_escape", PF1, "vi$on_escape", vi$cmd_keys);
X    DEFINE_KEY ("vi$on_escape", F11, "vi$on_escape", vi$cmd_keys);
X    DEFINE_KEY ("vi$_go_to_marker", KEY_NAME ("'"),
X        "vi$_go_to_marker", vi$cmd_keys);
X    DEFINE_KEY ("vi$_go_to_marker", KEY_NAME ("`"),
X        "vi$_go_to_marker", vi$cmd_keys);
X    DEFINE_KEY ("vi$select_buffer", KEY_NAME ('"'),
X        "vi$select_buffer", vi$cmd_keys);
X    DEFINE_KEY ("vi$_match_brackets", KEY_NAME ('%'),
X        "vi$_match_brackets", vi$cmd_keys);
X    DEFINE_KEY ("vi$_change_case", KEY_NAME ('~'),
X        "vi$_change_case", vi$cmd_keys);
X    DEFINE_KEY ("vi$region_left", KEY_NAME ('<'),
X        "vi$region_left", vi$cmd_keys);
X    DEFINE_KEY ("vi$region_right", KEY_NAME ('>'),
X        "vi$region_right", vi$cmd_keys);
V    DEFINE_KEY ("vi$_next_line", KEY_NAME ('+'), "vi$_next_line", vi$cmd_keys)
X;
X    DEFINE_KEY ("vi$do_macro('k^', 0)", KEY_NAME ('-'),
X        "vi$do_macro('k^', 0)", vi$cmd_keys);
X    DEFINE_KEY ("vi$_paragraph (-1)", KEY_NAME ('{'),
X        "vi$_paragraph (-1)", vi$cmd_keys);
X    DEFINE_KEY ("vi$_section (-1)", KEY_NAME ('['),
X        "vi$_section (-1)", vi$cmd_keys);
X    DEFINE_KEY ("vi$_begin_sentence", KEY_NAME ('('),
X        "vi$_begin_sentence", vi$cmd_keys);
X    DEFINE_KEY ("vi$_paragraph (1)", KEY_NAME ('}'),
X        "vi$_paragraph (1)", vi$cmd_keys);
X    DEFINE_KEY ("vi$_section (1)", KEY_NAME (']'),
X        "vi$_section (1)", vi$cmd_keys);
X    DEFINE_KEY ("vi$_end_sentence", KEY_NAME (')'),
X        "vi$_end_sentence", vi$cmd_keys);
X    DEFINE_KEY ("vi$insert_after", KEY_NAME ('a'),
X        "vi$insert_after", vi$cmd_keys);
X    DEFINE_KEY ("vi$do_macro('$a', 0)", KEY_NAME ('A'),
X        "vi$do_macro('$a', 0)", vi$cmd_keys);
X    DEFINE_KEY ("vi$_word_back", KEY_NAME ('b'),
X        "vi$_word_back", vi$cmd_keys);
X    DEFINE_KEY ("vi$_full_word_back", KEY_NAME ('B'),
X        "vi$_full_word_back", vi$cmd_keys);
X    DEFINE_KEY ("vi$_change", KEY_NAME ('c'),
X        "vi$_change", vi$cmd_keys);
X    DEFINE_KEY ("vi$do_macro ('c$', 0)", KEY_NAME ('C'),
X        "vi$do_macro ('c$', 0)", vi$cmd_keys);
X    DEFINE_KEY ("vi$_delete (0, -1)", KEY_NAME ('d'),
X        "delete", vi$cmd_keys);
X    DEFINE_KEY ("vi$_delete (KEY_NAME('$'), -1)", KEY_NAME ('D'),
X        "delete_eol", vi$cmd_keys);
X    DEFINE_KEY ("vi$_word_end", KEY_NAME ('e'),
X        "vi$_word_end", vi$cmd_keys);
X    DEFINE_KEY ("vi$_full_word_end", KEY_NAME ('E'),
X        "vi$_full_word_end", vi$cmd_keys);
X    DEFINE_KEY ("vi$_find_char (0)", KEY_NAME ('f'),
X        "vi$_find_char (0)", vi$cmd_keys);
X    DEFINE_KEY ("vi$_back_find_char (0)", KEY_NAME ('F'),
X        "vi$_back_find_char (0)", vi$cmd_keys);
X    DEFINE_KEY ("vi$go_to_line", KEY_NAME ('G'),
X        "vi$go_to_line", vi$cmd_keys);
X    DEFINE_KEY ("vi$move_left", KEY_NAME ('h'),
X        "vi$move_left", vi$cmd_keys);
X    DEFINE_KEY ("home", KEY_NAME ('H'), "home", vi$cmd_keys);
X    DEFINE_KEY ("vi$insert_here", KEY_NAME ('i'),
X        "vi$insert_here", vi$cmd_keys);
X    DEFINE_KEY ("vi$insert_at_begin", KEY_NAME ('I'),
X        "vi$insert_at_begin", vi$cmd_keys);
X    DEFINE_KEY ("vi$move_down", KEY_NAME ('j'),
X        "vi$move_down", vi$cmd_keys);
X    DEFINE_KEY ("vi$_join_lines", KEY_NAME ('J'),
X        "vi$_join_lines", vi$cmd_keys);
X    DEFINE_KEY ("vi$move_up", KEY_NAME ('k'), "vi$move_up", vi$cmd_keys);
V    DEFINE_KEY ("vi$move_right", KEY_NAME ('l'), "vi$move_right", vi$cmd_keys)
X;
X    DEFINE_KEY ("vi$last", KEY_NAME ('L'), "vi$last", vi$cmd_keys);
X    DEFINE_KEY ("vi$_set_mark", KEY_NAME ('m'), "vi$_set_mark", vi$cmd_keys);
X    DEFINE_KEY ("vi$middle", KEY_NAME ('M'), "vi$middle", vi$cmd_keys);
X    DEFINE_KEY ("vi$_search_next(vi$last_search_dir)", KEY_NAME('n'),
X        "vi$_search_next(vi$last_search_dir)", vi$cmd_keys);
X    DEFINE_KEY ("vi$_search_next(-vi$last_search_dir)", KEY_NAME('N'),
X        "vi$_search_next(-vi$last_search_dir)", vi$cmd_keys);
V    DEFINE_KEY ("vi$open_below", KEY_NAME ('o'), "vi$open_below", vi$cmd_keys)
X;
X    DEFINE_KEY ("vi$open_here", KEY_NAME ('O'), "vi$open_here", vi$cmd_keys);
X    DEFINE_KEY ("vi$put_here (VI$HERE, -1)", KEY_NAME ('P'),
X        "vi$put_here (VI$HERE, -1)", vi$cmd_keys);
X    DEFINE_KEY ("vi$put_after (-1)", KEY_NAME ('p'),
X        "vi$put_after (-1)", vi$cmd_keys);
X    DEFINE_KEY ("vi$_replace_char", KEY_NAME ('r'),
X        "vi$_replace_char", vi$cmd_keys);
X    DEFINE_KEY ("vi$_replace_str", KEY_NAME ('R'),
X        "vi$_replace_str", vi$cmd_keys);
X    DEFINE_KEY ("vi$do_macro('cl', 0)", KEY_NAME ('s'),
X        "vi$do_macro('cl', 0)", vi$cmd_keys);
X    DEFINE_KEY ("vi$_big_s", KEY_NAME ('S'), "vi$_big_s", vi$cmd_keys);
X    DEFINE_KEY ("vi$_to_char (0)", KEY_NAME ('t'),
X        "vi$_to_char (0)", vi$cmd_keys);
X    DEFINE_KEY ("vi$_back_to_char (0)", KEY_NAME ('T'),
X        "vi$_back_to_char (0)", vi$cmd_keys);
X    DEFINE_KEY ("vi$perform_undo", KEY_NAME ('u'),
X        "vi$perform_undo", vi$cmd_keys);
X    DEFINE_KEY ("vi$undo_one_line", KEY_NAME ('U'),
X        "vi$undo_one_line", vi$cmd_keys);
X    DEFINE_KEY ("vi$_word_forward", KEY_NAME ('w'),
X        "vi$_word_forward", vi$cmd_keys);
X    DEFINE_KEY ("vi$_full_word_forward", KEY_NAME ('W'),
X        "vi$_full_word_forward", vi$cmd_keys);
X    DEFINE_KEY ("vi$do_macro ('dl', 0)", KEY_NAME ('x'),
X        "vi$do_macro ('dl', 0)", vi$cmd_keys);
X    DEFINE_KEY ("vi$do_macro ('dh', 0)", KEY_NAME ('X'),
X        "vi$do_macro ('dh', 0)", vi$cmd_keys);
X    DEFINE_KEY ("vi$_yank (0, -1)", KEY_NAME ('y'),
X        "vi$_yank (0, -1)", vi$cmd_keys);
X    DEFINE_KEY ("vi$_yank (KEY_NAME('y'), -1)", KEY_NAME ('Y'),
X        "vi$_yank (KEY_NAME('y'), -1)", vi$cmd_keys);
X    DEFINE_KEY ("vi$_ZZ", KEY_NAME ('Z'), "vi$_ZZ", vi$cmd_keys);
X    DEFINE_KEY ("vi$_z_move", KEY_NAME ('z'), "vi$_z_move", vi$cmd_keys);
X    DEFINE_KEY ("vi$_to_column", KEY_NAME ('|'),
X        "vi$_to_column", vi$cmd_keys);
X    DEFINE_KEY ("vi$_next_line", RET_KEY, "vi$_next_line", vi$cmd_keys);
X    DEFINE_KEY ("vi$repeat_count", KEY_NAME ('0'),
X        "vi$repeat_count", vi$cmd_keys);
X    DEFINE_KEY ("vi$repeat_count", KEY_NAME ('1'),
X        "vi$repeat_count", vi$cmd_keys);
X    DEFINE_KEY ("vi$repeat_count", KEY_NAME ('2'),
X        "vi$repeat_count", vi$cmd_keys);
X    DEFINE_KEY ("vi$repeat_count", KEY_NAME ('3'),
X        "vi$repeat_count", vi$cmd_keys);
X    DEFINE_KEY ("vi$repeat_count", KEY_NAME ('4'),
X        "vi$repeat_count", vi$cmd_keys);
X    DEFINE_KEY ("vi$repeat_count", KEY_NAME ('5'),
X        "vi$repeat_count", vi$cmd_keys);
X    DEFINE_KEY ("vi$repeat_count", KEY_NAME ('6'),
X        "vi$repeat_count", vi$cmd_keys);
X    DEFINE_KEY ("vi$repeat_count", KEY_NAME ('7'),
X        "vi$repeat_count", vi$cmd_keys);
X    DEFINE_KEY ("vi$repeat_count", KEY_NAME ('8'),
X        "vi$repeat_count", vi$cmd_keys);
X    DEFINE_KEY ("vi$repeat_count", KEY_NAME ('9'),
X        "vi$repeat_count", vi$cmd_keys);
X    DEFINE_KEY ("vi$move_left", F12, "vi$move_left", vi$cmd_keys);
X    DEFINE_KEY ("vi$move_left", LEFT, "vi$move_left", vi$cmd_keys);
X    DEFINE_KEY ("vi$move_right", RIGHT, "vi$move_right", vi$cmd_keys);
X    DEFINE_KEY ("vi$move_up", UP, "vi$move_up", vi$cmd_keys);
X    DEFINE_KEY ("vi$move_down", DOWN, "vi$move_down", vi$cmd_keys);
X    DEFINE_KEY ("vi$move_left", DEL_KEY, "vi$move_left", vi$cmd_keys);
V    DEFINE_KEY ("vi$move_right", KEY_NAME (' '), "vi$move_right", vi$cmd_keys)
X;
X    DEFINE_KEY ("vi$ex_mode", DO, "vi$ex_mode", vi$cmd_keys);
X    DEFINE_KEY ("vi$ex_mode", KEY_NAME(':'), "vi$ex_mode", vi$cmd_keys);
X    DEFINE_KEY ("vi$_repeat_torf_back", KEY_NAME(','),
X        "vi$_repeat_torf_back", vi$cmd_keys);
X    DEFINE_KEY ("vi$_repeat_torf", KEY_NAME(';'),
X        "vi$_repeat_torf", vi$cmd_keys);
X    DEFINE_KEY ("vi$_search(1)", KEY_NAME('/'),
X        "vi$_search(1)", vi$cmd_keys);
X    DEFINE_KEY ("vi$_search(-1)", KEY_NAME('?'),
X        "vi$_search(-1)", vi$cmd_keys);
X    DEFINE_KEY ("vi$_eol", KEY_NAME('$'), "vi$_eol", vi$cmd_keys);
X    DEFINE_KEY ("vi$_bol", KEY_NAME('^'), "vi$_bol", vi$cmd_keys);
X    DEFINE_KEY ("vi$do_macro(vi$last_keys, 0)", KEY_NAME('.'),
X        "vi$do_macro(vi$last_keys, 0)", vi$cmd_keys);
X    DEFINE_KEY ("vi$macro", KEY_NAME('@'), "vi$macro", vi$cmd_keys);
V    DEFINE_KEY ("vi$repeat_subs", KEY_NAME('&'), "vi$repeat_subs", vi$cmd_keys
X);
X    DEFINE_KEY ("vi$region_filter", KEY_NAME('!'),
X        "vi$region_filter", vi$cmd_keys);
X
X    ! Define all of the insert-mode keys
X
X    vi$edit_keys := CREATE_KEY_MAP ("e_keys");
X
X    ! These maps are not really active, but the comment fields are used
X    ! during the execution of "vi$while_not_esc".
X
X    DEFINE_KEY ("vi$_dummy", F12, "bs", vi$edit_keys);
X    DEFINE_KEY ("vi$_dummy", PF1, "escape", vi$edit_keys);
X    DEFINE_KEY ("vi$_dummy", F11, "escape", vi$edit_keys);
X    DEFINE_KEY ("vi$_dummy", KEY_NAME (ASCII(27)), "escape", vi$edit_keys);
X    DEFINE_KEY ("vi$_dummy", KEY_NAME (ASCII(0)), "reinsert", vi$edit_keys);
X    DEFINE_KEY ("vi$_dummy", RET_KEY, "eol", vi$edit_keys);
X    DEFINE_KEY ("vi$_dummy", TAB_KEY, "tab", vi$edit_keys);
X    DEFINE_KEY ("vi$_dummy", CTRL_H_KEY, "bs", vi$edit_keys);
X    DEFINE_KEY ("vi$_dummy", CTRL_V_KEY, "vquote", vi$edit_keys);
X    DEFINE_KEY ("vi$_dummy", CTRL_W_KEY, "bword", vi$edit_keys);
X    DEFINE_KEY ("vi$_dummy", DEL_KEY, "bs", vi$edit_keys);
X
X    ! Define all of the delete mode mappings
X
X    vi$move_keys := CREATE_KEY_MAP ("m_keys");
X
X    DEFINE_KEY ("vi$downline(1)", RET_KEY, "vi$downline(1)", vi$move_keys);
X    DEFINE_KEY ("vi$right", KEY_NAME (" "), "vi$right", vi$move_keys);
X    DEFINE_KEY ("vi$eol", KEY_NAME("$"), "vi$eol", vi$move_keys);
X    DEFINE_KEY ("vi$to_marker", KEY_NAME ("'"), "vi$to_marker", vi$move_keys);
X    DEFINE_KEY ("vi$to_marker", KEY_NAME ("`"), "vi$to_marker", vi$move_keys);
X    DEFINE_KEY ("vi$first_no_space", KEY_NAME("^"),
X        "vi$first_no_space", vi$move_keys);
X    DEFINE_KEY ("vi$fol", KEY_NAME("0"), "vi$fol", vi$move_keys);
X    DEFINE_KEY ("vi$upline", KEY_NAME ("-"), "vi$upline", vi$move_keys);
X    DEFINE_KEY ("vi$downline(1)", KEY_NAME ("+"),
X        "vi$downline(1)", vi$move_keys);
X    DEFINE_KEY ("vi$search(1)", KEY_NAME ("/"), "vi$search(1)", vi$move_keys);
V    DEFINE_KEY ("vi$search(-1)", KEY_NAME ("?"), "vi$search(-1)", vi$move_keys
X);
X    DEFINE_KEY ("vi$match_brackets", KEY_NAME ("%"),
X        "vi$match_brackets", vi$move_keys);
X    DEFINE_KEY ("vi$full_word_move(-1)", KEY_NAME ("B"),
X        "vi$full_word_move(-1)", vi$move_keys);
X    DEFINE_KEY ("vi$word_move(-1)", KEY_NAME ("b"),
X        "vi$word_move(-1)", vi$move_keys);
X    DEFINE_KEY ("vi$_dummy", KEY_NAME ("c"),
X        "vi$_dummy", vi$move_keys);
X    DEFINE_KEY ("vi$word_end", KEY_NAME ("e"), "vi$word_end", vi$move_keys);
X    DEFINE_KEY ("vi$full_word_end", KEY_NAME ("E"),
X        "vi$full_word_end", vi$move_keys);
X    DEFINE_KEY ("vi$back_find_char(0)", KEY_NAME ("F"),
X        "vi$back_find_char(0)", vi$move_keys);
X    DEFINE_KEY ("vi$find_char(0)", KEY_NAME ("f"),
X        "vi$find_char(0)", vi$move_keys);
X    DEFINE_KEY ("vi$to_line (vi$active_count)", KEY_NAME ("G"),
X            "vi$to_line (vi$active_count)", vi$move_keys);
X    DEFINE_KEY ("vi$to_home", KEY_NAME ("H"), "vi$to_home", vi$move_keys);
X    DEFINE_KEY ("vi$left", KEY_NAME ("h"), "vi$left", vi$move_keys);
X    DEFINE_KEY ("vi$downline(1)", KEY_NAME ("j"),
X        "vi$downline(1)", vi$move_keys);
X    DEFINE_KEY ("vi$upline", KEY_NAME ("k"), "vi$upline", vi$move_keys);
X    DEFINE_KEY ("vi$right", KEY_NAME ("l"), "vi$right", vi$move_keys);
X    DEFINE_KEY ("vi$to_middle", KEY_NAME ("M"), "vi$to_middle", vi$move_keys);
X    DEFINE_KEY ("vi$to_last", KEY_NAME ("L"), "vi$to_last", vi$move_keys);
X    DEFINE_KEY ("vi$search_next(vi$last_search_dir)", KEY_NAME('n'),
X            "vi$search_next(vi$last_search_dir)", vi$move_keys);
X    DEFINE_KEY ("vi$search_next(-vi$last_search_dir)", KEY_NAME('N'),
X            "vi$search_next(-vi$last_search_dir)", vi$move_keys);
V    DEFINE_KEY ("vi$to_char(0)", KEY_NAME ("t"), "vi$to_char(0)", vi$move_keys
X);
X    DEFINE_KEY ("vi$back_to_char(0)", KEY_NAME ("T"),
X        "vi$back_to_char(0)", vi$move_keys);
X    DEFINE_KEY ("vi$word_move(1)", KEY_NAME ("w"),
X        "vi$word_move(1)", vi$move_keys);
X    DEFINE_KEY ("vi$full_word_move(1)", KEY_NAME ("W"),
X        "vi$full_word_move(1)", vi$move_keys);
X    DEFINE_KEY ("vi$downline", KEY_NAME(">"), "vi$downline(0)", vi$move_keys);
X    DEFINE_KEY ("vi$downline", KEY_NAME("<"), "vi$downline(0)", vi$move_keys);
X    DEFINE_KEY ("vi$downline(0)", KEY_NAME("d"),
X        "vi$downline(0)", vi$move_keys);
X    DEFINE_KEY ("vi$downline(0)", KEY_NAME("y"),
X        "vi$downline(0)", vi$move_keys);
X    DEFINE_KEY ("vi$downline(0)", KEY_NAME("!"),
X        "vi$downline(0)", vi$move_keys);
X    DEFINE_KEY ("vi$to_column", KEY_NAME ('|'), "vi$to_column", vi$move_keys);
X    DEFINE_KEY ("vi$repeat_torf", KEY_NAME(';'),
X        "vi$repeat_torf", vi$move_keys);
X    DEFINE_KEY ("vi$repeat_torf_back", KEY_NAME(','),
X        "vi$repeat_torf_back", vi$move_keys);
X    DEFINE_KEY ("vi$paragraph (1)", KEY_NAME ('}'),
X        "vi$paragraph (1)", vi$move_keys);
X    DEFINE_KEY ("vi$section (1)", KEY_NAME (']'),
X        "vi$section (1)", vi$move_keys);
X    DEFINE_KEY ("vi$end_sentence", KEY_NAME (')'),
X        "vi$end_sentence", vi$move_keys);
X    DEFINE_KEY ("vi$paragraph (-1)", KEY_NAME ('{'),
X        "vi$paragraph (-1)", vi$move_keys);
X    DEFINE_KEY ("vi$section (-1)", KEY_NAME ('['),
X        "vi$section (-1)", vi$move_keys);
X    DEFINE_KEY ("vi$begin_sentence", KEY_NAME ('('),
X        "vi$begin_sentence", vi$move_keys);
X
XENDPROCEDURE;
X
X!
X!   This procedure is called by the CTRL-` keystroke to swap the current
X!   buffer with the previous one.
X!
XPROCEDURE vi$move_prev_buf
X    LOCAL
X        outf,
X        buf;
X
X    IF (vi$last_mapped = 0) OR
X                            (GET_INFO (vi$last_mapped, "TYPE") <> BUFFER) THEN
X        MESSAGE ("No alternate buffer!");
X        RETURN;
X    ENDIF;
X    buf := vi$last_mapped;
X    vi$check_auto_write;
X    MAP (CURRENT_WINDOW, buf);
X    vi$set_status_line (CURRENT_WINDOW);
X    vi$pos_in_middle (MARK (NONE));
X    outf := GET_INFO (CURRENT_BUFFER, "OUTPUT_FILE");
X    IF outf = 0 THEN
X        outf := GET_INFO (CURRENT_BUFFER, "NAME");
X    ENDIF;
X    MESSAGE ('"'+outf+'"');
XENDPROCEDURE;
X
X!
X!   This procedure is used to return the current mark in the buffer, after
X!   moving to the mark passed.  This routine is used by the majority of the
X!   procedures that perform movement, and then return the location they
X!   stopped at, but do not change the current location in the buffer.
X!
XPROCEDURE vi$retpos (pos)
X    LOCAL
X        endpos;
X
X    ON_ERROR
X    ENDON_ERROR
X
X    endpos := MARK (NONE);
X
X    ! If the marker is zero, then there is no way to position to it.
X
X    IF (pos <> 0) THEN
X        POSITION (pos);
X    ENDIF;
X    RETURN (endpos);
XENDPROCEDURE;
X
X!
X!   This procedure is called whenever ESCAPE is pressed while in command mode.
X!   The current active count should be zeroed, and possibly other things.
X!
XPROCEDURE vi$on_escape
X    vi$active_count := 0;
X    vi$beep;
XENDPROCEDURE;
X
X!
X!
X!
X!
XPROCEDURE vi$do_help (init_command)
X    LOCAL
X        buf,
X        win;
X
X    buf := CURRENT_BUFFER;
X    MAP (info_window, show_buffer);
X    HELP_TEXT ("vi$root:[doc]vi.hlb","VI " + init_command,ON,show_buffer);
X    UNMAP (info_window);
X    POSITION (buf);
XENDPROCEDURE;
X
X!
X!   This is the main processing loop, this function should never be exited.
X!   This means that the TPU "ABORT" builtin can not be used anywhere.
X!
XPROCEDURE vi$command_mode (l_key)
X    LOCAL
X        key,
X        last_len,
X        win,
X        cwin,
X        pos,
X        prog;
X
X    IF (NOT vi$min_update) THEN
X        UPDATE (CURRENT_WINDOW);
X    ENDIF;
X
X    ! Get the key to process.
X
X    key := l_key;
X    vi$push_a_key (key);
X    vi$last_key := key;
X
X    ! Initialize macro level counter.
X
X    vi$m_level := 0;
X
X    ! Set up so that 'U' works.
X
X    pos := MARK (NONE);
X    MOVE_HORIZONTAL (-CURRENT_OFFSET);
X    IF (vi$undo_line_mark <> MARK (NONE)) THEN
X        vi$undo_line_mark := MARK (NONE);
X        vi$undo_line_str := vi$current_line;
X    ENDIF;
X    POSITION (pos);
X
X    ! Get that keys program.
X
X    prog := LOOKUP_KEY (KEY_NAME (key), PROGRAM, vi$cmd_keys);
X
X    ! If prog = 0 then key is undefined, so ignore it.
X
X    IF (prog <> 0) THEN
X
X        vi$command_type := VI$OTHER_TYPE;
X
X        ! Otherwise, do the program for that key.
X
X        EXECUTE (prog);
X
X        ! If this is a key that can change the buffer, then
X        ! save the sequence of keys so that '.' causes them to
X        ! be repeated.
X
X        IF (INDEX (vi$dot_keys, ASCII (key)) <> 0) THEN
X            vi$copy_keys (vi$last_keys, vi$cur_keys);
X        ENDIF;
X    ENDIF;
X
X    ! Make sure we are not past end of line or at EOB.
X
X    vi$check_rmarg;
X
X    IF (INDEX ("0123456789", ASCII (key)) = 0) OR (vi$active_count = 0) THEN
X        ERASE (vi$cur_keys);
X    ENDIF;
XENDPROCEDURE;
X
X!
X!   Perform a macro command string that is either a string, or a buffer
X!   containing KEY_NAME values (as in execution of the '.' command).
X!
XPROCEDURE vi$do_macro (commands, save_buffer)
X    LOCAL
X        typ,
X        old_global,
X        pos,
X        key,
X        prog;
X
X    IF (vi$m_level > 30) THEN
X        MESSAGE ("Infinite loop detected in key macro sequence!");
X        RETURN;
X    ENDIF;
X    vi$m_level := vi$m_level + 1;
X
X    pos := MARK (NONE);
X
X    ! If "commands" is a string then we must generate a buffer to
X    ! place the commands into so that they can be read with "vi$read_a_key".
X
X    IF (GET_INFO (commands, "TYPE") = STRING) THEN
X        IF (vi$tmp_key_buf = 0) THEN
X            vi$tmp_key_buf := vi$init_buffer ("$$tmp_key_buf$$", "");
X        ELSE
X            ERASE (vi$tmp_key_buf);
X        ENDIF;
X
X        IF vi$tmp_key_buf = 0 THEN
X            vi$message ("Can't do key macro: "+commands);
X            RETURN;
X        ENDIF;
X
X        vi$str_to_keybuf (commands, vi$tmp_key_buf);
X        vi$insert_macro_keys (vi$tmp_key_buf);
X    ELSE
X        vi$insert_macro_keys (commands);
X    ENDIF;
X
X    POSITION (pos);
X
X    IF vi$undo_map THEN
X        old_global := vi$in_global;
X        vi$in_global := 0;
X        IF (save_buffer AND (NOT old_global)) THEN
X            vi$save_for_undo (CURRENT_BUFFER, VI$LINE_MODE, 1);
X            vi$in_global := 1;
X        ELSE
X            IF old_global THEN
X                vi$in_global := 1;
X            ENDIF;
X        ENDIF;
X    ENDIF;
X
X    LOOP
X
X        ! Stop when all levels of macro are completed.
X
X        EXITIF (vi$key_buf = 0);
X        key := vi$read_a_key;
X
X        ! Get that keys program.
X
X        prog := LOOKUP_KEY (KEY_NAME (key), PROGRAM, vi$cmd_keys);
X
X        ! If prog = 0 then key is undefined, so ignore it.
X
X        IF (prog <> 0) THEN
X
X            ! Otherwise, do the program for that key.
X
X            EXECUTE (prog);
X        ELSE
X            MESSAGE ("Key '"+key+"' is undefined!");
X            vi$abort (0);
X        ENDIF;
X    ENDLOOP;
X
X    IF (vi$in_global) THEN
X        vi$undo_start := BEGINNING_OF (CURRENT_BUFFER);
X        vi$undo_end := END_OF (CURRENT_BUFFER);
X        vi$in_global := old_global;
X    ENDIF;
XENDPROCEDURE;
X
X!
X!   This function handles the macro capability that allows the text in
X!   a named or numbered buffer to be executed as a sequence of commands
X!   by type an '@' and then the letter or number indicating the buffer to
X!   execute the contents of.
X!
XPROCEDURE vi$macro
X    LOCAL
X        line,
X        buf_name,
X        bpos,
X        cnt,
X        ccnt,
X        pos,
X        buf,
X        mode,
X        ch;
X
X    IF (vi$m_level > 30) THEN
X        MESSAGE ("Infinite loop detected in macro key sequence!");
X        RETURN;
X    ENDIF;
X    vi$m_level := vi$m_level + 1;
X
X    ch := vi$read_a_key;
X
X    IF (INDEX ("123456789", ASCII(ch)) <> 0) THEN
X
X        ! Selected a deletion buffer.
X
X        buf_name := "vi$del_buf_"+ASCII(ch);
X    ELSE
X        IF (INDEX (vi$_letter_chars, ASCII(ch)) <> 0) THEN
X
X            ! Selected a named buffer.
X
X            IF (INDEX (vi$_upper_chars, ASCII(ch)) <> 0) THEN
X                ch := SUBSTR (vi$_lower_chars,
X                            INDEX (vi$_upper_chars, ASCII(ch)), 1);
X            ENDIF;
X
X            buf_name := "vi$ins_buf_"+ASCII(ch);
X        ELSE
X            vi$message ("Invalid buffer!");
X            RETURN;
X        ENDIF;
X    ENDIF;
X
X    vi$global_var := 0;
X    EXECUTE (COMPILE ("vi$global_var := "+buf_name+";"));
X    buf := vi$global_var;
X    IF (buf = 0) THEN
X        vi$message ("There is no text in that buffer!");
X        RETURN;
X    ENDIF;
X
X    pos := MARK (NONE);
X    POSITION (BEGINNING_OF (buf));
X
X    !  Skip the buffer mode indicator.
X
X    mode := INT (vi$current_line);
X    MOVE_VERTICAL (1);
X    cnt := GET_INFO (CURRENT_BUFFER, "RECORD_COUNT") - 2;
X    ccnt := 0;
X
X    LOOP
X        line := vi$current_line;
X
X        IF (ccnt = cnt) THEN
X            IF mode = VI$LINE_MODE THEN
X                line := line + ASCII (13);
X            ENDIF;
X        ELSE
X            line := line + ASCII (13);
X        ENDIF;
X
X        ccnt := ccnt + 1;
X        bpos := MARK (NONE);
X        POSITION (pos);
X        vi$do_macro (line, 1);
X
X        EXITIF (ccnt = cnt);
X
X        pos := MARK (NONE);
X        POSITION (bpos);
X        MOVE_VERTICAL (1);
X    ENDLOOP;
XENDPROCEDURE;
X
X!
X!   This procedure handles the operation of the U command.  U undoes all
X!   changes performed on a line, providing the cursor has not left that
X!   line.
X!
XPROCEDURE vi$undo_one_line
X    LOCAL
X        pos;
X
X    pos := MARK (NONE);
X    MOVE_HORIZONTAL (-CURRENT_OFFSET);
X    IF (MARK (NONE) = vi$undo_line_mark) THEN
X        ERASE_LINE;
X        COPY_TEXT (vi$undo_line_str);
X        SPLIT_LINE;
X        MOVE_VERTICAL (-1);
X        vi$kill_undo;
X        vi$undo_end := 0;
X    ELSE
X        vi$undo_line_mark := 0;
X    ENDIF;
XENDPROCEDURE;
X
X!
X!   This procedure takes a range or string of data, and squirrels it away
X!   to be restored when an undo operation is performed.
X!
XPROCEDURE vi$save_for_undo (undo_data, btype, save_line_info)
X    LOCAL
X        pos;
X
X    pos := MARK (NONE);
X
X    IF (vi$in_global) THEN
X        RETURN;
X    ENDIF;
X
X    IF (save_line_info) THEN
X        vi$undo_line := vi$cur_line_no;
X        vi$undo_offset := CURRENT_OFFSET;
X    ELSE
X        vi$undo_line := 0;
X    ENDIF;
X
X    IF vi$undo_buffer = 0 THEN
X        vi$undo_buffer := vi$init_buffer ("$$vi$undo_buffer$$", "");
X        IF vi$undo_buffer = 0 THEN
X            vi$message ("Error creating undo buffer!");
X            RETURN;
X        ENDIF;
X    ENDIF;
X
X    vi$type2buf (STR (btype), vi$undo_buffer);
X    vi$cp2buf (undo_data, vi$undo_buffer);
X
X    vi$undo_valid := 1;
X
X    POSITION (pos);
XENDPROCEDURE;
X
X!
X!   Disallow the data last saved with vi$save_for_undo() from being restored
X!   during an undo operation.
X!
XPROCEDURE vi$kill_undo
X    IF (NOT vi$in_global) THEN
X        vi$undo_valid := 0;
X        vi$undo_line := 0;
X    ENDIF;
XENDPROCEDURE;
X
X!
X!   Perform the operation of undoing the last change.  This operation is
X!   actually comprised of 3 separate operations.  The first operation is
X!   to restore any text saved by vi$save_for_undo().  The next operation is
X!   to vi$save_for_undo() any text delimited by vi$undo_start and vi$undo_end.
X!   vi$undo_start marks the location where step 1 is performed.  vi$undo_end
X!   determines whether or not there is text to save and then delete.  If
X!   it has a non-zero value, then the range delimited by it and vi$undo_start
X!   is saved (using vi$save_for_undo()), and then deleted.
X!
XPROCEDURE vi$perform_undo
X    LOCAL
X        done_pos,
X        cbuf,
X        pos,
X        undo_line,
X        undo_offset,
X        cline,
X        coff,
X        btype,
X        errno,
X        undo_mode,
X        saved_text,
X        new_start,
X        new_end,
X        era_range;
X
X    vi$new_offset := 1;
X    new_start := 0;
X    cline := vi$cur_line_no;
X    coff := CURRENT_OFFSET;
X    undo_line := vi$undo_line;
X    undo_offset := vi$undo_offset;
X
X    IF (GET_INFO (vi$undo_start, "BUFFER") <> CURRENT_BUFFER) OR
X            ((NOT vi$undo_valid) AND (vi$undo_end = 0)) THEN
X        vi$beep;
X        RETURN;
X    ENDIF;
X
X    IF (vi$undo_valid) THEN
X        cbuf := CURRENT_BUFFER;
X
X        POSITION (BEGINNING_OF (vi$undo_buffer));
X        undo_mode := INT (vi$current_line);
X        ERASE_LINE;
X
X        POSITION (vi$undo_start);
X
X        IF MARK (NONE) = BEGINNING_OF (CURRENT_BUFFER) THEN
X            new_start := 1;
X        ELSE
X            MOVE_HORIZONTAL (-1);
X            new_start := MARK (NONE);
X            MOVE_HORIZONTAL (1);
X        ENDIF;
X
X        SET (INSERT, CURRENT_BUFFER);
X        COPY_TEXT (vi$undo_buffer);
X
X        APPEND_LINE;
X        MOVE_HORIZONTAL (-1);
X        new_end := MARK (NONE);
X
X        POSITION (BEGINNING_OF (vi$undo_buffer));
X        COPY_TEXT (STR (undo_mode));
X        SPLIT_LINE;
X
X        POSITION (new_end);
X    ENDIF;
X
X    ! Use flag to determine whether or not to kill buffer contents.
X
X    saved_text := 0;
X
X    IF (vi$undo_start <> 0) AND (vi$undo_end <> 0) THEN
X        saved_text := 1;
X        pos := MARK (NONE);
X
X        POSITION (vi$undo_end);
X        IF (CURRENT_OFFSET <> 0) THEN
X            btype := VI$IN_LINE_MODE;
X        ELSE
X            btype := VI$LINE_MODE;
X        ENDIF;
X
X        POSITION (pos);
X
X        era_range := CREATE_RANGE (vi$undo_start, vi$undo_end, NONE);
X
X        IF era_range <> 0 THEN
X            POSITION (vi$undo_start);
X            vi$save_for_undo (era_range, btype, 1);
X            ERASE (era_range);
X        ENDIF;
X    ENDIF;
X
X    IF (GET_INFO (new_start, "TYPE") <> INTEGER) THEN
X        POSITION (new_start);
X        vi$move_horizontal (1);
X        vi$undo_start := MARK (NONE);
X        vi$undo_end := new_end;
X    ELSE
X        IF new_start = 1 THEN
X            vi$undo_start := BEGINNING_OF (CURRENT_BUFFER);
X            vi$undo_end := new_end;
X        ELSE
X            vi$undo_end := 0;
X        ENDIF;
X    ENDIF;
X
X    IF (saved_text = 0) THEN
X        vi$kill_undo;
X    ENDIF;
X
X    IF (vi$undo_start <> 0) THEN
X        POSITION (vi$undo_start);
X    ENDIF;
X
X    ! If undoing a macro then reposition to the place where we started.
X
X    IF (undo_line <> 0) THEN
X        vi$move_to_line (undo_line);
X        vi$move_horizontal (undo_offset);
X        vi$pos_in_middle (MARK (NONE));
X        vi$undo_line := undo_line;
X        vi$undo_offset := undo_offset;
X    ENDIF;
X
X    vi$message ("");
XENDPROCEDURE;
X
X!
X!   This function performs the operations associated with the ^Y and ^E
X!   keystrokes.
X!
XPROCEDURE vi$pull_push_line (direction)
X
X    LOCAL
X        currow,
X        limit,
X        n_lines,
X        pos;
X
X    ON_ERROR
X        ! Ignore "ATTEMPT to move past TOP/BOTTOM of buffer"
X    ENDON_ERROR;
X
X    ! Get the number of lines to move.
X
X    n_lines := vi$cur_active_count * direction;
X
X    ! Mark the destination position for the case where we are at the top or
X    ! bottom of the window.
X
X    MOVE_VERTICAL (n_lines);
X    pos := MARK (NONE);
X
X    ! Return to the old position.
X
X    MOVE_VERTICAL (-n_lines);
X
X    ! Get the current screen row
X
X    currow := GET_INFO (CURRENT_WINDOW, "CURRENT_ROW");
X
X    ! Get the proper border value based on the direction.
X
X    IF (n_lines < 0) THEN
X        limit := GET_INFO (CURRENT_WINDOW, "VISIBLE_BOTTOM");
X    ELSE
X        limit := GET_INFO (CURRENT_WINDOW, "VISIBLE_TOP");
X    ENDIF;
X
X    ! If we are NOT at the top or bottom, then the current row is the dest.
X
X    IF (n_lines > 0) THEN
X        IF (currow - limit) >= n_lines THEN
X            pos := MARK (NONE);
X        ENDIF;
X    ELSE
X        IF vi$abs (currow - limit) >= vi$abs (n_lines) THEN
X            pos := MARK (NONE);
X        ENDIF;
X    ENDIF;
X
X    ! Scroll the window.  If the scroll fails, then move the cursor.
X
X    IF (SCROLL (CURRENT_WINDOW, n_lines) <> n_lines) THEN
X        MOVE_VERTICAL (n_lines);
X    ELSE
X
X        ! Otherwise the position we wanted is visible, so move there.
X
X        POSITION (pos);
X        IF (n_lines < 0) AND ((currow - limit) > n_lines) THEN
X            MOVE_VERTICAL (limit - currow);
X        ENDIF;
X    ENDIF;
XENDPROCEDURE;
X
X!
X!   Move to the location indicated by a '|' command.
X!
XPROCEDURE vi$_to_column
X    vi$position (vi$to_column, 0);
XENDPROCEDURE;
X
X!
X!   Return the marker indicating the column selected by vi$active_count
X!
XPROCEDURE vi$to_column
X    LOCAL
X        pos,
X        act_count;
X
X    act_count := vi$cur_active_count;
X    pos := MARK (NONE);
X
X    IF (act_count <= LENGTH (vi$current_line)) THEN
X        pos := MARK (NONE);
X        MOVE_HORIZONTAL (act_count - CURRENT_OFFSET - 1);
X        RETURN (vi$retpos (pos));
X    ENDIF;
X    RETURN (0);
XENDPROCEDURE;
X
X!
X!   Perform the operations associated with 'ZZ' (write and exit) command.
X!
XPROCEDURE vi$_ZZ
X     LOCAL
X        prcnam,
X        ans,
X        cur_buf,
X        buf,
X        errno;
X
X    ON_ERROR
X        errno := ERROR;
X        IF errno = TPU$_NOPARENT THEN
X
X            !  Use vi$quit so that buffers not written will not be written
X            !  automatically.
X
X            vi$quit;
X        ENDIF;
X    ENDON_ERROR;
X
X    IF (vi$read_a_key = KEY_NAME ('Z')) THEN
X        cur_buf := CURRENT_BUFFER;
X
X        vi$message ("");
X
X        IF (GET_INFO (cur_buf, "MODIFIED")) AND
X                            (GET_INFO (cur_buf, "NO_WRITE") = 0) AND
X                            (GET_INFO (cur_buf, "SYSTEM") = 0) THEN
X
X            vi$message ("Writing out """+GET_INFO (cur_buf, "NAME")+"""");
X            WRITE_FILE (cur_buf);
X        ENDIF;
X
X        buf := GET_INFO (BUFFERS, "FIRST");
X        LOOP
X            EXITIF (buf = 0);
X            IF (GET_INFO (buf, "MODIFIED")) AND
X                                (GET_INFO (buf, "NO_WRITE") = 0) AND
X                                (GET_INFO (buf, "SYSTEM") = 0) THEN
X
V                ans := vi$read_line ("Write """+GET_INFO (buf, "NAME")+"""? ")
X;
X
X                CHANGE_CASE (ans, LOWER);
X                IF SUBSTR (ans, 1, 1) = "y" THEN
X                    vi$message ("Writing out """+GET_INFO (buf, "NAME")+"""");
X                    WRITE_FILE (buf);
X                ENDIF;
X            ENDIF;
X            buf := GET_INFO (BUFFERS, "NEXT");
X        ENDLOOP;
X
X        IF (vi$get_attach_parm ("TPU$NOSUBPROC") = " ") THEN
X            prcnam := vi$get_attach_parm ("TPU$ATTACH_NAME");
X            vi$pasthru_off;
X            IF (prcnam = " ") THEN
X                ATTACH;
X            ELSE
X                ATTACH (prcnam);
X            ENDIF;
X            vi$pasthru_on;
X            vi$process_args;
X        ELSE
X            vi$do_quit ("q", "q");
X        ENDIF;
X    ENDIF;
X
X    vi$kill_undo;
X    vi$undo_end := 0;
X    vi$active_count := 0;
XENDPROCEDURE;
X
X!
X!   Process the job logical names that are used to pass parameters between
X!   the parent process and the editor.
X!
XPROCEDURE vi$process_args
X
X    LOCAL
X        buf,
X        bufn,
X        errno,
X        startup_cmd,
X        new_output,
X        find_text,
X        new_lineno,
X        input_file;
X
X    ON_ERROR
X
X        errno := ERROR;
X
X        SET (SUCCESS, ON);
X        vi$system_message (errno);
X        RETURN;
X
X    ENDON_ERROR;
X
X    startup_cmd := vi$get_attach_parm ("TPU$NEWCMD");
X
X    IF startup_cmd = " " THEN
X        input_file := vi$get_attach_parm ("TPU$ARGS");
X
X        IF (input_file <> " ") THEN
X            new_output := vi$get_attach_parm ("TPU$OUTPUT");
X
X            !  When a file is specified, and a new output file is also
X            !  specified, then we will attempt to erase any existing
X            !  buffer's contents so that MAIL will actually be able to
X            !  be used over and over during an editor's life.
X
X            IF (new_output <> " ") THEN
X                bufn := FILE_PARSE (input_file,"","",NAME) +
X                        FILE_PARSE (input_file,"","",TYPE);
X                buf := vi$find_buffer_by_name (bufn);
X                IF buf <> 0 THEN
X                    IF (GET_INFO (buf, "MODIFIED") = 0) OR
X                                        GET_INFO (buf, "NO_WRITE") THEN
X                        ERASE (buf);
X                    ELSE
X                        MESSAGE (
X                "Buffer is modified, original contents not destroyed!");
X                    ENDIF;
X                ENDIF;
X            ENDIF;
X
X            vi$get_file (input_file);
X
X            IF (new_output <> " ") THEN
X                SET (OUTPUT_FILE, CURRENT_BUFFER, new_output);
X                vi$status_lines (CURRENT_BUFFER);
X
X                !  Set the buffer to be modified so that the file will
X                !  be written on exit.
X
X                SPLIT_LINE;
X                APPEND_LINE;
X            ENDIF;
X        ENDIF;
X    ELSE
X        new_output := vi$get_attach_parm ("TPU$OUTPUT");
X        IF (new_output <> " ") THEN
X            SET (OUTPUT, CURRENT_BUFFER, new_output);
X            vi$status_lines (CURRENT_BUFFER);
X
X            !  Set the buffer to be modified so that the file will
X            !  be written on exit.
X
X            SPLIT_LINE;
X            APPEND_LINE;
X        ENDIF;
X
X        vi$do_cmd_line (startup_cmd);
X    ENDIF;
X
X    new_lineno := vi$get_attach_parm ("TPU$LINE");
X
X    IF (new_lineno = " ") THEN
X        find_text := vi$get_attach_parm ("TPU$SEARCH");
X        IF (find_text <> " ") THEN
X            IF SUBSTR (find_text, 1, 1) = "/" THEN
X                SET (FORWARD, CURRENT_BUFFER);
X                vi$last_search_dir := 1;
X            ELSE
X                SET (REVERSE, CURRENT_BUFFER);
X                vi$last_search_dir := -1;
X            ENDIF;
X            vi$search_string := SUBSTR (find_text, 2, LENGTH (find_text)-1);
X            vi$position (vi$find_str (vi$search_string, 0), 1);
X        ENDIF;
X    ELSE
X        vi$position (vi$to_line (INT (new_lineno)), 1);
X    ENDIF;
XENDPROCEDURE;
X
X!
X!  A special procedure to trap any errors in translating logical names, and
X!  just ignore them, and return a " " string on error.
X!
XPROCEDURE vi$get_attach_parm (parm)
X    LOCAL
X        rstr,
X        errno,
X        blank;
X
X    ON_ERROR
X        errno := ERROR;
X        RETURN (blank);
X    ENDON_ERROR;
X
X    blank := " ";
X
X    rstr := CALL_USER (vi$cu_trnlnm_job, parm);
X    RETURN (rstr);
XENDPROCEDURE;
X
X!
X!   Perform the operations associated with the 'z' key command.
X!
XPROCEDURE vi$_z_move
X
X    LOCAL
X        pos,
X        crow,
X        old_scroll,
X        scrl_value,
X        scroll_top,
X        scroll_bottom,
X        scroll_amount,
X        act_count,
X        done,
X        next_key,
X        cur_window;
X
X    vi$active_count := 0;
X    LOOP
X        next_key := vi$read_a_key;
X        EXITIF INDEX (vi$_numeric_chars, ASCII (next_key)) = 0;
X        vi$active_count := vi$active_count * 10 +
X                                            INT (ASCII (KEY_NAME (next_key)));
X    ENDLOOP;
X
X    IF (next_key = F11) OR ((next_key <> RET_KEY) AND
X                    (next_key <> KEY_NAME ('.')) AND
X                    (next_key <> KEY_NAME ('+')) AND
X                    (next_key <> KEY_NAME ('-'))) THEN
X        vi$active_count := 0;
X        RETURN;
X    ENDIF;
X
X    IF (vi$active_count > 0) AND (next_key <> KEY_NAME ('.')) THEN
X        vi$old_place := MARK (NONE);
X        pos := vi$to_line (vi$active_count);
X    ELSE
X        pos := MARK (NONE);
X    ENDIF;
X
X    cur_window := CURRENT_WINDOW;
X    scroll_top    := GET_INFO (cur_window, "SCROLL_TOP");
X    scroll_bottom := GET_INFO (cur_window, "SCROLL_BOTTOM");
X    scroll_amount := GET_INFO (cur_window, "SCROLL_AMOUNT");
X
X    done := 0;
X
X    IF next_key = KEY_NAME ('-') THEN
X        scrl_value := (GET_INFO (cur_window, "VISIBLE_LENGTH") / 2);
X
X        SET (SCROLLING, cur_window, ON, scrl_value, scrl_value, scrl_value);
X
X        POSITION (pos);
X        vi$update (cur_window);
X        done := 1;
X    ELSE
X        IF next_key = KEY_NAME ('+') THEN
X            scrl_value := GET_INFO (cur_window, "VISIBLE_LENGTH");
V            SET (SCROLLING, cur_window, ON, scrl_value, scrl_value, scrl_value
X);
X            POSITION (pos);
X            vi$update (cur_window);
X
X            done := 1;
X        ELSE
X            IF next_key = RET_KEY THEN
X                scrl_value := GET_INFO (cur_window, "VISIBLE_LENGTH");
X                SET (SCROLLING, cur_window, ON, 0, scrl_value, scrl_value);
X                POSITION (pos);
X                vi$update (cur_window);
X
X                done := 1;
X            ELSE
X                IF next_key = KEY_NAME ('.') THEN
X                    vi$do_set_window (vi$cur_active_count);
X                    vi$pos_in_middle (MARK (NONE));
X                    MESSAGE ("");
X                    done := 0;
X                ENDIF;
X            ENDIF;
X        ENDIF;
X    ENDIF;
X
X    IF (done) THEN
X        SET (SCROLLING, cur_window, ON, scroll_top, scroll_bottom,
V                                                                scroll_amount)
X;
X    ENDIF;
XENDPROCEDURE;
X
X!
X!   Perform the 'r' command
X!
XPROCEDURE vi$_replace_char
X
X    LOCAL
X        act_cnt,
X        key,
X        pos;
X
X    ON_ERROR;
X        POSITION (pos);
X        RETURN;
X    ENDON_ERROR;
X
X    pos := MARK (NONE);
X    act_cnt := vi$cur_active_count;
X    IF (vi$show_mode) THEN
X        vi$mess_select (BOLD);
X        MESSAGE (FAO ("!7*  REPLACE"));
X        vi$mess_select (REVERSE);
X    ENDIF;
X    key := vi$read_a_key;
X
X    IF (key = F11) THEN
X        IF (vi$show_mode) THEN
X            MESSAGE ("");
$ GoSub Convert_File
$ Exit