|
|
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.