|
|
1.1 root 1: /* input.c */
2:
3: /* Author:
4: * Steve Kirkendall
5: * 14407 SW Teal Blvd. #C
6: * Beaverton, OR 97005
7: * [email protected]
8: */
9:
10:
11: /* This file contains the input() function, which implements vi's INPUT mode.
12: * It also contains the code that supports digraphs.
13: */
14:
15: #include "config.h"
16: #include "ctype.h"
17: #include "vi.h"
18:
19:
20: #ifndef NO_DIGRAPH
21: static struct _DIG
22: {
23: struct _DIG *next;
24: char key1;
25: char key2;
26: char dig;
27: char save;
28: } *digs;
29:
30: char digraph(key1, key2)
31: int key1; /* the underlying character */
32: int key2; /* the second character */
33: {
34: int newkey;
35: REG struct _DIG *dp;
36:
37: /* if digraphs are disabled, then just return the new char */
38: if (!*o_digraph)
39: {
40: return key2;
41: }
42:
43: /* remember the new key, so we can return it if this isn't a digraph */
44: newkey = key2;
45:
46: /* sort key1 and key2, so that their original order won't matter */
47: if (key1 > key2)
48: {
49: key2 = key1;
50: key1 = newkey;
51: }
52:
53: /* scan through the digraph chart */
54: for (dp = digs;
55: dp && (dp->key1 != key1 || dp->key2 != key2);
56: dp = dp->next)
57: {
58: }
59:
60: /* if this combination isn't in there, just use the new key */
61: if (!dp)
62: {
63: return newkey;
64: }
65:
66: /* else use the digraph key */
67: return dp->dig;
68: }
69:
70: /* this function lists or defines digraphs */
71: void do_digraph(bang, extra)
72: int bang;
73: char extra[];
74: {
75: int dig;
76: REG struct _DIG *dp;
77: struct _DIG *prev;
78: static int user_defined = FALSE; /* boolean: are all later digraphs user-defined? */
79: char listbuf[8];
80:
81: /* if "extra" is NULL, then we've reached the end of the built-ins */
82: if (!extra)
83: {
84: user_defined = TRUE;
85: return;
86: }
87:
88: /* if no args, then display the existing digraphs */
89: if (*extra < ' ')
90: {
91: listbuf[0] = listbuf[1] = listbuf[2] = listbuf[5] = ' ';
92: listbuf[7] = '\0';
93: for (dig = 0, dp = digs; dp; dp = dp->next)
94: {
95: if (dp->save || bang)
96: {
97: dig += 7;
98: if (dig >= COLS)
99: {
100: addch('\n');
101: exrefresh();
102: dig = 7;
103: }
104: listbuf[3] = dp->key1;
105: listbuf[4] = dp->key2;
106: listbuf[6] = dp->dig;
107: qaddstr(listbuf);
108: }
109: }
110: addch('\n');
111: exrefresh();
112: return;
113: }
114:
115: /* make sure we have at least two characters */
116: if (!extra[1])
117: {
118: msg("Digraphs must be composed of two characters");
119: return;
120: }
121:
122: /* sort key1 and key2, so that their original order won't matter */
123: if (extra[0] > extra[1])
124: {
125: dig = extra[0];
126: extra[0] = extra[1];
127: extra[1] = dig;
128: }
129:
130: /* locate the new digraph character */
131: for (dig = 2; extra[dig] == ' ' || extra[dig] == '\t'; dig++)
132: {
133: }
134: dig = extra[dig];
135: if (!bang && dig)
136: {
137: dig |= 0x80;
138: }
139:
140: /* search for the digraph */
141: for (prev = (struct _DIG *)0, dp = digs;
142: dp && (dp->key1 != extra[0] || dp->key2 != extra[1]);
143: prev = dp, dp = dp->next)
144: {
145: }
146:
147: /* deleting the digraph? */
148: if (!dig)
149: {
150: if (!dp)
151: {
152: #ifndef CRUNCH
153: msg("%c%c not a digraph", extra[0], extra[1]);
154: #endif
155: return;
156: }
157: if (prev)
158: prev->next = dp->next;
159: else
160: digs = dp->next;
161: _free_(dp);
162: return;
163: }
164:
165: /* if necessary, create a new digraph struct for the new digraph */
166: if (dig && !dp)
167: {
168: dp = (struct _DIG *)malloc(sizeof *dp);
169: if (!dp)
170: {
171: msg("Out of space in the digraph table");
172: return;
173: }
174: if (prev)
175: prev->next = dp;
176: else
177: digs = dp;
178: dp->next = (struct _DIG *)0;
179: }
180:
181: /* assign it the new digraph value */
182: dp->key1 = extra[0];
183: dp->key2 = extra[1];
184: dp->dig = dig;
185: dp->save = user_defined;
186: }
187:
188: # ifndef NO_MKEXRC
189: void savedigs(fd)
190: int fd;
191: {
192: static char buf[] = "digraph! XX Y\n";
193: REG struct _DIG *dp;
194:
195: for (dp = digs; dp; dp = dp->next)
196: {
197: if (dp->save)
198: {
199: buf[9] = dp->key1;
200: buf[10] = dp->key2;
201: buf[12] = dp->dig;
202: write(fd, buf, (unsigned)14);
203: }
204: }
205: }
206: # endif
207: #endif
208:
209:
210: /* This function allows the user to replace an existing (possibly zero-length)
211: * chunk of text with typed-in text. It returns the MARK of the last character
212: * that the user typed in.
213: */
214: MARK input(from, to, when, delta)
215: MARK from; /* where to start inserting text */
216: MARK to; /* extent of text to delete */
217: int when; /* either WHEN_VIINP or WHEN_VIREP */
218: int delta; /* 1 to take indent from lower line, -1 for upper, 0 for none */
219: {
220: char key[2]; /* key char followed by '\0' char */
221: char *build; /* used in building a newline+indent string */
222: char *scan; /* used while looking at the indent chars of a line */
223: MARK m; /* some place in the text */
224: #ifndef NO_EXTENSIONS
225: int quit = FALSE; /* boolean: are we exiting after this? */
226: int inchg; /* boolean: have we done a "beforedo()" yet? */
227: #endif
228:
229: #ifdef DEBUG
230: /* if "from" and "to" are reversed, complain */
231: if (from > to)
232: {
233: msg("ERROR: input(%ld:%d, %ld:%d)",
234: markline(from), markidx(from),
235: markline(to), markidx(to));
236: return MARK_UNSET;
237: }
238: #endif
239:
240: key[1] = 0;
241:
242: /* if we're replacing text with new text, save the old stuff */
243: /* (Alas, there is no easy way to save text for replace mode) */
244: if (from != to)
245: {
246: cut(from, to);
247: }
248:
249: /* if doing a dot command, then reuse the previous text */
250: if (doingdot)
251: {
252: ChangeText
253: {
254: /* delete the text that's there now */
255: if (from != to)
256: {
257: delete(from, to);
258: }
259:
260: /* insert the previous text */
261: cutname('.');
262: cursor = paste(from, FALSE, TRUE) + 1L;
263: }
264: }
265: else /* interactive version */
266: {
267: /* assume that whoever called this already did a beforedo() */
268: #ifndef NO_EXTENSIONS
269: inchg = TRUE;
270: #endif
271:
272: /* if doing a change within the line... */
273: if (from != to && markline(from) == markline(to))
274: {
275: /* mark the end of the text with a "$" */
276: change(to - 1, to, "$");
277: }
278: else
279: {
280: /* delete the old text right off */
281: if (from != to)
282: {
283: delete(from, to);
284: }
285: to = from;
286: }
287:
288: /* handle autoindent of the first line, maybe */
289: cursor = from;
290: m = cursor + MARK_AT_LINE(delta);
291: if (delta != 0 && *o_autoindent && markidx(m) == 0
292: && markline(m) >= 1L && markline(m) <= nlines)
293: {
294: /* Only autoindent blank lines. */
295: pfetch(markline(cursor));
296: if (plen == 0)
297: {
298: /* Okay, we really want to autoindent */
299: pfetch(markline(m));
300: for (scan = ptext, build = tmpblk.c;
301: *scan == ' ' || *scan == '\t';
302: )
303: {
304: *build++ = *scan++;
305: }
306: if (build > tmpblk.c)
307: {
308: *build = '\0';
309: add(cursor, tmpblk.c);
310: cursor += (int)(build - tmpblk.c);
311: if (cursor > to)
312: to = cursor;
313: }
314: }
315: }
316:
317: /* repeatedly add characters from the user */
318: for (;;)
319: {
320: /* Get a character */
321: redraw(cursor, TRUE);
322: #ifdef DEBUG2
323: msg("cursor=%ld.%d, to=%ld.%d",
324: markline(cursor), markidx(cursor),
325: markline(to), markidx(to));
326: #endif
327: #ifndef NO_ABBR
328: pfetch(markline(cursor));
329: build = ptext;
330: if (pline == markline(from))
331: build += markidx(from);
332: for (scan = ptext + markidx(cursor); --scan >= build && isalnum(*scan); )
333: {
334: }
335: scan++;
336: key[0] = getabkey(when, scan, (int)(ptext + markidx(cursor) - scan));
337: #else
338: key[0] = getkey(when);
339: #endif
340: #ifndef NO_VISIBLE
341: if (key[0] != '\0' && V_from != MARK_UNSET)
342: {
343: msg("Can't modify text during a selection");
344: beep();
345: continue;
346: }
347: #endif
348:
349: #ifndef NO_EXTENSIONS
350: if (key[0] == ctrl('O'))
351: {
352: if (inchg)
353: {
354: if (cursor < to)
355: {
356: delete(cursor, to);
357: redraw(cursor, TRUE);
358: }
359: afterdo();
360: inchg = FALSE;
361: }
362: }
363: else if (key[0] != ctrl('['))
364: {
365: if (!inchg)
366: {
367: beforedo(FALSE);
368: inchg = TRUE;
369: }
370: }
371: #endif
372:
373: #ifndef CRUNCH
374: /* if wrapmargin is set & we're past the
375: * warpmargin, then change the last whitespace
376: * characters on line into a newline
377: */
378: if (*o_wrapmargin != 0)
379: {
380: pfetch(markline(cursor));
381: if (plen == idx2col(cursor, ptext, TRUE)
382: && plen > COLS - (*o_wrapmargin & 0xff))
383: {
384: build = tmpblk.c;
385: *build++ = '\n';
386: if (*o_autoindent)
387: {
388: /* figure out indent for next line */
389: for (scan = ptext; *scan == ' ' || *scan == '\t'; )
390: {
391: *build++ = *scan++;
392: }
393: }
394: *build = '\0';
395:
396: scan = ptext + plen;
397: m = cursor & ~(BLKSIZE - 1);
398: while (ptext < scan)
399: {
400: scan--;
401: if (*scan != ' ' && *scan != '\t')
402: continue;
403:
404: /*break up line, and we do autoindent if needed*/
405: change(m + (int)(scan - ptext), m + (int)(scan - ptext) + 1, tmpblk.c);
406:
407: /* NOTE: for some reason, MSC 5.10 doesn't
408: * like for these lines to be combined!!!
409: */
410: cursor = (cursor & ~(BLKSIZE - 1));
411: cursor += BLKSIZE;
412: cursor += strlen(tmpblk.c) - 1;
413: cursor += plen - (int)(scan - ptext) - 1;
414:
415: /*remove trailing spaces on previous line*/
416: pfetch(markline(m));
417: scan = ptext + plen;
418: while (ptext < scan)
419: {
420: scan--;
421: if (*scan != ' ' && *scan != '\t')
422: break;
423: }
424: delete(m + (int)(scan - ptext) + 1, m + plen);
425:
426: break;
427: }
428: }
429: }
430: #endif /* !CRUNCH */
431:
432: /* process it */
433: switch (*key)
434: {
435: #ifndef NO_EXTENSIONS
436: case ctrl('O'): /* special movement mapped keys */
437: *key = getkey(0);
438: switch (*key)
439: {
440: case 'h': m = m_left(cursor, 0L); break;
441: case 'j':
442: case 'k': m = m_updnto(cursor, 0L, *key); break;
443: case 'l': m = cursor + 1; break;
444: case 'B':
445: case 'b': m = m_bword(cursor, 0L, *key); break;
446: case 'W':
447: case 'w': m = m_fword(cursor, 0L, *key, '\0'); break;
448: case '^': m = m_front(cursor, 0L); break;
449: case '$': m = m_rear(cursor, 0L); break;
450: case ctrl('B'):
451: case ctrl('F'):
452: m = m_scroll(cursor, 0L, *key); break;
453: case 'x':
454: #ifndef NO_VISIBLE
455: if (V_from)
456: beep();
457: else
458: #endif
459: ChangeText
460: {
461: m = v_xchar(cursor, 0L, 'x');
462: }
463: break;
464: case 'i': m = to = from = cursor;
465: when = WHEN_VIINP + WHEN_VIREP - when;
466: break;
467: case 'K':
468: pfetch(markline(cursor));
469: changes++; /* <- after this, we can alter ptext */
470: ptext[markidx(cursor)] = 0;
471: for (scan = ptext + markidx(cursor) - 1;
472: scan >= ptext && isalnum(*scan);
473: scan--)
474: {
475: }
476: scan++;
477: m = (*scan ? v_keyword(scan, cursor, 0L) : cursor);
478: break;
479:
480: # ifndef NO_VISIBLE
481: case 'v':
482: case 'V':
483: if (V_from)
484: V_from = MARK_UNSET;
485: else
486: V_from = cursor;
487: m = from = to = cursor;
488: V_linemd = (*key == 'V');
489: break;
490:
491: case 'd':
492: case 'y':
493: case '\\':
494: /* do nothing if unmarked */
495: if (!V_from)
496: {
497: msg("You must mark the text first");
498: beep();
499: break;
500: }
501:
502: /* "from" must come before "to" */
503: if (V_from < cursor)
504: {
505: from = V_from;
506: to = cursor;
507: }
508: else
509: {
510: from = cursor;
511: to = V_from;
512: }
513:
514: /* we don't need V_from anymore */
515: V_from = MARK_UNSET;
516:
517: if (V_linemd)
518: {
519: /* adjust for line mode */
520: from &= ~(BLKSIZE - 1);
521: to |= (BLKSIZE - 1);
522: }
523: else
524: {
525: /* in character mode, we must
526: * worry about deleting the newline
527: * at the end of the last line
528: */
529: pfetch(markline(to));
530: if (markidx(to) == plen)
531: to |= (BLKSIZE - 1);
532: }
533: to++;
534:
535: switch (*key)
536: {
537: case 'y':
538: cut(from, to);
539: break;
540:
541: case 'd':
542: ChangeText
543: {
544: cut(from, to);
545: delete(from, to);
546: }
547: cursor = from;
548: break;
549:
550: #ifndef NO_POPUP
551: case '\\':
552: ChangeText
553: {
554: cursor = v_popup(from, to);
555: }
556: break;
557: #endif
558: }
559: m = from = to = cursor;
560: break;
561:
562: case 'p':
563: case 'P':
564: V_from = MARK_UNSET;
565: ChangeText
566: {
567: m = from = to = cursor = paste(cursor, (*key == 'p'), FALSE);
568: }
569: break;
570: # endif /* !NO_VISIBLE */
571: default: m = MARK_UNSET;
572: }
573:
574: /* adjust the moved cursor */
575: if (m != cursor)
576: {
577: m = adjmove(cursor, m, (*key == 'j' || *key == 'k' ? NCOL|FINL : FINL));
578: if (*key == '$' || (*key == 'l' && m <= cursor))
579: {
580: m++;
581: }
582: }
583:
584: /* if the cursor is reasonable, use it */
585: if (m == MARK_UNSET)
586: {
587: beep();
588: }
589: else
590: {
591: from = to = cursor = m;
592: }
593: break;
594:
595: case ctrl('Z'):
596: if (getkey(0) == ctrl('Z'))
597: {
598: quit = TRUE;
599: goto BreakBreak;
600: }
601: break;
602: #endif
603:
604: case ctrl('['):
605: /* if last line contains only whitespace, then remove whitespace */
606: if (*o_autoindent)
607: {
608: pfetch(markline(cursor));
609: for (scan = ptext; isspace(*scan); scan++)
610: {
611: }
612: if (scan > ptext && !*scan)
613: {
614: cursor &= ~(BLKSIZE - 1L);
615: if (to < cursor + plen)
616: {
617: to = cursor + plen;
618: }
619: }
620: }
621: goto BreakBreak;
622:
623: case ctrl('U'):
624: if (markline(cursor) == markline(from))
625: {
626: cursor = from;
627: }
628: else
629: {
630: cursor &= ~(BLKSIZE - 1);
631: }
632: break;
633:
634: case ctrl('D'):
635: case ctrl('T'):
636: if (to > cursor)
637: {
638: delete(cursor, to);
639: }
640: mark[27] = cursor;
641: cmd_shift(cursor, cursor, *key == ctrl('D') ? CMD_SHIFTL : CMD_SHIFTR, TRUE, "");
642: if (mark[27])
643: {
644: cursor = mark[27];
645: }
646: else
647: {
648: cursor = m_front(cursor, 0L);
649: }
650: to = cursor;
651: break;
652:
653: case '\b':
654: if (cursor <= from)
655: {
656: beep();
657: }
658: else if (markidx(cursor) == 0)
659: {
660: cursor -= BLKSIZE;
661: pfetch(markline(cursor));
662: cursor += plen;
663: }
664: else
665: {
666: cursor--;
667: }
668: break;
669:
670: case ctrl('W'):
671: m = m_bword(cursor, 1L, 'b');
672: if (markline(m) == markline(cursor) && m >= from)
673: {
674: cursor = m;
675: if (from > cursor)
676: {
677: from = cursor;
678: }
679: }
680: else
681: {
682: beep();
683: }
684: break;
685:
686: case '\n':
687: #if OSK
688: case '\l':
689: #else
690: case '\r':
691: #endif
692: build = tmpblk.c;
693: *build++ = '\n';
694: if (*o_autoindent)
695: {
696: /* figure out indent for next line */
697: pfetch(markline(cursor));
698: for (scan = ptext; *scan == ' ' || *scan == '\t'; )
699: {
700: *build++ = *scan++;
701: }
702:
703: /* remove indent from this line, if blank */
704: if ((int)(scan - ptext) >= markidx(cursor) && plen > 0)
705: {
706: to = cursor &= ~(BLKSIZE - 1);
707: delete(cursor, cursor + (int)(scan - ptext));
708: }
709: }
710: *build = 0;
711: if (cursor >= to && when != WHEN_VIREP)
712: {
713: add(cursor, tmpblk.c);
714: }
715: else
716: {
717: change(cursor, to, tmpblk.c);
718: }
719: redraw(cursor, TRUE);
720: to = cursor = (cursor & ~(BLKSIZE - 1))
721: + BLKSIZE
722: + (int)(build - tmpblk.c) - 1;
723: break;
724:
725: case ctrl('A'):
726: case ctrl('P'):
727: if (cursor < to)
728: {
729: delete(cursor, to);
730: }
731: if (*key == ctrl('A'))
732: {
733: cutname('.');
734: }
735: to = cursor = paste(cursor, FALSE, TRUE) + 1L;
736: break;
737:
738: case ctrl('V'):
739: if (cursor >= to && when != WHEN_VIREP)
740: {
741: add(cursor, "^");
742: }
743: else
744: {
745: change(cursor, to, "^");
746: to = cursor + 1;
747: }
748: redraw(cursor, TRUE);
749: *key = getkey(0);
750: if (*key == '\n')
751: {
752: /* '\n' too hard to handle */
753: #if OSK
754: *key = '\l';
755: #else
756: *key = '\r';
757: #endif
758: }
759: change(cursor, cursor + 1, key);
760: cursor++;
761: if (cursor > to)
762: {
763: to = cursor;
764: }
765: break;
766:
767: case ctrl('L'):
768: case ctrl('R'):
769: redraw(MARK_UNSET, FALSE);
770: break;
771:
772: default:
773: if (cursor >= to && when != WHEN_VIREP)
774: {
775: add(cursor, key);
776: cursor++;
777: to = cursor;
778: }
779: else
780: {
781: pfetch(markline(cursor));
782: if (markidx(cursor) == plen)
783: {
784: add(cursor, key);
785: }
786: else
787: {
788: #ifndef NO_DIGRAPH
789: *key = digraph(ptext[markidx(cursor)], *key);
790: #endif
791: change(cursor, cursor + 1, key);
792: }
793: cursor++;
794: }
795: #ifndef NO_SHOWMATCH
796: /* show matching "({[" if necessary */
797: if (*o_showmatch && strchr(")}]", *key))
798: {
799: redraw(cursor, TRUE);
800: m = m_match(cursor - 1, 0L);
801: if (markline(m) >= topline
802: && markline(m) <= botline)
803: {
804: redraw(m, TRUE);
805: refresh();
806: sleep(1);
807: }
808: }
809: #endif
810: } /* end switch(*key) */
811: } /* end for(;;) */
812: BreakBreak:;
813: /* delete any excess characters */
814: if (cursor < to)
815: {
816: #ifndef NO_EXTENSIONS
817: /* if we aren't in the middle of a change, start one! */
818: if (!inchg)
819: {
820: beforedo(FALSE);
821: inchg = TRUE;
822: }
823: #endif
824: delete(cursor, to);
825: }
826:
827: } /* end if doingdot else */
828:
829: /* put the new text into a cut buffer for possible reuse */
830: if (!doingdot)
831: {
832: blksync();
833: cutname('.');
834: cut(from, cursor);
835: }
836:
837: /* move to last char that we inputted, unless it was newline */
838: if (markidx(cursor) != 0)
839: {
840: cursor--;
841: }
842: redraw(cursor, FALSE);
843:
844: #ifndef NO_EXTENSIONS
845: if (quit)
846: {
847: /* if this is a nested "do", then cut it short */
848: abortdo();
849:
850: /* exit, unless we can't write out the file */
851: cursor = v_xit(cursor, 0L, 'Z');
852: }
853: #endif
854:
855: rptlines = 0L;
856: return cursor;
857: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.