home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume1 / 8710 / vms-vi / 10 < prev    next >
Encoding:
Internet Message Format  |  1990-07-13  |  36.6 KB

  1. Path: uunet!husc6!necntc!ncoast!allbery
  2. From: gregg@a.cs.okstate.edu@mandrill.CWRU.Edu (Gregg Wonderly)
  3. Newsgroups: comp.sources.misc
  4. Subject: VI in TPU part 10/13
  5. Message-ID: <4859@ncoast.UUCP>
  6. Date: 13 Oct 87 02:54:43 GMT
  7. Sender: allbery@ncoast.UUCP
  8. Organization: Oklahoma State Univ., Stillwater
  9. Lines: 1504
  10. Approved: allbery@ncoast.UUCP
  11. X-Archive: comp.sources.misc/8710/vms-vi/10
  12.  
  13. $ WRITE SYS$OUTPUT "Creating ""VI.9"""
  14. $ CREATE VI.9
  15. $ DECK/DOLLARS=$$EOD$$
  16.     vi$active_count := 0;
  17. ENDPROCEDURE;
  18.  
  19. !
  20. !   Move to line in file.  vi$active_count holds the line number to GO TO.
  21. !   If VI$ACTIVE_COUNT is zero, we move to the end of the file.
  22. !
  23. PROCEDURE vi$to_line (cnt)
  24.  
  25.     LOCAL
  26.         this_pos,           ! Saved position in case of botch
  27.         last_line,          ! Last line in the buffer
  28.         win_len;            ! Length of CURRENT_WINDOW
  29.  
  30.     ON_ERROR
  31.         vi$message (FAO ("No such line: !SL", VI$ACTIVE_COUNT));
  32.         POSITION (this_pos);
  33.         cnt := 0;
  34.         RETURN;
  35.     ENDON_ERROR;
  36.  
  37.     this_pos := MARK(NONE);
  38.     MOVE_HORIZONTAL (-CURRENT_OFFSET);
  39.     vi$start_pos := MARK (NONE);
  40.  
  41.     IF cnt = 0 THEN
  42.         POSITION (END_OF (CURRENT_BUFFER));
  43.     ELSE
  44.         last_line := GET_INFO (CURRENT_BUFFER, "RECORD_COUNT");
  45.  
  46.         IF cnt > last_line THEN
  47.             IF last_line > 0 THEN
  48.                 vi$message ("Not that many lines in buffer");
  49.                 POSITION (this_pos);
  50.                 RETURN (0);
  51.             ENDIF;
  52.         ELSE
  53.             POSITION (BEGINNING_OF (CURRENT_BUFFER));
  54.             win_len := GET_INFO (CURRENT_WINDOW, "VISIBLE_LENGTH");
  55.             MOVE_VERTICAL (cnt - 1);
  56.             cnt := 0;
  57.         ENDIF;
  58.     ENDIF;
  59.  
  60.     IF (MARK (NONE) <> END_OF (CURRENT_BUFFER)) THEN
  61.         MOVE_VERTICAL (1);
  62.         MOVE_HORIZONTAL (-1);
  63.         vi$new_endpos := MARK (NONE);
  64.         MOVE_HORIZONTAL (-CURRENT_OFFSET);
  65.     ENDIF;
  66.  
  67.     vi$yank_mode := VI$LINE_MODE;
  68.     RETURN (vi$retpos (this_pos));
  69. ENDPROCEDURE;
  70.  
  71. !
  72. !   Set a marker in the current buffer.
  73. !
  74. PROCEDURE vi$_set_mark
  75.  
  76.     LOCAL
  77.         mark_char,
  78.         mark_name,
  79.         key_pressed;
  80.  
  81.     key_pressed := vi$read_a_key;
  82.  
  83.     mark_char := ASCII (key_pressed);
  84.     IF (INDEX (vi$_lower_chars, mark_char) <> 0) THEN
  85.         mark_name := "vi$mark_" + mark_char;
  86.         EXECUTE (COMPILE (mark_name + " := MARK(NONE);"));
  87.     ELSE
  88.         vi$MESSAGE ("Invalid marker key!");
  89.     ENDIF;
  90.  
  91. ENDPROCEDURE;
  92.  
  93. !
  94. !   Function mapped to "'" and "`".
  95. !
  96. PROCEDURE vi$_go_to_marker
  97.     IF (vi$position (vi$to_marker, 1) <> 0) THEN
  98.         vi$pos_in_middle (MARK (NONE));
  99.     ENDIF;
  100. ENDPROCEDURE;
  101.  
  102. !
  103. !   Function to move the marker indicated by the next keystroke.
  104. !
  105. PROCEDURE vi$to_marker
  106.  
  107.     LOCAL
  108.         mode_key,
  109.         pos,
  110.         mark_name,
  111.         mark_char,
  112.         key_pressed;
  113.  
  114.     ON_ERROR;
  115.         vi$message ("Mark not set!");
  116.         RETURN (0);
  117.     ENDON_ERROR;
  118.  
  119.     pos := MARK (NONE);
  120.     mode_key := vi$last_key;
  121.     key_pressed := vi$read_a_key;
  122.  
  123.     mark_char := ASCII (key_pressed);
  124.     IF (INDEX (vi$_lower_chars+"'`", mark_char) = 0) THEN
  125.         vi$MESSAGE ("Invalid marker key!");
  126.         RETURN (0);
  127.     ENDIF;
  128.  
  129.     IF (key_pressed <> F11) THEN
  130.         IF (mark_char = "'") OR (mark_char = "`") THEN
  131.             IF (vi$old_place <> 0) THEN
  132.                 IF (GET_INFO (vi$old_place, "BUFFER") = CURRENT_BUFFER) THEN
  133.                     POSITION (vi$old_place);
  134.                 ELSE
  135.                     MESSAGE ("Previous place not in this buffer!");
  136.                     RETURN (0);
  137.                 ENDIF;
  138.             ELSE
  139.                 MESSAGE ("No previous mark to return to!");
  140.                 RETURN (0);
  141.             ENDIF;
  142.         ELSE
  143.             mark_name := "vi$mark_" + mark_char;
  144.             EXECUTE (COMPILE ("vi$global_mark := "+mark_name+";"));
  145.  
  146.             IF (vi$global_mark <> 0) AND (GET_INFO (vi$global_mark, "BUFFER") =
  147.                                                             CURRENT_BUFFER) THE
  148. N
  149.                 POSITION (vi$global_mark);
  150.                 vi$yank_mode := VI$LINE_MODE;
  151.             ELSE
  152.                 vi$message ("Invalid mark for this buffer!");
  153.                 RETURN (0);
  154.             ENDIF;
  155.         ENDIF;
  156.  
  157.         IF ASCII (mode_key) = "'" THEN
  158.             MOVE_HORIZONTAL (-CURRENT_OFFSET);
  159.             POSITION (vi$first_no_space);
  160.         ENDIF;
  161.  
  162.         IF (MARK (NONE) <> END_OF (CURRENT_BUFFER)) THEN
  163.             MOVE_VERTICAL (1);
  164.             vi$new_endpos := MARK (NONE);
  165.             MOVE_VERTICAL (-1);
  166.         ENDIF;
  167.  
  168.         RETURN (vi$retpos (pos));
  169.     ENDIF;
  170.  
  171.     POSITION (pos);
  172.     RETURN (0);
  173. ENDPROCEDURE;
  174.  
  175. !
  176. !   Maintain the repeat count in vi$active_count.  If VI$ACTIVE_COUNT is ZERO,
  177. !   and '0' is typed, this means move to beginning of the line.
  178. !
  179. PROCEDURE vi$repeat_count
  180.  
  181.     IF VI$ACTIVE_COUNT = 0 THEN
  182.         vi$active_count := INT (ASCII (KEY_NAME (vi$last_key)));
  183.         IF vi$active_count = 0 THEN
  184.             vi$position (vi$fol, 0);
  185.         ENDIF;
  186.     ELSE
  187.         vi$active_count := vi$active_count * 10 +
  188.                                     INT (ASCII (KEY_NAME (vi$last_key)));
  189.     ENDIF;
  190.  
  191. ENDPROCEDURE;
  192.  
  193. !
  194. !   The function mapped to <CR>.
  195. !
  196. PROCEDURE vi$_next_line
  197.     POSITION (vi$beg_next);
  198. ENDPROCEDURE;
  199.  
  200. !
  201. !   Move the cursor to the beginning of the next line
  202. !
  203. PROCEDURE vi$beg_next
  204.     LOCAL
  205.         pos;
  206.  
  207.     ON_ERROR
  208.         RETURN (MARK (NONE));
  209.     ENDON_ERROR;
  210.  
  211.     pos := MARK (NONE);
  212.     MOVE_VERTICAL (vi$cur_active_count);
  213.     MOVE_HORIZONTAL (-CURRENT_OFFSET);
  214.     POSITION (vi$first_no_space);
  215.     vi$yank_mode := VI$LINE_MODE;
  216.     vi$new_offset := 1;
  217.     RETURN (vi$retpos (pos));
  218.  
  219. ENDPROCEDURE;
  220.  
  221. !
  222. !   This function moves to the first non-blank character of a line
  223. !
  224. PROCEDURE vi$first_no_space
  225.  
  226.     LOCAL
  227.         pos,
  228.         t_range;
  229.  
  230.     ON_ERROR
  231.         ! Ignore string not found messages.
  232.     ENDON_ERROR;
  233.  
  234.     pos := MARK (NONE);
  235.     MOVE_HORIZONTAL (- CURRENT_OFFSET);
  236.  
  237.     IF (LENGTH (CURRENT_LINE) > 0) THEN
  238.         IF t_range = 0 THEN
  239.             t_range :=
  240.                 SEARCH (ANCHOR & SPAN (vi$no_space) &
  241.                                         NOTANY(vi$no_space), FORWARD);
  242.         ENDIF;
  243.  
  244.         IF t_range <> 0 THEN
  245.             POSITION (END_OF (t_range));
  246.         ELSE
  247.             ! If that fails, then search for a blank line with extra white
  248.             ! space, and move to the end of the white space.
  249.  
  250.             t_range := SEARCH (ANCHOR & SPAN (vi$no_space), FORWARD);
  251.  
  252.             IF t_range <> 0 THEN
  253.                 POSITION (END_OF (t_range));
  254.             ENDIF;
  255.         ENDIF;
  256.     ENDIF;
  257.  
  258.     vi$yank_mode := VI$IN_LINE_MODE;
  259.     RETURN (vi$retpos (pos));
  260. ENDPROCEDURE;
  261.  
  262. !
  263. !   Move by a section in the indicated direction
  264. !
  265. PROCEDURE vi$_section (dir)
  266.     LOCAL
  267.         ch;
  268.  
  269.     ch := vi$read_a_key;
  270.     IF ((ASCII(ch) = "]") AND (dir = 1)) OR
  271.         ((ASCII(ch) = "[") AND (dir = -1)) THEN
  272.         vi$position (vi$section (dir), 1);
  273.     ELSE
  274.         vi$beep;
  275.     ENDIF;
  276. ENDPROCEDURE;
  277.  
  278. !
  279. !   Sound a bell.
  280. !
  281. PROCEDURE vi$beep
  282.     LOCAL
  283.         pos;
  284.  
  285.     IF (vi$error_bells = 0) THEN
  286.         RETURN;
  287.     ENDIF;
  288.  
  289.     pos := CURRENT_WINDOW;
  290.     SET (BELL, ALL, ON);
  291.     MESSAGE ("");
  292.     SET (BELL, ALL, OFF);
  293.     SET (BELL, BROADCAST, ON);
  294.     POSITION (pos);
  295. ENDPROCEDURE;
  296.  
  297. !
  298. !   Mapped to '}' and '{', moves by a paragraph in the indicated direction.
  299. !
  300. PROCEDURE vi$_paragraph(dir)
  301.     vi$position (vi$paragraph(dir), 1);
  302. ENDPROCEDURE;
  303.  
  304. !
  305. !   Mapped to ( moves backward a sentence
  306. !
  307. PROCEDURE vi$_begin_sentence
  308.     vi$position (vi$begin_sentence, 1);
  309. ENDPROCEDURE;
  310.  
  311. !
  312. !   Mapped to ) moves forward a sentence
  313. !
  314. PROCEDURE vi$_end_sentence
  315.     vi$position (vi$end_sentence, 1);
  316. ENDPROCEDURE;
  317.  
  318. !
  319. !   Move backward a sentence.
  320. !
  321. PROCEDURE vi$begin_sentence
  322.     LOCAL
  323.         rng,
  324.         spos,
  325.         pos;
  326.  
  327.     ON_ERROR;
  328.     ENDON_ERROR;
  329.  
  330.     pos := MARK (NONE);
  331.  
  332.     MOVE_HORIZONTAL (-1);
  333.  
  334.     LOOP;
  335.         rng := SEARCH (
  336.             (("" | " " | "  ") & ANY (vi$_upper_chars)),
  337.             REVERSE, EXACT);
  338.  
  339.         EXITIF rng = 0;
  340.  
  341.         POSITION (BEGINNING_OF (rng));
  342.         IF INDEX ("     ", CURRENT_CHARACTER) = 0 THEN
  343.             MOVE_HORIZONTAL (-1);
  344.         ENDIF;
  345.         IF INDEX ("     ", CURRENT_CHARACTER) <> 0 THEN
  346.             IF (CURRENT_CHARACTER = " ") THEN
  347.                 MOVE_HORIZONTAL (-1);
  348.                 IF INDEX ("     ", CURRENT_CHARACTER) <> 0 THEN
  349.                     MOVE_HORIZONTAL (-1);
  350.                     IF INDEX ("?.!", CURRENT_CHARACTER) <> 0 THEN
  351.                         MOVE_HORIZONTAL (3);
  352.                         RETURN (vi$retpos (pos));
  353.                     ENDIF;
  354.                 ENDIF;
  355.             ELSE
  356.                 MOVE_HORIZONTAL (1);
  357.                 RETURN (vi$retpos (pos));
  358.             ENDIF;
  359.         ENDIF;
  360.         POSITION (BEGINNING_OF (rng));
  361.         MOVE_HORIZONTAL (-1);
  362.     ENDLOOP;
  363.  
  364.     RETURN (0);
  365. ENDPROCEDURE;
  366.  
  367. !
  368. !   Move to next paragraph
  369. !
  370. PROCEDURE vi$paragraph (dir)
  371.     RETURN (vi$para_sect (dir, vi$para_pat));
  372. ENDPROCEDURE;
  373.  
  374. !
  375. !   Find next paragraph or section.
  376. !
  377. PROCEDURE vi$para_sect (dir, pat)
  378.     LOCAL
  379.         loc,
  380.         direct,
  381.         pos;
  382.  
  383.     pos := MARK (NONE);
  384.  
  385.     IF (dir < 0) THEN
  386.         direct := REVERSE;
  387.         MOVE_VERTICAL (-1);
  388.     ELSE
  389.         direct := FORWARD;
  390.         MOVE_VERTICAL (1);
  391.     ENDIF;
  392.  
  393.     SET (TIMER, ON, "Searching...");
  394.     loc := SEARCH (pat, direct, NO_EXACT);
  395.     SET (TIMER, OFF);
  396.  
  397.     IF (loc <> 0) THEN
  398.         RETURN (BEGINNING_OF (loc));
  399.     ELSE
  400.         SET (TIMER, ON, "Searching...");
  401.         loc := SEARCH (vi$next_blank, direct, NO_EXACT);
  402.         SET (TIMER, OFF);
  403.         IF (loc <> 0) THEN
  404.             RETURN (BEGINNING_OF (loc));
  405.         ENDIF;
  406.     ENDIF;
  407.  
  408.     POSITION (pos);
  409.     RETURN (0);
  410. ENDPROCEDURE;
  411.  
  412. !
  413. !   Move to next section
  414. !
  415. PROCEDURE vi$section (dir)
  416.     RETURN (vi$para_sect (dir, vi$sect_pat));
  417. ENDPROCEDURE;
  418.  
  419. !
  420. !   Move forward a sentence.
  421. !
  422. PROCEDURE vi$end_sentence
  423.     LOCAL
  424.         rng,
  425.         spos,
  426.         pos;
  427.  
  428.     ON_ERROR;
  429.     ENDON_ERROR;
  430.  
  431.     pos := MARK (NONE);
  432.  
  433.     MOVE_HORIZONTAL (1);
  434.  
  435.     LOOP;
  436.         rng := SEARCH (ANY (vi$_upper_chars), FORWARD, EXACT);
  437.  
  438.         EXITIF rng = 0;
  439.  
  440.         POSITION (BEGINNING_OF (rng));
  441.         IF INDEX ("     ", CURRENT_CHARACTER) = 0 THEN
  442.             MOVE_HORIZONTAL (-1);
  443.         ENDIF;
  444.         IF INDEX ("     ", CURRENT_CHARACTER) <> 0 THEN
  445.             IF (CURRENT_CHARACTER = " ") THEN
  446.                 MOVE_HORIZONTAL (-1);
  447.                 IF INDEX ("     ", CURRENT_CHARACTER) <> 0 THEN
  448.                     MOVE_HORIZONTAL (-1);
  449.                     IF INDEX ("?.!", CURRENT_CHARACTER) <> 0 THEN
  450.                         MOVE_HORIZONTAL (3);
  451.                         RETURN (vi$retpos (pos));
  452.                     ENDIF;
  453.                 ENDIF;
  454.             ELSE
  455.                 MOVE_HORIZONTAL (1);
  456.                 RETURN (vi$retpos (pos));
  457.             ENDIF;
  458.         ENDIF;
  459.         POSITION (BEGINNING_OF (rng));
  460.         MOVE_HORIZONTAL (1);
  461.     ENDLOOP;
  462.  
  463.     RETURN (0);
  464. ENDPROCEDURE;
  465.  
  466. !
  467. !   This function returns the value in vi$active count.  It takes into
  468. !   account that when vi$active_count is zero, it should really be
  469. !   one.
  470. !
  471. PROCEDURE vi$cur_active_count
  472.     LOCAL
  473.         resp,
  474.         old_cnt;
  475.  
  476.     old_cnt := vi$active_count;
  477.     vi$active_count := 0;
  478.     IF old_cnt <= 0 THEN
  479.         old_cnt := 1;
  480.     ENDIF;
  481.  
  482.     RETURN (old_cnt);
  483. ENDPROCEDURE;
  484.  
  485. !
  486. !   The function mapped to 'p'.
  487. !
  488. PROCEDURE vi$put_after (dest_buf)
  489.  
  490.     LOCAL
  491.         source,
  492.         pos;
  493.  
  494.     source := vi$cur_text;
  495.  
  496.     IF (GET_INFO (dest_buf, "TYPE") = BUFFER) THEN
  497.         source := dest_buf;
  498.     ENDIF;
  499.  
  500.     IF (GET_INFO (source, "TYPE") = BUFFER) THEN
  501.         pos := MARK (NONE);
  502.         POSITION (BEGINNING_OF (source));
  503.         vi$yank_mode := INT (vi$current_line);
  504.         POSITION (pos);
  505.     ENDIF;
  506.  
  507.     IF (source = "") THEN
  508.         RETURN;
  509.     ENDIF;
  510.  
  511.     IF (vi$yank_mode = VI$LINE_MODE) THEN
  512.         IF (MARK(NONE) <> END_OF (CURRENT_BUFFER)) THEN
  513.             MOVE_VERTICAL (1);
  514.         ENDIF;
  515.     ELSE
  516.         IF (LENGTH (CURRENT_LINE) > 0) THEN
  517.             MOVE_HORIZONTAL (1);
  518.         ENDIF;
  519.     ENDIF;
  520.  
  521.     vi$put_here (VI$AFTER, source);
  522. ENDPROCEDURE;
  523.  
  524. !
  525. !   The function mapped to 'P'.
  526. !
  527. PROCEDURE vi$put_here (here_or_below, dest_buf)
  528.     LOCAL
  529.         olen,
  530.         source,
  531.         pos;
  532.  
  533.     source := vi$cur_text;
  534.     olen := GET_INFO (CURRENT_BUFFER, "RECORD_COUNT");
  535.  
  536.     IF (GET_INFO (dest_buf, "TYPE") = BUFFER) THEN
  537.         source := dest_buf;
  538.     ENDIF;
  539.  
  540.     IF (GET_INFO (source, "TYPE") = BUFFER) THEN
  541.         pos := MARK (NONE);
  542.         POSITION (BEGINNING_OF (source));
  543.         IF (MARK (NONE) = END_OF (source)) THEN
  544.             RETURN;
  545.         ENDIF;
  546.         vi$yank_mode := INT (vi$current_line);
  547.         ERASE_LINE;
  548.         POSITION (pos);
  549.     ELSE
  550.         IF (source = "") THEN
  551.             RETURN;
  552.         ENDIF;
  553.     ENDIF;
  554.  
  555.     IF source = 0 THEN
  556.         vi$message ("Bad buffer for put!");
  557.         RETURN;
  558.     ENDIF;
  559.  
  560.     IF (vi$yank_mode = VI$LINE_MODE) THEN
  561.         MOVE_HORIZONTAL (-CURRENT_OFFSET);
  562.     ENDIF;
  563.  
  564.     pos := vi$get_undo_start;
  565.  
  566.     COPY_TEXT (source);
  567.     APPEND_LINE;
  568.     MOVE_HORIZONTAL (-1);
  569.     vi$undo_end := MARK (NONE);
  570.     MOVE_HORIZONTAL (1);
  571.  
  572.     vi$kill_undo;
  573.  
  574.     IF (here_or_below = VI$AFTER) AND (vi$yank_mode = VI$LINE_MODE) THEN
  575.         MOVE_HORIZONTAL (-CURRENT_OFFSET);
  576.     ENDIF;
  577.  
  578.     vi$undo_start := vi$set_undo_start (pos);
  579.  
  580.     ! Put the mode back into the buffer.
  581.  
  582.     IF (GET_INFO (source, "TYPE") = BUFFER) THEN
  583.         POSITION (BEGINNING_OF (source));
  584.         COPY_TEXT (STR (vi$yank_mode));
  585.         SPLIT_LINE;
  586.         POSITION (vi$undo_start);
  587.     ENDIF;
  588.  
  589.     IF (here_or_below = VI$AFTER) AND (vi$yank_mode = VI$IN_LINE_MODE) THEN
  590.         POSITION (vi$undo_end);
  591.     ENDIF;
  592.  
  593.     vi$check_length (olen);
  594. ENDPROCEDURE;
  595.  
  596. !
  597. !   Function mapped to 'o'.  Note that this makes undo NOT place
  598. !   the cursor where is really should be.
  599. !
  600. PROCEDURE vi$open_below
  601.     LOCAL
  602.         uline;
  603.  
  604.     ON_ERROR
  605.         ! Ignore attempt to move past EOB errors
  606.     ENDON_ERROR;
  607.  
  608.     uline := vi$cur_line_no;
  609.     MOVE_VERTICAL (1);
  610.     vi$open_here;
  611.     vi$undo_line := uline;
  612.  
  613. ENDPROCEDURE;
  614.  
  615. !
  616. !   Function mapped to 'O'
  617. !
  618. PROCEDURE vi$open_here
  619.  
  620.     LOCAL
  621.         uline,
  622.         offs,
  623.         cnt,
  624.         epos,
  625.         spos;
  626.  
  627.     uline := vi$cur_line_no;
  628.     offs := CURRENT_OFFSET;
  629.  
  630.     MOVE_HORIZONTAL (- CURRENT_OFFSET);
  631.  
  632.     IF (MARK (NONE) <> BEGINNING_OF (CURRENT_BUFFER)) THEN
  633.         MOVE_HORIZONTAL (-1);
  634.         spos := MARK (NONE);
  635.         MOVE_HORIZONTAL (1);
  636.     ELSE
  637.         spos := 0;
  638.     ENDIF;
  639.  
  640.     SPLIT_LINE;
  641.  
  642.     MOVE_VERTICAL (-1);
  643.  
  644.     cnt := vi$while_not_esc;
  645.     epos := MARK (NONE);
  646.  
  647.     IF (cnt <> 0) THEN
  648.         IF (LENGTH (vi$current_line) > 0) THEN
  649.             MOVE_HORIZONTAL (1);
  650.         ENDIF;
  651.     ENDIF;
  652.  
  653.     vi$undo_end := MARK (NONE);
  654.  
  655.     IF spos <> 0 THEN
  656.         POSITION (spos);
  657.         MOVE_HORIZONTAL (1);
  658.     ELSE
  659.         POSITION (BEGINNING_OF (CURRENT_BUFFER));
  660.     ENDIF;
  661.  
  662.     vi$undo_start := MARK (NONE);
  663.     POSITION (epos);
  664.  
  665.     vi$kill_undo;
  666.  
  667.     vi$undo_line := uline;
  668.     vi$undo_offset := offs;
  669. ENDPROCEDURE;
  670.  
  671. !
  672. !   This function guards the right margin, and the end of the buffer so
  673. !   that the cursor never is displayed past those boundries.
  674. !
  675. PROCEDURE vi$check_rmarg
  676.  
  677.     ON_ERROR;
  678.         ! ignore "Can't return line and end of buffer" messages
  679.         RETURN;
  680.     ENDON_ERROR;
  681.  
  682.     IF (LENGTH (vi$current_line) > 0) THEN
  683.         IF (CURRENT_OFFSET = LENGTH (vi$current_line)) THEN
  684.             MOVE_HORIZONTAL (-1);
  685.         ENDIF;
  686.     ENDIF;
  687.  
  688.     IF (MARK (NONE) = END_OF (CURRENT_BUFFER)) THEN
  689.         MOVE_VERTICAL (-1);
  690.     ENDIF;
  691. ENDPROCEDURE;
  692.  
  693. !
  694. !   The function mapped to 'h'.
  695. !
  696. PROCEDURE vi$move_left
  697.     vi$position (vi$left, 0);
  698. ENDPROCEDURE;
  699.  
  700. !
  701. !   The function mapped to 'l'.
  702. !
  703. PROCEDURE vi$move_right
  704.     vi$position (vi$right, 0);
  705. ENDPROCEDURE;
  706.  
  707. !
  708. !   The function mapped to 'j'
  709. !
  710. PROCEDURE vi$move_down
  711.     LOCAL
  712.         save_mark;
  713.  
  714.     save_mark := 0;
  715.  
  716.     IF (vi$active_count >= vi$report) THEN
  717.         save_mark := 1;
  718.     ENDIF;
  719.  
  720.     vi$position (vi$downline (0), save_mark);
  721. ENDPROCEDURE;
  722.  
  723. !
  724. !   The function mapped to 'k'.
  725. !
  726. PROCEDURE vi$move_up
  727.     LOCAL
  728.         save_mark;
  729.  
  730.     save_mark := 0;
  731.  
  732.     IF (vi$active_count >= vi$report) THEN
  733.         save_mark := 1;
  734.     ENDIF;
  735.  
  736.     vi$position (vi$upline, save_mark);
  737. ENDPROCEDURE;
  738.  
  739. !
  740. !   The function mapped to 'i'.
  741. !
  742. PROCEDURE vi$insert_here
  743.     LOCAL
  744.         act_cnt,
  745.         rnge,
  746.         ccnt,
  747.         epos,
  748.         spos;
  749.  
  750.     vi$kill_undo;
  751.  
  752.     IF (MARK (NONE) <> BEGINNING_OF (CURRENT_BUFFER)) THEN
  753.         MOVE_HORIZONTAL (-1);
  754.         spos := MARK (NONE);
  755.         MOVE_HORIZONTAL (1);
  756.     ELSE
  757.         spos := 0;
  758.     ENDIF;
  759.  
  760.     vi$undo_start := MARK (NONE);
  761.  
  762.     ccnt := vi$while_not_esc;
  763.  
  764.     vi$undo_end := 0;
  765.  
  766.     IF (ccnt > 0) THEN
  767.         IF (CURRENT_OFFSET = 0) AND
  768.                         ((ccnt > 1) OR (LENGTH (CURRENT_LINE) = 0)) AND
  769.                         (MARK (NONE) <> BEGINNING_OF (CURRENT_BUFFER)) THEN
  770.             MOVE_HORIZONTAL (-1);
  771.             epos := MARK (NONE);
  772.             MOVE_HORIZONTAL (1);
  773.         ELSE
  774.             epos := MARK (NONE);
  775.         ENDIF;
  776.     ELSE
  777.         epos := 0;
  778.     ENDIF;
  779.  
  780.     IF epos <> 0 THEN
  781.         act_cnt := vi$cur_active_count;
  782.  
  783.         IF spos <> 0 THEN
  784.             POSITION (spos);
  785.             MOVE_HORIZONTAL (1);
  786.         ELSE
  787.             POSITION (BEGINNING_OF (CURRENT_BUFFER));
  788.         ENDIF;
  789.         vi$undo_start := MARK (NONE);
  790.  
  791.         POSITION (epos);
  792.  
  793.         IF (vi$undo_start = 0) OR (epos = 0) THEN
  794.             vi$message ("Ooops, bad markers in vi$insert_here");
  795.             RETURN ;
  796.         ENDIF;
  797.  
  798.         rnge := CREATE_RANGE (vi$undo_start, epos, NONE);
  799.  
  800.         LOOP
  801.             EXITIF act_cnt < 2;
  802.             MOVE_HORIZONTAL (1);
  803.  
  804.             IF rnge = 0 THEN
  805.                 vi$message ("Ooops, generated a bad range in vi$insert_here");
  806.                 RETURN ;
  807.             ENDIF;
  808.  
  809.             COPY_TEXT (rnge);
  810.             act_cnt := act_cnt - 1;
  811.             MOVE_HORIZONTAL (-1);
  812.         ENDLOOP;
  813.  
  814.         vi$undo_end := MARK (NONE);
  815.         IF (CURRENT_OFFSET = LENGTH (vi$current_line)) THEN
  816.             MOVE_HORIZONTAL (1);
  817.         ENDIF;
  818.     ENDIF;
  819. ENDPROCEDURE;
  820.  
  821. !
  822. !   The function mapped to 'I'
  823. !
  824. PROCEDURE vi$insert_at_begin
  825.  
  826.     MOVE_HORIZONTAL (- CURRENT_OFFSET);
  827.     vi$_bol;
  828.     vi$insert_here;
  829.  
  830. ENDPROCEDURE;
  831.  
  832. !
  833. !   The function mapped to 'a'
  834. !
  835. PROCEDURE vi$insert_after
  836.  
  837.     IF (LENGTH (vi$current_line) > 0) THEN
  838.         IF (CURRENT_OFFSET < LENGTH(vi$current_line)) THEN
  839.             MOVE_HORIZONTAL (1);
  840.         ENDIF;
  841.     ENDIF;
  842.     vi$insert_here;
  843.  
  844. ENDPROCEDURE;
  845.  
  846. !
  847. !  A do nothing function
  848. !
  849. PROCEDURE vi$_dummy
  850. ENDPROCEDURE;
  851.  
  852. !
  853. !  Do the command line input processing
  854. !
  855. PROCEDURE vi$while_not_esc
  856.  
  857.     LOCAL
  858.         max_mark,
  859.         start_pos,
  860.         max_col;
  861.  
  862.     max_col := CURRENT_OFFSET;
  863.     start_pos := max_col;
  864.     max_mark := MARK(NONE);
  865.     vi$update (CURRENT_WINDOW);
  866.  
  867.     RETURN (vi$line_edit (max_col, start_pos, max_mark, 0));
  868. ENDPROCEDURE;
  869.  
  870. !
  871. !   Insert text into the buffer using standard VI insertion.
  872. !   Used by CHANGE, APPEND, INSERT, and REPLACE functions.
  873. !
  874. PROCEDURE vi$line_edit (max_col, start_pos, max_mark, replace)
  875.  
  876.     LOCAL
  877.         chcnt,
  878.         offset,
  879.         seen_eol,
  880.         col,
  881.         cnt,
  882.         tabstops,
  883.         current_mark,
  884.         desc,
  885.         start_ins,
  886.         ins_text,
  887.         should_wrap,
  888.         abbrs,
  889.         rchar,
  890.         abbrlen,
  891.         cabbr,
  892.         pos,
  893.         in_char;
  894.  
  895.     ON_ERROR
  896.     ENDON_ERROR;
  897.  
  898.     IF (vi$show_mode) THEN
  899.         vi$mess_select (BOLD);
  900.         MESSAGE (FAO ("!7*  INSERT"));
  901.         vi$mess_select (REVERSE);
  902.     ENDIF;
  903.     chcnt := 0;
  904.     seen_eol := 0;
  905.  
  906.     abbrs := EXPAND_NAME ("vi$abbr_", VARIABLES) + " ";
  907.  
  908.     cabbr := "";
  909.     abbrlen := 0;
  910.  
  911.     SET (INSERT, CURRENT_BUFFER);
  912.     IF (max_col > CURRENT_OFFSET) OR (replace <> 0) THEN
  913.         SET (OVERSTRIKE, CURRENT_BUFFER);
  914.     ENDIF;
  915.  
  916.     start_ins := MARK (NONE);
  917.  
  918.     LOOP
  919.         LOOP
  920.             in_char := vi$read_a_key;
  921.             desc := LOOKUP_KEY (KEY_NAME (in_char), COMMENT, vi$edit_keys);
  922.             EXITIF (desc <> "reinsert");
  923.  
  924.             IF max_mark <> MARK (NONE) THEN
  925.                 current_mark := MARK (NONE);
  926.                 POSITION (max_mark);
  927.                 MOVE_HORIZONTAL (-1);
  928.  
  929.                 ERASE (CREATE_RANGE (MARK (NONE), current_mark, NONE));
  930.             ENDIF;
  931.  
  932.             SET (INSERT, CURRENT_BUFFER);
  933.             COPY_TEXT (vi$last_insert);
  934.             APPEND_LINE;
  935.  
  936.             max_col := CURRENT_OFFSET;
  937.             start_pos := CURRENT_OFFSET;
  938.             max_mark := MARK(NONE);
  939.             chcnt := chcnt + 1;
  940.         ENDLOOP;
  941.  
  942.         IF (desc = "active_macro") THEN
  943.             EXECUTE (LOOKUP_KEY (KEY_NAME (in_char), PROGRAM, vi$edit_keys));
  944.         ELSE
  945.             EXITIF desc = "escape";
  946.  
  947.             should_wrap := (vi$wrap_margin <> 0) AND
  948.                             ((CURRENT_OFFSET + vi$wrap_margin) > vi$scr_width);
  949.  
  950.             IF (desc <> "eol") AND (desc <> "bword") AND (desc <> "bs") THEN
  951.                 IF (should_wrap) THEN
  952.  
  953.                     offset := 0;
  954.                     MOVE_HORIZONTAL (-1);
  955.  
  956.                     LOOP
  957.                         EXITIF (CURRENT_OFFSET = 0);
  958.                         EXITIF (INDEX ("    ", CURRENT_CHARACTER) <> 0);
  959.                         MOVE_HORIZONTAL (-1);
  960.                         offset := offset + 1;
  961.                     ENDLOOP;
  962.  
  963.                     IF (offset <> 0) THEN
  964.                         ERASE_CHARACTER (1);
  965.                         LOOP
  966.                             EXITIF (CURRENT_OFFSET = 0);
  967.                             MOVE_HORIZONTAL (-1);
  968.                             EXITIF (
  969.                                 INDEX ("    ", CURRENT_CHARACTER) = 0);
  970.                             ERASE_CHARACTER (1);
  971.                         ENDLOOP;
  972.                     ENDIF;
  973.  
  974.                     IF (CURRENT_OFFSET <> 0) THEN
  975.                         MOVE_HORIZONTAL (1);
  976.                         SPLIT_LINE;
  977.                         max_col := CURRENT_OFFSET;
  978.                         start_pos := CURRENT_OFFSET;
  979.                         max_mark := MARK(NONE);
  980.                         MOVE_HORIZONTAL (offset);
  981.                     ELSE
  982.                         MOVE_HORIZONTAL (offset);
  983.                         SPLIT_LINE;
  984.                         max_col := CURRENT_OFFSET;
  985.                         start_pos := CURRENT_OFFSET;
  986.                         max_mark := MARK(NONE);
  987.                     ENDIF;
  988.                 ENDIF;
  989.  
  990.                 vi$update (CURRENT_WINDOW);
  991.  
  992.                 IF desc = "vquote" THEN
  993.                     in_char := vi$read_a_key;
  994.                 ENDIF;
  995.  
  996.                 IF in_char = TAB_KEY THEN
  997.                     vi$abbr (abbrs, 0, cabbr, abbrlen);
  998.                     IF (vi$use_tabs = 1) THEN
  999.                         COPY_TEXT (ASCII (9));
  1000.                     ELSE
  1001.                         cnt := 0;
  1002.                         col := GET_INFO (SCREEN, "CURRENT_COLUMN");
  1003.                         tabstops := GET_INFO (CURRENT_BUFFER, "TAB_STOPS");
  1004.  
  1005.                         IF (GET_INFO (tabstops, "TYPE") <> STRING) THEN
  1006.                             LOOP
  1007.                                 EXITIF (col - ((col / tabstops) *
  1008.                                                                 tabstops) = 0);
  1009.                                 cnt := cnt + 1;
  1010.                                 col := col + 1;
  1011.                             ENDLOOP;
  1012.  
  1013.                             chcnt := chcnt + cnt;
  1014.                             LOOP
  1015.                                 EXITIF (cnt < 0);
  1016.                                 IF (CURRENT_OFFSET = max_col) AND
  1017.                                                 ((replace = 0) OR seen_eol) THE
  1018. N
  1019.                                     SET (INSERT, CURRENT_BUFFER);
  1020.                                 ELSE
  1021.                                     IF CURRENT_OFFSET > max_col THEN
  1022.                                         max_col := CURRENT_OFFSET;
  1023.                                         max_mark := MARK (NONE);;
  1024.                                     ENDIF;
  1025.                                 ENDIF;
  1026.                                 COPY_TEXT (" ");
  1027.                                 cnt := cnt - 1;
  1028.                             ENDLOOP
  1029.                         ELSE
  1030.  
  1031.                             ! Give up on windows with weird tab stops.
  1032.  
  1033.                             COPY_TEXT (ASCII (9));
  1034.                         ENDIF;
  1035.                     ENDIF;
  1036.                     chcnt := chcnt + 1;
  1037.                 ELSE
  1038.                     IF (in_char <= CTRL_Z_KEY) AND (in_char >= CTRL_A_KEY) THEN
  1039.                         in_char := (in_char - CTRL_A_KEY) /
  1040.                                     (CTRL_B_KEY - CTRL_A_KEY) + 1;
  1041.                     ENDIF;
  1042.  
  1043.                     rchar := vi$ascii(in_char);
  1044.  
  1045.                     IF (INDEX (vi$_ws, rchar) <> 0) THEN
  1046.                         chcnt := chcnt + vi$abbr (abbrs, rchar, cabbr, abbrlen)
  1047. ;
  1048.                     ELSE
  1049.                         COPY_TEXT (rchar);
  1050.                         IF (INDEX(vi$_upper_chars, rchar) <> 0) THEN
  1051.                             cabbr := cabbr + "_";
  1052.                         ENDIF;
  1053.                         cabbr := cabbr + rchar;
  1054.                         abbrlen := abbrlen + 1;
  1055.                         chcnt := chcnt + 1;
  1056.                     ENDIF;
  1057.                 ENDIF;
  1058.  
  1059.                 IF (CURRENT_OFFSET = max_col) AND
  1060.                                     ((replace = 0) OR seen_eol) THEN
  1061.                     SET (INSERT, CURRENT_BUFFER);
  1062.                 ELSE
  1063.                     IF CURRENT_OFFSET > max_col THEN
  1064.                         max_col := CURRENT_OFFSET;
  1065.                         max_mark := MARK (NONE);
  1066.                     ENDIF;
  1067.                 ENDIF;
  1068.             ELSE
  1069.                 IF desc = "bs" THEN
  1070.                     IF start_pos < CURRENT_OFFSET THEN
  1071.                         ! Delete backspace and the character before it.
  1072.                         vi$del_a_key;
  1073.                         vi$del_a_key;
  1074.                         SET (OVERSTRIKE, CURRENT_BUFFER);
  1075.                         MOVE_HORIZONTAL (-1);
  1076.                         chcnt := chcnt - 1;
  1077.                     ENDIF;
  1078.                 ELSE
  1079.                     IF desc = "eol" THEN
  1080.                         IF (max_mark <> MARK (NONE)) AND (replace = 0) THEN
  1081.                             current_mark := MARK (NONE);
  1082.                             POSITION (max_mark);
  1083.                             MOVE_HORIZONTAL (-1);
  1084.                             ERASE (CREATE_RANGE (MARK (NONE),
  1085.                                                         current_mark, NONE));
  1086.                         ENDIF;
  1087.                         vi$abbr (abbrs, 0, cabbr, abbrlen);
  1088.                         SPLIT_LINE;
  1089.                         chcnt := chcnt + 1;
  1090.                         seen_eol := 1;
  1091.                         IF (CURRENT_BUFFER = vi$dcl_buf) AND (vi$send_dcl) THEN
  1092.                             MOVE_VERTICAL (-1);
  1093.                             vi$send_to_dcl (CURRENT_LINE);
  1094.                             MOVE_VERTICAL (1);
  1095.                         ENDIF;
  1096.                         max_col := CURRENT_OFFSET;
  1097.                         start_pos := CURRENT_OFFSET;
  1098.                         SET (INSERT, CURRENT_BUFFER);
  1099.                         max_mark := MARK(NONE);
  1100.                         IF (CURRENT_BUFFER = vi$dcl_buf) AND (vi$send_dcl) THEN
  1101.                             EXITIF (1);
  1102.                         ENDIF;
  1103.                     ELSE
  1104.                         IF (desc = "bword") THEN
  1105.  
  1106.                             ! Backup over whitespace.
  1107.  
  1108.                             LOOP
  1109.                                 EXITIF start_pos = CURRENT_OFFSET;
  1110.                                 MOVE_HORIZONTAL (-1);
  1111.                                 chcnt := chcnt - 1;
  1112.                                 EXITIF (INDEX ("    ", CURRENT_CHARACTER) = 0);
  1113.                                 SET (OVERSTRIKE, CURRENT_BUFFER);
  1114.                             ENDLOOP;
  1115.  
  1116.                             ! Backup over noblank words.
  1117.  
  1118.                             LOOP
  1119.                                 EXITIF start_pos = CURRENT_OFFSET;
  1120.                                 SET (OVERSTRIKE, CURRENT_BUFFER);
  1121.                                 IF (INDEX ("    ", CURRENT_CHARACTER) <> 0) THE
  1122. N
  1123.                                     chcnt := chcnt + 1;
  1124.                                     MOVE_HORIZONTAL (1);
  1125.                                     EXITIF (1);
  1126.                                 ENDIF;
  1127.                                 MOVE_HORIZONTAL (-1);
  1128.                                 chcnt := chcnt - 1;
  1129.                             ENDLOOP;
  1130.                         ENDIF;
  1131.                     ENDIF;
  1132.                 ENDIF;
  1133.             ENDIF;
  1134.         ENDIF;
  1135.  
  1136.         vi$update (CURRENT_WINDOW);
  1137.     ENDLOOP;
  1138.  
  1139.     IF max_mark <> MARK (NONE) THEN
  1140.         current_mark := MARK (NONE);
  1141.         IF (NOT seen_eol) AND (replace <> 0) THEN
  1142.             SET (OVERSTRIKE, CURRENT_BUFFER);
  1143.             COPY_TEXT (SUBSTR (replace, CURRENT_OFFSET + 1,
  1144.                                                 max_col - CURRENT_OFFSET));
  1145.             POSITION (current_mark);
  1146.         ELSE
  1147.             POSITION (max_mark);
  1148.             IF (MARK(NONE) <> BEGINNING_OF (CURRENT_BUFFER)) THEN
  1149.                 MOVE_HORIZONTAL (-1);
  1150.             ENDIF;
  1151.             ERASE (CREATE_RANGE (MARK (NONE), current_mark, NONE));
  1152.         ENDIF;
  1153.     ENDIF;
  1154.  
  1155.     IF (CURRENT_OFFSET > 0) AND
  1156.                             (MARK(NONE) <> BEGINNING_OF (CURRENT_BUFFER)) THEN
  1157.         MOVE_HORIZONTAL (-1);
  1158.     ENDIF;
  1159.  
  1160.     ins_text := CREATE_RANGE (start_ins, MARK (NONE), NONE);
  1161.  
  1162.     ! Save last inserted text to buffer.
  1163.  
  1164.     ERASE (vi$last_insert);
  1165.     pos := MARK (NONE);
  1166.  
  1167.     POSITION (vi$last_insert);
  1168.     COPY_TEXT (ins_text);
  1169.     SPLIT_LINE;
  1170.     POSITION (BEGINNING_OF (vi$last_insert));
  1171.  
  1172.     POSITION (pos);
  1173.  
  1174.     SET (INSERT, CURRENT_BUFFER);
  1175.  
  1176.     IF (vi$show_mode) THEN
  1177.         MESSAGE ("");
  1178.     ENDIF;
  1179.     RETURN (chcnt);
  1180. ENDPROCEDURE;
  1181.  
  1182. !
  1183. !   Check to see if 'cabbr' is a known abbreviation, and substitute the
  1184. !   proper text if it is.
  1185. !
  1186. PROCEDURE vi$abbr (abbrs, rchar, cabbr, abbrlen)
  1187.     LOCAL
  1188.         strg;
  1189.  
  1190.     strg := "";
  1191.  
  1192.     IF (abbrlen > 0) THEN
  1193.         EDIT (cabbr, UPPER);
  1194.         IF (INDEX (abbrs, "VI$ABBR_"+cabbr+" ") <> 0) THEN
  1195.             vi$global_var := 0;
  1196.             EXECUTE (COMPILE ("vi$global_var := vi$abbr_"+cabbr+";"));
  1197.             IF (vi$global_var <> 0) THEN
  1198.                 ERASE_CHARACTER (-abbrlen);
  1199.                 strg := vi$global_var;
  1200.                 COPY_TEXT (strg);
  1201.             ENDIF;
  1202.         ENDIF;
  1203.         cabbr := "";
  1204.         abbrlen := 0;
  1205.     ENDIF;
  1206.     IF (rchar <> 0) THEN
  1207.         COPY_TEXT (rchar);
  1208.     ENDIF;
  1209.     RETURN (LENGTH (strg) + (rchar <> 0));
  1210. ENDPROCEDURE;
  1211.  
  1212. !
  1213. !   Return a string describing the KEY_NAME passed.  For control characters,
  1214. !   it is "^?" where the '?' is A-Z.  Otherwise, the value returned by the
  1215. !   ASCII() builtin is used.
  1216. !
  1217. PROCEDURE vi$ascii_name (key_n)
  1218.     LOCAL
  1219.         key;
  1220.  
  1221.     key := (key_n - CTRL_A_KEY) / (CTRL_B_KEY - CTRL_A_KEY);
  1222.     IF (key > 31) OR (key < 0) THEN
  1223.         key := ASCII (key_n);
  1224.     ELSE
  1225.         key := "^" + ASCII(key+65);
  1226.     ENDIF;
  1227.  
  1228.     RETURN (key);
  1229. ENDPROCEDURE;
  1230.  
  1231. !
  1232. !   Perform some mapping of keys to different ASCII values.
  1233. !
  1234. PROCEDURE vi$ascii (key_n)
  1235.     IF key_n = F12 THEN
  1236.         RETURN (ASCII (8));
  1237.     ENDIF;
  1238.     IF key_n = F11 THEN
  1239.         RETURN (ASCII (27));
  1240.     ENDIF;
  1241.     IF key_n = PF1 THEN
  1242.         RETURN (ASCII (27));
  1243.     ENDIF;
  1244.     IF key_n = RET_KEY THEN
  1245.         RETURN (ASCII (13));
  1246.     ENDIF;
  1247.     IF key_n = TAB_KEY THEN
  1248.         RETURN (ASCII (9));
  1249.     ENDIF;
  1250.     RETURN (ASCII (key_n));
  1251. ENDPROCEDURE;
  1252.  
  1253. !
  1254. !   Move up by screens
  1255. !
  1256. PROCEDURE vi$prev_screen
  1257.     ON_ERROR
  1258.     ENDON_ERROR;
  1259.  
  1260.     MOVE_VERTICAL (-vi$cur_active_count *
  1261.                         GET_INFO (CURRENT_WINDOW, "VISIBLE_LENGTH"));
  1262.  
  1263.     vi$position (vi$first_no_space, 0);
  1264. ENDPROCEDURE;
  1265.  
  1266. !
  1267. !   Move down by screens
  1268. !
  1269. PROCEDURE vi$next_screen
  1270.     ON_ERROR
  1271.     ENDON_ERROR;
  1272.  
  1273.     MOVE_VERTICAL (vi$cur_active_count *
  1274.                         (GET_INFO (CURRENT_WINDOW, "VISIBLE_LENGTH") + 2));
  1275.  
  1276.     vi$position (vi$first_no_space, 0);
  1277. ENDPROCEDURE;
  1278.  
  1279. !
  1280. ! Scroll forward one screen
  1281. !
  1282. PROCEDURE vi$screen_forward
  1283.  
  1284.     vi$scroll_screen (1);
  1285.  
  1286. ENDPROCEDURE;
  1287.  
  1288. !
  1289. ! Scroll back one screen
  1290. !
  1291. PROCEDURE vi$screen_backward
  1292.  
  1293.     vi$scroll_screen (-1);
  1294.  
  1295. ENDPROCEDURE;
  1296.  
  1297. !
  1298. !   Scroll the screen up or down depending on the sign of "how_many_screens"
  1299. !   The magnitude actually has effect as well, but is never greater than 1
  1300. !   in this use.
  1301. !
  1302. PROCEDURE vi$scroll_screen (how_many_screens)
  1303.  
  1304.     LOCAL
  1305.         scroll_window,          ! Window to be scrolled
  1306.         this_window,            ! Current window
  1307.         this_column,            ! Current column in scroll_window
  1308.         this_row,               ! Current row in scroll_window
  1309.         old_scroll_top,         ! Original value of scroll_top
  1310.         old_scroll_bottom,      ! Original value of scroll_bottom
  1311.         old_scroll_amount;      ! Original value of scroll_amount
  1312.  
  1313.     ! Trap and ignore messages about move beyond buffer boundaries -
  1314.     ! just move to top or bottom line of buffer
  1315.  
  1316.     ON_ERROR
  1317.     ENDON_ERROR;
  1318.  
  1319.     this_window := CURRENT_WINDOW;
  1320.  
  1321.     scroll_window := this_window;
  1322.  
  1323.     IF vi$active_count <> 0 THEN
  1324.         vi$how_much_scroll := vi$cur_active_count;
  1325.     ENDIF;
  1326.  
  1327.     this_row := GET_INFO (scroll_window, "CURRENT_ROW");
  1328.  
  1329.     IF this_row = 0 THEN
  1330.         this_row := GET_INFO (scroll_window, "VISIBLE_TOP");
  1331.     ENDIF;
  1332.  
  1333.     this_column := GET_INFO (scroll_window, "CURRENT_COLUMN");
  1334.     MOVE_HORIZONTAL (-CURRENT_OFFSET);
  1335.  
  1336.     old_scroll_top := GET_INFO (scroll_window, "SCROLL_TOP");
  1337.     old_scroll_bottom := GET_INFO (scroll_window, "SCROLL_BOTTOM");
  1338.     old_scroll_amount := GET_INFO (scroll_window, "SCROLL_AMOUNT");
  1339.  
  1340.     SET (SCROLLING, scroll_window, ON,
  1341.                     this_row - GET_INFO (scroll_window, "VISIBLE_TOP"),
  1342.                     GET_INFO (scroll_window, "VISIBLE_BOTTOM") - this_row, 0);
  1343.  
  1344.     MOVE_VERTICAL (how_many_screens * vi$how_much_scroll);
  1345.     vi$update (scroll_window);
  1346.  
  1347.     IF this_window <> CURRENT_WINDOW THEN
  1348.         POSITION (this_window);
  1349.     ENDIF;
  1350.  
  1351.     SET (SCROLLING, scroll_window, ON, old_scroll_top, old_scroll_bottom,
  1352.                                                             old_scroll_amount);
  1353. ENDPROCEDURE;
  1354.  
  1355. !
  1356. !   Move forward logical words
  1357. !
  1358. PROCEDURE vi$_word_forward
  1359.     vi$position (vi$word_move (1), 0);
  1360. ENDPROCEDURE;
  1361.  
  1362. !
  1363. !   Move backward logical words
  1364. !
  1365. PROCEDURE vi$_word_back
  1366.     vi$position (vi$word_move(-1), 0);
  1367. ENDPROCEDURE;
  1368.  
  1369. !
  1370. !   Move by logical word taking into account the repeat count
  1371. !
  1372. PROCEDURE vi$word_move(dir)
  1373.     LOCAL
  1374.         old_pos,
  1375.         pos;
  1376.  
  1377.     old_pos := MARK (NONE);
  1378.  
  1379.     IF vi$active_count <= 0 THEN
  1380.         vi$active_count := 1;
  1381.     ENDIF;
  1382.  
  1383.     LOOP
  1384.         pos := vi$move_logical_word (dir);
  1385.         EXITIF pos = 0;
  1386.         POSITION (pos);
  1387.         vi$active_count := vi$active_count - 1;
  1388.         EXITIF vi$active_count = 0;
  1389.     ENDLOOP;
  1390.  
  1391.     vi$yank_mode := VI$IN_LINE_MODE;
  1392.     RETURN (vi$retpos (old_pos));
  1393. ENDPROCEDURE;
  1394.  
  1395. !
  1396. !   Move to end of logical word
  1397. !
  1398. PROCEDURE vi$_word_end
  1399.     vi$position (vi$word_end, 0);
  1400. ENDPROCEDURE;
  1401.  
  1402. !
  1403. !   Move to end of physical word
  1404. !
  1405. PROCEDURE vi$_full_word_end
  1406.     vi$position (vi$full_word_end, 0);
  1407. ENDPROCEDURE;
  1408.  
  1409. !
  1410. !   Move to the end of the current word.
  1411. !
  1412. PROCEDURE vi$word_end
  1413.     LOCAL
  1414.         old_pos,
  1415.         pos;
  1416.  
  1417.     old_pos := MARK (NONE);
  1418.  
  1419.     IF vi$active_count <= 0 THEN
  1420.         vi$active_count := 1;
  1421.     ENDIF;
  1422.  
  1423.     LOOP
  1424.         pos := vi$move_logical_end;
  1425.         EXITIF pos = 0;
  1426.         POSITION (pos);
  1427.         vi$active_count := vi$active_count - 1;
  1428.         EXITIF vi$active_count = 0;
  1429.     ENDLOOP;
  1430.  
  1431.     vi$yank_mode := VI$IN_LINE_MODE;
  1432.     RETURN (vi$retpos (old_pos));
  1433. ENDPROCEDURE;
  1434.  
  1435. !
  1436. !   Move to the end of a blank (eol is also considered blank) terminated word.
  1437. !
  1438. PROCEDURE vi$full_word_end
  1439.  
  1440.     LOCAL
  1441.         old_pos,
  1442.         pos;
  1443.  
  1444.     old_pos := MARK (NONE);
  1445.  
  1446.     IF vi$active_count <= 0 THEN
  1447.         vi$active_count := 1;
  1448.     ENDIF;
  1449.  
  1450.     LOOP
  1451.         pos := vi$move_full_end;
  1452.         EXITIF pos = 0;
  1453.         POSITION (pos);
  1454.         vi$active_count := vi$active_count - 1;
  1455.         EXITIF vi$active_count = 0;
  1456.     ENDLOOP;
  1457.  
  1458.     vi$yank_mode := VI$IN_LINE_MODE;
  1459.     RETURN (vi$retpos (old_pos));
  1460. ENDPROCEDURE;
  1461.  
  1462. !
  1463. !   Move forward by ONE white-space delimited word
  1464. !
  1465. PROCEDURE vi$_full_word_forward
  1466.     vi$position (vi$full_word_move (1), 0);
  1467. ENDPROCEDURE;
  1468.  
  1469. !
  1470. !
  1471. !   Move backward by ONE white-space delimited word
  1472. !
  1473. PROCEDURE vi$_full_word_back
  1474.     vi$position (vi$full_word_move (-1), 0);
  1475. ENDPROCEDURE;
  1476.  
  1477. !
  1478. !   Move by physical word taking the repeat count into account
  1479. !
  1480. PROCEDURE vi$full_word_move (dir)
  1481.  
  1482.     LOCAL
  1483.         old_pos,
  1484.         pos;
  1485.  
  1486.     old_pos := MARK (NONE);
  1487.  
  1488.     IF vi$active_count <= 0 THEN
  1489.         vi$active_count := 1;
  1490.     ENDIF;
  1491.  
  1492.     LOOP
  1493.         pos := vi$move_full_word (dir);
  1494.         EXITIF pos = 0;
  1495.         POSITION (pos);
  1496.         vi$active_count := vi$active_count - 1;
  1497.         EXITIF vi$active_count = 0;
  1498.     ENDLOOP;
  1499.  
  1500.     vi$yank_mode := VI$IN_LINE_MODE;
  1501.     RETURN (vi$retpos (old_pos));
  1502. ENDPROCEDURE;
  1503.  
  1504. !
  1505. !   Move the cursor by BLANK separated words.  DIRECTION is either
  1506. !   +1, or -1 to indicate the direction (forward, or backword respectfully)
  1507. !   to move
  1508. !
  1509. PROCEDURE vi$move_full_word (direction)
  1510.  
  1511.     LOCAL
  1512.         pos;
  1513.  
  1514.     pos := MARK (NONE);
  1515.  
  1516. $$EOD$$
  1517.