source: trunk/minix/commands/elvis/vi.c@ 15

Last change on this file since 15 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 20.6 KB
Line 
1/* vi.c */
2
3/* Author:
4 * Steve Kirkendall
5 * Beaverton, OR 97005
6 * kirkenda@cs.pdx.edu
7 */
8
9
10#include "config.h"
11#include "ctype.h"
12#include "vi.h"
13
14
15
16/* This array describes what each key does */
17#define NO_FUNC (MARK (*)())0
18
19#define NO_ARGS 0
20#define CURSOR 1
21#define CURSOR_CNT_KEY 2
22#define CURSOR_MOVED 3
23#define CURSOR_EOL 4
24#define ZERO 5
25#define DIGIT 6
26#define CURSOR_TEXT 7
27#define KEYWORD 8
28#define ARGSMASK 0x0f
29#define C_C_K_REP1 (CURSOR_CNT_KEY | 0x10)
30#define C_C_K_CUT (CURSOR_CNT_KEY | 0x20)
31#define C_C_K_MARK (CURSOR_CNT_KEY | 0x30)
32#define C_C_K_CHAR (CURSOR_CNT_KEY | 0x40)
33#ifndef NO_SHOWMODE
34static int keymodes[] = {0, WHEN_REP1, WHEN_CUT, WHEN_MARK, WHEN_CHAR};
35# define KEYMODE(args) (keymodes[(args) >> 4])
36#else
37# define KEYMODE(args) 0
38#endif
39
40static struct keystru
41{
42 MARK (*func)(); /* the function to run */
43 uchar args; /* description of the args needed */
44#ifndef NO_VISIBLE
45 short flags;
46#else
47 uchar flags; /* other stuff */
48#endif
49}
50 vikeys[] =
51{
52/* NUL not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
53#ifndef NO_EXTENSIONS
54/* ^A find cursor word */ {m_wsrch, KEYWORD, MVMT|NREL|VIZ},
55#else
56/* ^A not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
57#endif
58/* ^B page backward */ {m_scroll, CURSOR, FRNT|VIZ},
59/* ^C not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
60/* ^D scroll dn 1/2page*/ {m_scroll, CURSOR, NCOL|VIZ},
61/* ^E scroll up */ {m_scroll, CURSOR, NCOL|VIZ},
62/* ^F page forward */ {m_scroll, CURSOR, FRNT|VIZ},
63/* ^G show file status */ {v_status, NO_ARGS, NO_FLAGS},
64/* ^H move left, like h*/ {m_left, CURSOR, MVMT|VIZ},
65/* ^I not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
66/* ^J move down */ {m_updnto, CURSOR, MVMT|LNMD|VIZ|INCL},
67/* ^K not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
68/* ^L redraw screen */ {v_redraw, NO_ARGS, NO_FLAGS|VIZ},
69/* ^M mv front next ln */ {m_updnto, CURSOR, MVMT|FRNT|LNMD|VIZ|INCL},
70/* ^N move down */ {m_updnto, CURSOR, MVMT|LNMD|VIZ|INCL|NCOL},
71/* ^O not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
72/* ^P move up */ {m_updnto, CURSOR, MVMT|LNMD|VIZ|INCL|NCOL},
73/* ^Q not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
74/* ^R redraw screen */ {v_redraw, NO_ARGS, NO_FLAGS|VIZ},
75/* ^S not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
76/* ^T not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
77/* ^U scroll up 1/2page*/ {m_scroll, CURSOR, NCOL|VIZ},
78/* ^V not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
79/* ^W not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
80/* ^X move to phys col */ {m_tocol, CURSOR, MVMT|NREL|VIZ},
81/* ^Y scroll down */ {m_scroll, CURSOR, NCOL|VIZ},
82#ifdef SIGTSTP
83/* ^Z suspend elvis */ {v_suspend, NO_ARGS, NO_FLAGS},
84#else
85/* ^Z not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
86#endif
87/* ESC not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
88/* ^\ not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
89/* ^] keyword is tag */ {v_tag, KEYWORD, NO_FLAGS},
90/* ^^ previous file */ {v_switch, CURSOR, NO_FLAGS},
91/* ^_ not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
92/* SPC move right,like l*/ {m_right, CURSOR, MVMT|INCL|VIZ},
93/* ! run thru filter */ {v_filter, CURSOR_MOVED, FRNT|LNMD|INCL|VIZ},
94/* " select cut buffer*/ {v_selcut, C_C_K_CUT, PTMV|VIZ},
95#ifndef NO_EXTENSIONS
96/* # increment number */ {v_increment, KEYWORD, SDOT},
97#else
98/* # not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
99#endif
100/* $ move to rear */ {m_rear, CURSOR, MVMT|INCL|VIZ},
101/* % move to match */ {m_match, CURSOR, MVMT|INCL|VIZ},
102/* & repeat subst */ {v_again, CURSOR_MOVED, SDOT|NCOL|LNMD|INCL},
103/* ' move to a mark */ {m_tomark, C_C_K_MARK, MVMT|FRNT|NREL|LNMD|INCL|VIZ},
104#ifndef NO_SENTENCE
105/* ( mv back sentence */ {m_sentence, CURSOR, MVMT|VIZ},
106/* ) mv fwd sentence */ {m_sentence, CURSOR, MVMT|VIZ},
107#else
108/* ( not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
109/* ) not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
110#endif
111#ifndef NO_ERRLIST
112/* * errlist */ {v_errlist, CURSOR, FRNT|NREL},
113#else
114/* * not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
115#endif
116/* + mv front next ln */ {m_updnto, CURSOR, MVMT|FRNT|LNMD|VIZ|INCL},
117#ifndef NO_CHARSEARCH
118/* , reverse [fFtT] cmd*/ {m__ch, CURSOR, MVMT|INCL|VIZ},
119#else
120/* , not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
121#endif
122/* - mv front prev ln */ {m_updnto, CURSOR, MVMT|FRNT|LNMD|VIZ|INCL},
123/* . special... */ {NO_FUNC, NO_ARGS, NO_FLAGS},
124/* / forward search */ {m_fsrch, CURSOR_TEXT, MVMT|NREL|VIZ},
125/* 0 part of count? */ {NO_FUNC, ZERO, MVMT|PTMV|VIZ},
126/* 1 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
127/* 2 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
128/* 3 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
129/* 4 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
130/* 5 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
131/* 6 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
132/* 7 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
133/* 8 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
134/* 9 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
135/* : run single EX cmd*/ {v_1ex, CURSOR_TEXT, NO_FLAGS},
136#ifndef NO_CHARSEARCH
137/* ; repeat [fFtT] cmd*/ {m__ch, CURSOR, MVMT|INCL|VIZ},
138#else
139/* ; not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS|VIZ},
140#endif
141/* < shift text left */ {v_lshift, CURSOR_MOVED, SDOT|FRNT|LNMD|INCL|VIZ},
142/* = preset filter */ {v_reformat, CURSOR_MOVED, SDOT|FRNT|LNMD|INCL|VIZ},
143/* > shift text right */ {v_rshift, CURSOR_MOVED, SDOT|FRNT|LNMD|INCL|VIZ},
144/* ? backward search */ {m_bsrch, CURSOR_TEXT, MVMT|NREL|VIZ},
145#ifndef NO_AT
146/* @ execute a cutbuf */ {v_at, C_C_K_CUT, NO_FLAGS},
147#else
148/* @ not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
149#endif
150/* A append at EOL */ {v_insert, CURSOR, SDOT},
151/* B move back Word */ {m_bword, CURSOR, MVMT|VIZ},
152/* C change to EOL */ {v_change, CURSOR_EOL, SDOT},
153/* D delete to EOL */ {v_delete, CURSOR_EOL, SDOT},
154/* E move end of Word */ {m_eword, CURSOR, MVMT|INCL|VIZ},
155#ifndef NO_CHARSEARCH
156/* F move bk to char */ {m_Fch, C_C_K_CHAR, MVMT|INCL|VIZ},
157#else
158/* F not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
159#endif
160/* G move to line # */ {m_updnto, CURSOR, MVMT|NREL|LNMD|FRNT|INCL|VIZ},
161/* H move to row */ {m_row, CURSOR, MVMT|LNMD|FRNT|VIZ|INCL},
162/* I insert at front */ {v_insert, CURSOR, SDOT},
163/* J join lines */ {v_join, CURSOR, SDOT},
164#ifndef NO_EXTENSIONS
165/* K look up keyword */ {v_keyword, KEYWORD, NO_FLAGS},
166#else
167/* K not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
168#endif
169/* L move to last row */ {m_row, CURSOR, MVMT|LNMD|FRNT|VIZ|INCL},
170/* M move to mid row */ {m_row, CURSOR, MVMT|LNMD|FRNT|VIZ|INCL},
171/* N reverse prev srch*/ {m_Nsrch, CURSOR, MVMT|NREL|VIZ},
172/* O insert above line*/ {v_insert, CURSOR, SDOT},
173/* P paste before */ {v_paste, CURSOR, SDOT},
174/* Q quit to EX mode */ {v_quit, NO_ARGS, NO_FLAGS},
175/* R overtype */ {v_overtype, CURSOR, SDOT},
176/* S change line */ {v_change, CURSOR_MOVED, SDOT},
177#ifndef NO_CHARSEARCH
178/* T move bk to char */ {m_Tch, C_C_K_CHAR, MVMT|INCL|VIZ},
179#else
180/* T not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
181#endif
182/* U undo whole line */ {v_undoline, CURSOR, FRNT},
183#ifndef NO_VISIBLE
184/* V start visible */ {v_start, CURSOR, INCL|LNMD|VIZ},
185#else
186/* V not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
187#endif
188/* W move forward Word*/ {m_fword, CURSOR, MVMT|INCL|VIZ},
189/* X delete to left */ {v_xchar, CURSOR, SDOT},
190/* Y yank text */ {v_yank, CURSOR_MOVED, NCOL},
191/* Z save file & exit */ {v_xit, CURSOR_CNT_KEY, NO_FLAGS},
192/* [ move back section*/ {m_paragraph, CURSOR, MVMT|LNMD|NREL|VIZ},
193#ifndef NO_POPUP
194/* \ pop-up menu */ {v_popup, CURSOR_MOVED, VIZ},
195#else
196/* \ not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
197#endif
198/* ] move fwd section */ {m_paragraph, CURSOR, MVMT|LNMD|NREL|VIZ},
199/* ^ move to front */ {m_front, CURSOR, MVMT|VIZ},
200/* _ current line */ {m_updnto, CURSOR, MVMT|LNMD|FRNT|INCL},
201/* ` move to mark */ {m_tomark, C_C_K_MARK, MVMT|NREL|VIZ},
202/* a append at cursor */ {v_insert, CURSOR, SDOT},
203/* b move back word */ {m_bword, CURSOR, MVMT|VIZ},
204/* c change text */ {v_change, CURSOR_MOVED, SDOT|VIZ},
205/* d delete op */ {v_delete, CURSOR_MOVED, SDOT|VIZ},
206/* e move end word */ {m_eword, CURSOR, MVMT|INCL|VIZ},
207#ifndef NO_CHARSEARCH
208/* f move fwd for char*/ {m_fch, C_C_K_CHAR, MVMT|INCL|VIZ},
209#else
210/* f not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
211#endif
212/* g not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
213/* h move left */ {m_left, CURSOR, MVMT|VIZ},
214/* i insert at cursor */ {v_insert, CURSOR, SDOT},
215/* j move down */ {m_updnto, CURSOR, MVMT|NCOL|LNMD|VIZ|INCL},
216/* k move up */ {m_updnto, CURSOR, MVMT|NCOL|LNMD|VIZ|INCL},
217/* l move right */ {m_right, CURSOR, MVMT|INCL|VIZ},
218/* m define a mark */ {v_mark, C_C_K_MARK, NO_FLAGS},
219/* n repeat prev srch */ {m_nsrch, CURSOR, MVMT|NREL|VIZ},
220/* o insert below line*/ {v_insert, CURSOR, SDOT},
221/* p paste after */ {v_paste, CURSOR, SDOT},
222/* q not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
223/* r replace chars */ {v_replace, C_C_K_REP1, SDOT},
224/* s subst N chars */ {v_subst, CURSOR, SDOT},
225#ifndef NO_CHARSEARCH
226/* t move fwd to char */ {m_tch, C_C_K_CHAR, MVMT|INCL|VIZ},
227#else
228/* t not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
229#endif
230/* u undo */ {v_undo, CURSOR, NO_FLAGS},
231#ifndef NO_VISIBLE
232/* v start visible */ {v_start, CURSOR, INCL|VIZ},
233#else
234/* v not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
235#endif
236/* w move fwd word */ {m_fword, CURSOR, MVMT|INCL|VIZ},
237/* x delete character */ {v_xchar, CURSOR, SDOT},
238/* y yank text */ {v_yank, CURSOR_MOVED, NCOL|VIZ},
239/* z adjust scrn row */ {m_z, CURSOR_CNT_KEY, NCOL|VIZ},
240/* { back paragraph */ {m_paragraph, CURSOR, MVMT|LNMD|VIZ},
241/* | move to column */ {m_tocol, CURSOR, MVMT|NREL|VIZ},
242/* } fwd paragraph */ {m_paragraph, CURSOR, MVMT|LNMD|VIZ},
243/* ~ upper/lowercase */ {v_ulcase, CURSOR, SDOT},
244/* DEL not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}
245};
246
247
248
249void vi()
250{
251 REG int key; /* keystroke from user */
252 long count; /* numeric argument to some functions */
253 REG struct keystru *keyptr;/* pointer to vikeys[] element */
254 MARK tcurs; /* temporary cursor */
255 int prevkey;/* previous key, if d/c/y/</>/! */
256 MARK range; /* start of range for d/c/y/</>/! */
257 char text[132];
258 int dotkey; /* last "key" of a change */
259 int dotpkey;/* last "prevkey" of a change */
260 int dotkey2;/* last extra "getkey()" of a change */
261 int dotcnt; /* last "count" of a change */
262 int firstkey;
263 REG int i;
264
265 /* tell the redraw() function to start from scratch */
266 redraw(MARK_UNSET, FALSE);
267
268#ifdef lint
269 /* lint says that "range" might be used before it is set. This
270 * can't really happen due to the way "range" and "prevkey" are used,
271 * but lint doesn't know that. This line is here ONLY to keep lint
272 * happy.
273 */
274 range = 0L;
275#endif
276
277 /* safeguard against '.' with no previous command */
278 dotkey = dotpkey = dotkey2 = dotcnt = 0;
279
280 /* go immediately into insert mode, if ":set inputmode" */
281 firstkey = 0;
282#ifndef NO_EXTENSIONS
283 if (*o_inputmode)
284 {
285 firstkey = 'i';
286 }
287#endif
288
289 /* Repeatedly handle VI commands */
290 for (count = 0, prevkey = '\0'; mode == MODE_VI; )
291 {
292 /* if we've moved off the undoable line, then we can't undo it at all */
293 if (markline(cursor) != U_line)
294 {
295 U_line = 0L;
296 }
297
298 /* report any changes from the previous command */
299 if (rptlines >= *o_report)
300 {
301 redraw(cursor, FALSE);
302 msg("%ld line%s %s", rptlines, (rptlines==1?"":"s"), rptlabel);
303 }
304 rptlines = 0L;
305
306 /* get the next command key. It must be ASCII */
307 if (firstkey)
308 {
309 key = firstkey;
310 firstkey = 0;
311 }
312 else
313 {
314 do
315 {
316 key = getkey(WHEN_VICMD);
317 } while (key < 0 || key > 127);
318 }
319
320 /* Convert a doubled-up operator such as "dd" into "d_" */
321 if (prevkey && key == prevkey)
322 {
323 key = '_';
324 }
325
326 /* look up the structure describing this command */
327 keyptr = &vikeys[key];
328
329 /* '&' and uppercase operators always act like doubled */
330 if (!prevkey && keyptr->args == CURSOR_MOVED
331 && (key == '&' || isupper(key)))
332 {
333 range = cursor;
334 prevkey = key;
335 key = '_';
336 keyptr = &vikeys[key];
337 }
338
339#ifndef NO_VISIBLE
340 /* if we're in the middle of a v/V command, reject commands
341 * that aren't operators or movement commands
342 */
343 if (V_from && !(keyptr->flags & VIZ))
344 {
345 beep();
346 prevkey = 0;
347 count = 0;
348 continue;
349 }
350#endif
351
352 /* if we're in the middle of a d/c/y/</>/! command, reject
353 * anything but movement.
354 */
355 if (prevkey && !(keyptr->flags & (MVMT|PTMV)))
356 {
357 beep();
358 prevkey = 0;
359 count = 0;
360 continue;
361 }
362
363 /* set the "dot" variables, if we're supposed to */
364 if (((keyptr->flags & SDOT)
365 || (prevkey && vikeys[prevkey].flags & SDOT))
366#ifndef NO_VISIBLE
367 && !V_from
368#endif
369 )
370 {
371 dotkey = key;
372 dotpkey = prevkey;
373 dotkey2 = '\0';
374 dotcnt = count;
375
376 /* remember the line before any changes are made */
377 if (U_line != markline(cursor))
378 {
379 U_line = markline(cursor);
380 strcpy(U_text, fetchline(U_line));
381 }
382 }
383
384 /* if this is "." then set other vars from the "dot" vars */
385 if (key == '.')
386 {
387 key = dotkey;
388 keyptr = &vikeys[key];
389 prevkey = dotpkey;
390 if (prevkey)
391 {
392 range = cursor;
393 }
394 if (count == 0)
395 {
396 count = dotcnt;
397 }
398 doingdot = TRUE;
399
400 /* remember the line before any changes are made */
401 if (U_line != markline(cursor))
402 {
403 U_line = markline(cursor);
404 strcpy(U_text, fetchline(U_line));
405 }
406 }
407 else
408 {
409 doingdot = FALSE;
410 }
411
412 /* process the key as a command */
413 tcurs = cursor;
414 force_flags = NO_FLAGS;
415 switch (keyptr->args & ARGSMASK)
416 {
417 case ZERO:
418 if (count == 0)
419 {
420 tcurs = cursor & ~(BLKSIZE - 1);
421 break;
422 }
423 /* else fall through & treat like other digits... */
424
425 case DIGIT:
426 count = count * 10 + key - '0';
427 break;
428
429 case KEYWORD:
430 /* if not on a keyword, fail */
431 pfetch(markline(cursor));
432 key = markidx(cursor);
433 if (!isalnum(ptext[key]))
434 {
435 tcurs = MARK_UNSET;
436 break;
437 }
438
439 /* find the start of the keyword */
440 while (key > 0 && isalnum(ptext[key - 1]))
441 {
442 key--;
443 }
444 tcurs = (cursor & ~(BLKSIZE - 1)) + key;
445
446 /* copy it into a buffer, and NUL-terminate it */
447 i = 0;
448 do
449 {
450 text[i++] = ptext[key++];
451 } while (isalnum(ptext[key]));
452 text[i] = '\0';
453
454 /* call the function */
455 tcurs = (*keyptr->func)(text, tcurs, count);
456 count = 0L;
457 break;
458
459 case NO_ARGS:
460 if (keyptr->func)
461 {
462 (*keyptr->func)();
463 }
464 else
465 {
466 beep();
467 }
468 count = 0L;
469 break;
470
471 case CURSOR:
472 tcurs = (*keyptr->func)(cursor, count, key, prevkey);
473 count = 0L;
474 break;
475
476 case CURSOR_CNT_KEY:
477 if (doingdot)
478 {
479 tcurs = (*keyptr->func)(cursor, count, dotkey2);
480 }
481 else
482 {
483 /* get a key */
484 i = getkey(KEYMODE(keyptr->args));
485 if (i == '\033') /* ESC */
486 {
487 count = 0;
488 tcurs = MARK_UNSET;
489 break; /* exit from "case CURSOR_CNT_KEY" */
490 }
491 else if (i == ctrl('V'))
492 {
493 i = getkey(0);
494 }
495
496 /* if part of an SDOT command, remember it */
497 if (keyptr->flags & SDOT
498 || (prevkey && vikeys[prevkey].flags & SDOT))
499 {
500 dotkey2 = i;
501 }
502
503 /* do it */
504 tcurs = (*keyptr->func)(cursor, count, i);
505 }
506 count = 0L;
507 break;
508
509 case CURSOR_MOVED:
510#ifndef NO_VISIBLE
511 if (V_from)
512 {
513 range = cursor;
514 tcurs = V_from;
515 count = 0L;
516 prevkey = key;
517 key = (V_linemd ? 'V' : 'v');
518 keyptr = &vikeys[key];
519 }
520 else
521#endif
522 {
523 prevkey = key;
524 range = cursor;
525 force_flags = LNMD|INCL;
526 }
527 break;
528
529 case CURSOR_EOL:
530 prevkey = key;
531 /* a zero-length line needs special treatment */
532 pfetch(markline(cursor));
533 if (plen == 0)
534 {
535 /* act on a zero-length section of text */
536 range = tcurs = cursor;
537 key = '0';
538 }
539 else
540 {
541 /* act like CURSOR_MOVED with '$' movement */
542 range = cursor;
543 tcurs = m_rear(cursor, 1L);
544 key = '$';
545 }
546 count = 0L;
547 keyptr = &vikeys[key];
548 break;
549
550 case CURSOR_TEXT:
551 do
552 {
553 text[0] = key;
554 if (vgets(key, text + 1, sizeof text - 1) >= 0)
555 {
556 /* reassure user that <CR> was hit */
557 qaddch('\r');
558 refresh();
559
560 /* call the function with the text */
561 tcurs = (*keyptr->func)(cursor, text);
562 }
563 else
564 {
565 if (exwrote || mode == MODE_COLON)
566 {
567 redraw(MARK_UNSET, FALSE);
568 }
569 mode = MODE_VI;
570 }
571 } while (mode == MODE_COLON);
572 count = 0L;
573 break;
574 }
575
576 /* if that command took us out of vi mode, then exit the loop
577 * NOW, without tweaking the cursor or anything. This is very
578 * important when mode == MODE_QUIT.
579 */
580 if (mode != MODE_VI)
581 {
582 break;
583 }
584
585 /* now move the cursor, as appropriate */
586 if (keyptr->args == CURSOR_MOVED)
587 {
588 /* the < and > keys have FRNT,
589 * but it shouldn't be applied yet
590 */
591 tcurs = adjmove(cursor, tcurs, 0);
592 }
593 else
594 {
595 tcurs = adjmove(cursor, tcurs, (int)keyptr->flags | force_flags);
596 }
597
598 /* was that the end of a d/c/y/</>/! command? */
599 if (prevkey && ((keyptr->flags & MVMT)
600#ifndef NO_VISIBLE
601 || V_from
602#endif
603 ) && count == 0L)
604 {
605#ifndef NO_VISIBLE
606 /* turn off the hilight */
607 V_from = 0L;
608#endif
609
610 /* if the movement command failed, cancel operation */
611 if (tcurs == MARK_UNSET)
612 {
613 prevkey = 0;
614 count = 0;
615 continue;
616 }
617
618 /* make sure range=front and tcurs=rear. Either way,
619 * leave cursor=range since that's where we started.
620 */
621 cursor = range;
622 if (tcurs < range)
623 {
624 range = tcurs;
625 tcurs = cursor;
626 }
627
628 /* The 'w' and 'W' destinations should never take us
629 * to the front of a line. Instead, they should take
630 * us only to the end of the preceding line.
631 */
632 if ((keyptr->flags & (MVMT|NREL|LNMD|FRNT|INCL)) == MVMT
633 && markline(range) < markline(tcurs)
634 && (markline(tcurs) > nlines || tcurs == m_front(tcurs, 0L)))
635 {
636 tcurs = (tcurs & ~(BLKSIZE - 1)) - BLKSIZE;
637 pfetch(markline(tcurs));
638 tcurs += plen;
639 }
640
641 /* adjust for line mode & inclusion of last char/line */
642 i = (keyptr->flags | vikeys[prevkey].flags);
643 switch ((i | force_flags) & (INCL|LNMD))
644 {
645 case INCL:
646 tcurs++;
647 break;
648
649 case INCL|LNMD:
650 tcurs += BLKSIZE;
651 /* fall through... */
652
653 case LNMD:
654 range &= ~(BLKSIZE - 1);
655 tcurs &= ~(BLKSIZE - 1);
656 break;
657 }
658
659 /* run the function */
660 tcurs = (*vikeys[prevkey].func)(range, tcurs);
661 if (mode == MODE_VI)
662 {
663 (void)adjmove(cursor, cursor, 0);
664 cursor = adjmove(cursor, tcurs, (int)vikeys[prevkey].flags);
665 }
666
667 /* cleanup */
668 prevkey = 0;
669 }
670 else if (!prevkey)
671 {
672 if (tcurs != MARK_UNSET)
673 cursor = tcurs;
674 }
675 }
676}
677
678/* This function adjusts the MARK value that they return; here we make sure
679 * it isn't past the end of the line, and that the column hasn't been
680 * *accidentally* changed.
681 */
682MARK adjmove(old, new, flags)
683 MARK old; /* the cursor position before the command */
684 REG MARK new; /* the cursor position after the command */
685 int flags; /* various flags regarding cursor mvmt */
686{
687 static int colno; /* the column number that we want */
688 REG char *text; /* used to scan through the line's text */
689 REG int i;
690
691#ifdef DEBUG
692 watch();
693#endif
694
695 /* if the command failed, bag it! */
696 if (new == MARK_UNSET)
697 {
698 beep();
699 return old;
700 }
701
702 /* if this is a non-relative movement, set the '' mark */
703 if (flags & NREL)
704 {
705 mark[26] = old;
706 }
707
708 /* make sure it isn't past the end of the file */
709 if (markline(new) < 1)
710 {
711 new = MARK_FIRST;
712 }
713 else if (markline(new) > nlines)
714 {
715 new = MARK_LAST;
716 }
717
718 /* fetch the new line */
719 pfetch(markline(new));
720
721 /* move to the front, if we're supposed to */
722 if (flags & FRNT)
723 {
724 new = m_front(new, 1L);
725 }
726
727 /* change the column#, or change the mark to suit the column# */
728 if (!(flags & NCOL))
729 {
730 /* change the column# */
731 i = markidx(new);
732 if (i == BLKSIZE - 1)
733 {
734 new &= ~(BLKSIZE - 1);
735 if (plen > 0)
736 {
737 new += plen - 1;
738 }
739 colno = BLKSIZE * 8; /* one heck of a big colno */
740 }
741 else if (plen > 0)
742 {
743 if (i >= plen)
744 {
745 new = (new & ~(BLKSIZE - 1)) + plen - 1;
746 }
747 colno = idx2col(new, ptext, FALSE);
748 }
749 else
750 {
751 new &= ~(BLKSIZE - 1);
752 colno = 0;
753 }
754 }
755 else
756 {
757 /* adjust the mark to get as close as possible to column# */
758 for (i = 0, text = ptext; i <= colno && *text; text++)
759 {
760 if (*text == '\t' && !*o_list)
761 {
762 i += *o_tabstop - (i % *o_tabstop);
763 }
764 else if (UCHAR(*text) < ' ' || *text == 127)
765 {
766 i += 2;
767 }
768#ifndef NO_CHARATTR
769 else if (*o_charattr && text[0] == '\\' && text[1] == 'f' && text[2])
770 {
771 text += 2; /* plus one more in "for()" stmt */
772 }
773#endif
774 else
775 {
776 i++;
777 }
778 }
779 if (text > ptext)
780 {
781 text--;
782 }
783 new = (new & ~(BLKSIZE - 1)) + (int)(text - ptext);
784 }
785
786 return new;
787}
788
789
790#ifdef DEBUG
791watch()
792{
793 static wasset;
794
795 if (*origname)
796 {
797 wasset = TRUE;
798 }
799 else if (wasset)
800 {
801 mode = MODE_EX;
802 msg("origname was clobbered");
803 endwin();
804 abort();
805 }
806
807 if (wasset && nlines == 0)
808 {
809 mode = MODE_EX;
810 msg("nlines=0");
811 endwin();
812 abort();
813 }
814}
815#endif
Note: See TracBrowser for help on using the repository browser.