|
|
1.1 root 1: /* move1.c */
2:
3: /* Author:
4: * Steve Kirkendall
5: * 16820 SW Tallac Way
6: * Beaverton, OR 97006
7: * [email protected], or ...uunet!tektronix!psueea!jove!kirkenda
8: */
9:
10:
11: /* This file contains most movement functions */
12:
13: #include "config.h"
14: #include <ctype.h>
15: #include "vi.h"
16:
17: #ifndef isascii
18: # define isascii(c) !((c) & ~0x7f)
19: #endif
20:
21: MARK m_updnto(m, cnt, cmd)
22: MARK m; /* movement is relative to this mark */
23: long cnt; /* a numeric argument */
24: {
25: DEFAULT(cmd == 'G' ? nlines : 1L);
26:
27: /* move up or down 'cnt' lines */
28: switch (cmd)
29: {
30: case ('P'&0x1f):
31: case '-':
32: case 'k':
33: m -= MARK_AT_LINE(cnt);
34: break;
35:
36: case 'G':
37: if (cnt < 1L || cnt > nlines)
38: {
39: msg("Only %ld lines", nlines);
40: return MARK_UNSET;
41: }
42: m = MARK_AT_LINE(cnt);
43: break;
44:
45: default:
46: m += MARK_AT_LINE(cnt);
47: }
48:
49: /* if that left us screwed up, then fail */
50: if (m < MARK_FIRST || markline(m) > nlines)
51: {
52: return MARK_UNSET;
53: }
54:
55: return m;
56: }
57:
58: /*ARGSUSED*/
59: MARK m_right(m, cnt)
60: MARK m; /* movement is relative to this mark */
61: long cnt; /* a numeric argument */
62: {
63: int idx; /* index of the new cursor position */
64:
65: DEFAULT(1);
66:
67: /* move to right, if that's OK */
68: pfetch(markline(m));
69: idx = markidx(m) + cnt;
70: if (idx < plen)
71: {
72: m += cnt;
73: }
74: else
75: {
76: return MARK_UNSET;
77: }
78:
79: return m;
80: }
81:
82: /*ARGSUSED*/
83: MARK m_left(m, cnt)
84: MARK m; /* movement is relative to this mark */
85: long cnt; /* a numeric argument */
86: {
87: DEFAULT(1);
88:
89: /* move to the left, if that's OK */
90: if (markidx(m) >= cnt)
91: {
92: m -= cnt;
93: }
94: else
95: {
96: return MARK_UNSET;
97: }
98:
99: return m;
100: }
101:
102: /*ARGSUSED*/
103: MARK m_tocol(m, cnt)
104: MARK m; /* movement is relative to this mark */
105: long cnt; /* a numeric argument */
106: {
107: char *text; /* text of the line */
108: int col; /* column number */
109: int idx; /* index into the line */
110:
111: DEFAULT(1);
112:
113: /* internally, columns are numbered 0..COLS-1, not 1..COLS */
114: cnt--;
115:
116: /* if 0, that's easy */
117: if (cnt == 0)
118: {
119: m &= ~(BLKSIZE - 1);
120: return m;
121: }
122:
123: /* find that column within the line */
124: pfetch(markline(m));
125: text = ptext;
126: for (col = idx = 0; col < cnt && *text; text++, idx++)
127: {
128: if (*text == '\t' && !*o_list)
129: {
130: col += *o_tabstop;
131: col -= col % *o_tabstop;
132: }
133: else if (UCHAR(*text) < ' ' || *text == '\177')
134: {
135: col += 2;
136: }
137: #ifndef NO_CHARATTR
138: else if (text[0] == '\\' && text[1] == 'f' && text[2] && *o_charattr)
139: {
140: text += 2; /* plus one more as part of for loop */
141: }
142: #endif
143: else
144: {
145: col++;
146: }
147: }
148: if (!*text)
149: {
150: return MARK_UNSET;
151: }
152: else
153: {
154: m = (m & ~(BLKSIZE - 1)) + idx;
155: }
156: return m;
157: }
158:
159: /*ARGSUSED*/
160: MARK m_front(m, cnt)
161: MARK m; /* movement is relative to this mark */
162: long cnt; /* a numeric argument (ignored) */
163: {
164: char *scan;
165:
166: /* move to the first non-whitespace character */
167: pfetch(markline(m));
168: scan = ptext;
169: m &= ~(BLKSIZE - 1);
170: while (*scan == ' ' || *scan == '\t')
171: {
172: scan++;
173: m++;
174: }
175:
176: return m;
177: }
178:
179: /*ARGSUSED*/
180: MARK m_rear(m, cnt)
181: MARK m; /* movement is relative to this mark */
182: long cnt; /* a numeric argument (ignored) */
183: {
184: /* Try to move *EXTREMELY* far to the right. It is fervently hoped
185: * that other code will convert this to a more reasonable MARK before
186: * anything tries to actually use it. (See adjmove() in vi.c)
187: */
188: return m | (BLKSIZE - 1);
189: }
190:
191: #ifndef NO_SENTENCE
192: /*ARGSUSED*/
193: MARK m_fsentence(m, cnt)
194: MARK m; /* movement is relative to this mark */
195: long cnt; /* a numeric argument */
196: {
197: REG char *text;
198: REG long l;
199:
200: DEFAULT(1);
201:
202: /* get the current line */
203: l = markline(m);
204: pfetch(l);
205: text = ptext + markidx(m);
206:
207: /* for each requested sentence... */
208: while (cnt-- > 0)
209: {
210: /* search forward for one of [.?!] followed by spaces or EOL */
211: do
212: {
213: /* wrap at end of line */
214: if (!text[0])
215: {
216: if (l >= nlines)
217: {
218: return MARK_UNSET;
219: }
220: l++;
221: pfetch(l);
222: text = ptext;
223: }
224: else
225: {
226: text++;
227: }
228: } while (text[0] != '.' && text[0] != '?' && text[0] != '!'
229: || text[1] && (text[1] != ' ' || text[2] && text[2] != ' '));
230: }
231:
232: /* construct a mark for this location */
233: m = buildmark(text);
234:
235: /* move forward to the first word of the next sentence */
236: m = m_fword(m, 1L);
237:
238: return m;
239: }
240:
241: /*ARGSUSED*/
242: MARK m_bsentence(m, cnt)
243: MARK m; /* movement is relative to this mark */
244: long cnt; /* a numeric argument */
245: {
246: REG char *text; /* used to scan thru text */
247: REG long l; /* current line number */
248: int flag; /* have we passed at least one word? */
249:
250: DEFAULT(1);
251:
252: /* get the current line */
253: l = markline(m);
254: pfetch(l);
255: text = ptext + markidx(m);
256:
257: /* for each requested sentence... */
258: flag = TRUE;
259: while (cnt-- > 0)
260: {
261: /* search backward for one of [.?!] followed by spaces or EOL */
262: do
263: {
264: /* wrap at beginning of line */
265: if (text == ptext)
266: {
267: do
268: {
269: if (l <= 1)
270: {
271: return MARK_UNSET;
272: }
273: l--;
274: pfetch(l);
275: } while (!*ptext);
276: text = ptext + plen - 1;
277: }
278: else
279: {
280: text--;
281: }
282:
283: /* are we moving past a "word"? */
284: if (text[0] >= '0')
285: {
286: flag = FALSE;
287: }
288: } while (flag || text[0] != '.' && text[0] != '?' && text[0] != '!'
289: || text[1] && (text[1] != ' ' || text[2] && text[2] != ' '));
290: }
291:
292: /* construct a mark for this location */
293: m = buildmark(text);
294:
295: /* move to the front of the following sentence */
296: m = m_fword(m, 1L);
297:
298: return m;
299: }
300: #endif
301:
302: /*ARGSUSED*/
303: MARK m_fparagraph(m, cnt)
304: MARK m; /* movement is relative to this mark */
305: long cnt; /* a numeric argument */
306: {
307: char *text;
308: char *pscn; /* used to scan thru value of "paragraphs" option */
309: long l;
310:
311: DEFAULT(1);
312:
313: for (l = markline(m); cnt > 0 && l++ < nlines; )
314: {
315: text = fetchline(l);
316: if (!*text)
317: {
318: cnt--;
319: }
320: #ifndef NO_SENTENCE
321: else if (*text == '.')
322: {
323: for (pscn = o_paragraphs; pscn[0] && pscn[1]; pscn += 2)
324: {
325: if (pscn[0] == text[1] && pscn[1] == text[2])
326: {
327: cnt--;
328: break;
329: }
330: }
331: }
332: #endif
333: }
334: if (l <= nlines)
335: {
336: m = MARK_AT_LINE(l);
337: }
338: else
339: {
340: m = MARK_LAST;
341: }
342: return m;
343: }
344:
345: /*ARGSUSED*/
346: MARK m_bparagraph(m, cnt)
347: MARK m; /* movement is relative to this mark */
348: long cnt; /* a numeric argument */
349: {
350: char *text;
351: char *pscn; /* used to scan thru value of "paragraph" option */
352: long l;
353:
354: DEFAULT(1);
355:
356: for (l = markline(m); cnt > 0 && l-- > 1; )
357: {
358: text = fetchline(l);
359: if (!*text)
360: {
361: cnt--;
362: }
363: #ifndef NO_SENTENCE
364: else if (*text == '.')
365: {
366: for (pscn = o_paragraphs; pscn[0] && pscn[1]; pscn += 2)
367: {
368: if (pscn[0] == text[1] && pscn[1] == text[2])
369: {
370: cnt--;
371: break;
372: }
373: }
374: }
375: #endif
376: }
377: if (l >= 1)
378: {
379: m = MARK_AT_LINE(l);
380: }
381: else
382: {
383: m = MARK_FIRST;
384: }
385: return m;
386: }
387:
388: /*ARGSUSED*/
389: MARK m_fsection(m, cnt, key)
390: MARK m; /* movement is relative to this mark */
391: long cnt; /* (ignored) */
392: int key; /* second key stroke - must be ']' */
393: {
394: char *text;
395: char *sscn; /* used to scan thru value of "sections" option */
396: long l;
397:
398: /* make sure second key was ']' */
399: if (key != ']')
400: {
401: return MARK_UNSET;
402: }
403:
404: for (l = markline(m); l++ < nlines; )
405: {
406: text = fetchline(l);
407: if (*text == '{')
408: {
409: break;
410: }
411: #ifndef NO_SENTENCE
412: else if (*text == '.')
413: {
414: for (sscn = o_sections; sscn[0] && sscn[1]; sscn += 2)
415: {
416: if (sscn[0] == text[1] && sscn[1] == text[2])
417: {
418: goto BreakBreak;
419: }
420: }
421: }
422: #endif
423: }
424: BreakBreak:
425: if (l <= nlines)
426: {
427: m = MARK_AT_LINE(l);
428: }
429: else
430: {
431: m = MARK_LAST;
432: }
433: return m;
434: }
435:
436: /*ARGSUSED*/
437: MARK m_bsection(m, cnt, key)
438: MARK m; /* movement is relative to this mark */
439: long cnt; /* (ignored) */
440: int key; /* second key stroke - must be '[' */
441: {
442: char *text;
443: char *sscn; /* used to scan thru value of "sections" option */
444: long l;
445:
446: /* make sure second key was '[' */
447: if (key != '[')
448: {
449: return MARK_UNSET;
450: }
451:
452: for (l = markline(m); l-- > 1; )
453: {
454: text = fetchline(l);
455: if (*text == '{')
456: {
457: break;
458: }
459: #ifndef NO_SENTENCE
460: else if (*text == '.')
461: {
462: for (sscn = o_sections; sscn[0] && sscn[1]; sscn += 2)
463: {
464: if (sscn[0] == text[1] && sscn[1] == text[2])
465: {
466: goto BreakBreak;
467: }
468: }
469: }
470: #endif
471: }
472: BreakBreak:
473: if (l >= 1)
474: {
475: m = MARK_AT_LINE(l);
476: }
477: else
478: {
479: m = MARK_FIRST;
480: }
481: return m;
482: }
483:
484:
485: /*ARGSUSED*/
486: MARK m_match(m, cnt)
487: MARK m; /* movement is relative to this mark */
488: long cnt; /* a numeric argument (ignored) */
489: {
490: long l;
491: REG char *text;
492: REG char match;
493: REG char nest;
494: REG int count;
495:
496: /* get the current line */
497: l = markline(m);
498: pfetch(l);
499: text = ptext + markidx(m);
500:
501: /* search forward within line for one of "[](){}" */
502: for (match = '\0'; !match && *text; text++)
503: {
504: /* tricky way to recognize 'em in ASCII */
505: nest = *text;
506: if ((nest & 0xdf) == ']' || (nest & 0xdf) == '[')
507: {
508: match = nest ^ ('[' ^ ']');
509: }
510: else if ((nest & 0xfe) == '(')
511: {
512: match = nest ^ ('(' ^ ')');
513: }
514: else
515: {
516: match = 0;
517: }
518: }
519: if (!match)
520: {
521: return MARK_UNSET;
522: }
523: text--;
524:
525: /* search forward or backward for match */
526: if (match == '(' || match == '[' || match == '{')
527: {
528: /* search backward */
529: for (count = 1; count > 0; )
530: {
531: /* wrap at beginning of line */
532: if (text == ptext)
533: {
534: do
535: {
536: if (l <= 1L)
537: {
538: return MARK_UNSET;
539: }
540: l--;
541: pfetch(l);
542: } while (!*ptext);
543: text = ptext + plen - 1;
544: }
545: else
546: {
547: text--;
548: }
549:
550: /* check the char */
551: if (*text == match)
552: count--;
553: else if (*text == nest)
554: count++;
555: }
556: }
557: else
558: {
559: /* search forward */
560: for (count = 1; count > 0; )
561: {
562: /* wrap at end of line */
563: if (!*text)
564: {
565: if (l >= nlines)
566: {
567: return MARK_UNSET;
568: }
569: l++;
570: pfetch(l);
571: text = ptext;
572: }
573: else
574: {
575: text++;
576: }
577:
578: /* check the char */
579: if (*text == match)
580: count--;
581: else if (*text == nest)
582: count++;
583: }
584: }
585:
586: /* construct a mark for this place */
587: m = buildmark(text);
588: return m;
589: }
590:
591: /*ARGSUSED*/
592: MARK m_tomark(m, cnt, key)
593: MARK m; /* movement is relative to this mark */
594: long cnt; /* (ignored) */
595: int key; /* keystroke - the mark to move to */
596: {
597: /* mark '' is a special case */
598: if (key == '\'' || key == '`')
599: {
600: if (mark[26] == MARK_UNSET)
601: {
602: return MARK_FIRST;
603: }
604: else
605: {
606: return mark[26];
607: }
608: }
609:
610: /* if not a valid mark number, don't move */
611: if (key < 'a' || key > 'z')
612: {
613: return MARK_UNSET;
614: }
615:
616: /* return the selected mark -- may be MARK_UNSET */
617: if (!mark[key - 'a'])
618: {
619: msg("mark '%c is unset", key);
620: }
621: return mark[key - 'a'];
622: }
623:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.