Annotation of src/usr.bin/vim/misccmds.c, Revision 1.1
1.1 ! downsj 1: /* $OpenBSD$ */
! 2: /* vi:set ts=4 sw=4:
! 3: *
! 4: * VIM - Vi IMproved by Bram Moolenaar
! 5: *
! 6: * Do ":help uganda" in Vim to read copying and usage conditions.
! 7: * Do ":help credits" in Vim to see a list of people who contributed.
! 8: */
! 9:
! 10: /*
! 11: * misccmds.c: functions that didn't seem to fit elsewhere
! 12: */
! 13:
! 14: #include "vim.h"
! 15: #include "globals.h"
! 16: #include "proto.h"
! 17: #include "option.h"
! 18: #ifdef HAVE_FCNTL_H
! 19: # include <fcntl.h> /* for chdir() */
! 20: #endif
! 21:
! 22: static int get_indent_str __ARGS((char_u *ptr));
! 23: static void check_status __ARGS((BUF *));
! 24:
! 25: /*
! 26: * count the size of the indent in the current line
! 27: */
! 28: int
! 29: get_indent()
! 30: {
! 31: return get_indent_str(ml_get_curline());
! 32: }
! 33:
! 34: /*
! 35: * count the size of the indent in line "lnum"
! 36: */
! 37: int
! 38: get_indent_lnum(lnum)
! 39: linenr_t lnum;
! 40: {
! 41: return get_indent_str(ml_get(lnum));
! 42: }
! 43:
! 44: /*
! 45: * count the size of the indent in line "ptr"
! 46: */
! 47: static int
! 48: get_indent_str(ptr)
! 49: register char_u *ptr;
! 50: {
! 51: register int count = 0;
! 52:
! 53: for ( ; *ptr; ++ptr)
! 54: {
! 55: if (*ptr == TAB) /* count a tab for what it is worth */
! 56: count += (int)curbuf->b_p_ts - (count % (int)curbuf->b_p_ts);
! 57: else if (*ptr == ' ')
! 58: ++count; /* count a space for one */
! 59: else
! 60: break;
! 61: }
! 62: return (count);
! 63: }
! 64:
! 65: /*
! 66: * set the indent of the current line
! 67: * leaves the cursor on the first non-blank in the line
! 68: */
! 69: void
! 70: set_indent(size, del_first)
! 71: register int size;
! 72: int del_first;
! 73: {
! 74: int oldstate = State;
! 75: register int c;
! 76:
! 77: State = INSERT; /* don't want REPLACE for State */
! 78: curwin->w_cursor.col = 0;
! 79: if (del_first) /* delete old indent */
! 80: {
! 81: /* vim_iswhite() is a define! */
! 82: while ((c = gchar_cursor()), vim_iswhite(c))
! 83: (void)delchar(FALSE);
! 84: }
! 85: if (!curbuf->b_p_et) /* if 'expandtab' is set, don't use TABs */
! 86: while (size >= (int)curbuf->b_p_ts)
! 87: {
! 88: ins_char(TAB);
! 89: size -= (int)curbuf->b_p_ts;
! 90: }
! 91: while (size)
! 92: {
! 93: ins_char(' ');
! 94: --size;
! 95: }
! 96: State = oldstate;
! 97: }
! 98:
! 99: #if defined(CINDENT) || defined(SMARTINDENT)
! 100:
! 101: static int is_cinword __ARGS((char_u *line));
! 102:
! 103: /*
! 104: * Return TRUE if the string "line" starts with a word from 'cinwords'.
! 105: */
! 106: static int
! 107: is_cinword(line)
! 108: char_u *line;
! 109: {
! 110: char_u *cinw;
! 111: char_u *cinw_buf;
! 112: int cinw_len;
! 113: int retval = FALSE;
! 114: int len;
! 115:
! 116: cinw_len = STRLEN(curbuf->b_p_cinw) + 1;
! 117: cinw_buf = alloc((unsigned)cinw_len);
! 118: if (cinw_buf != NULL)
! 119: {
! 120: line = skipwhite(line);
! 121: for (cinw = curbuf->b_p_cinw; *cinw; )
! 122: {
! 123: len = copy_option_part(&cinw, cinw_buf, cinw_len, ",");
! 124: if (STRNCMP(line, cinw_buf, len) == 0 &&
! 125: (!iswordchar(line[len]) || !iswordchar(line[len - 1])))
! 126: {
! 127: retval = TRUE;
! 128: break;
! 129: }
! 130: }
! 131: vim_free(cinw_buf);
! 132: }
! 133: return retval;
! 134: }
! 135: #endif
! 136:
! 137: /*
! 138: * Opencmd
! 139: *
! 140: * Add a new line below or above the current line.
! 141: * Caller must take care of undo.
! 142: *
! 143: * Return TRUE for success, FALSE for failure
! 144: */
! 145:
! 146: int
! 147: Opencmd(dir, redraw, del_spaces)
! 148: int dir; /* FORWARD or BACKWARD */
! 149: int redraw; /* redraw afterwards */
! 150: int del_spaces; /* delete spaces after cursor */
! 151: {
! 152: char_u *saved_line; /* copy of the original line */
! 153: char_u *p_extra = NULL; /* what goes to next line */
! 154: int extra_len = 0; /* length of p_extra string */
! 155: FPOS old_cursor; /* old cursor position */
! 156: int newcol = 0; /* new cursor column */
! 157: int newindent = 0; /* auto-indent of the new line */
! 158: int n;
! 159: int trunc_line = FALSE; /* truncate current line afterwards */
! 160: int retval = FALSE; /* return value, default is FAIL */
! 161: int lead_len; /* length of comment leader */
! 162: char_u *lead_flags; /* position in 'comments' for comment leader */
! 163: char_u *leader = NULL; /* copy of comment leader */
! 164: char_u *allocated = NULL; /* allocated memory */
! 165: char_u *p;
! 166: int saved_char = NUL; /* init for GCC */
! 167: FPOS *pos;
! 168: int old_plines = 0; /* init for GCC */
! 169: int new_plines = 0; /* init for GCC */
! 170: #ifdef SMARTINDENT
! 171: int no_si = FALSE; /* reset did_si afterwards */
! 172: int first_char = NUL; /* init for GCC */
! 173: #endif
! 174:
! 175: /*
! 176: * make a copy of the current line so we can mess with it
! 177: */
! 178: saved_line = strsave(ml_get_curline());
! 179: if (saved_line == NULL) /* out of memory! */
! 180: return FALSE;
! 181:
! 182: if (State == INSERT || State == REPLACE)
! 183: {
! 184: p_extra = saved_line + curwin->w_cursor.col;
! 185: #ifdef SMARTINDENT
! 186: if (curbuf->b_p_si) /* need first char after new line break */
! 187: {
! 188: p = skipwhite(p_extra);
! 189: first_char = *p;
! 190: }
! 191: #endif
! 192: extra_len = STRLEN(p_extra);
! 193: saved_char = *p_extra;
! 194: *p_extra = NUL;
! 195: }
! 196:
! 197: u_clearline(); /* cannot do "U" command when adding lines */
! 198: #ifdef SMARTINDENT
! 199: did_si = FALSE;
! 200: #endif
! 201:
! 202: /*
! 203: * If 'autoindent' and/or 'smartindent' is set, try to figure out what
! 204: * indent to use for the new line.
! 205: */
! 206: if (curbuf->b_p_ai
! 207: #ifdef SMARTINDENT
! 208: || curbuf->b_p_si
! 209: #endif
! 210: )
! 211: {
! 212: /*
! 213: * count white space on current line
! 214: */
! 215: newindent = get_indent();
! 216: if (newindent == 0)
! 217: newindent = old_indent; /* for ^^D command in insert mode */
! 218: old_indent = 0;
! 219:
! 220: /*
! 221: * If we just did an auto-indent, then we didn't type anything on
! 222: * the prior line, and it should be truncated.
! 223: */
! 224: if (dir == FORWARD && did_ai)
! 225: trunc_line = TRUE;
! 226:
! 227: #ifdef SMARTINDENT
! 228: /*
! 229: * Do smart indenting.
! 230: * In insert/replace mode (only when dir == FORWARD)
! 231: * we may move some text to the next line. If it starts with '{'
! 232: * don't add an indent. Fixes inserting a NL before '{' in line
! 233: * "if (condition) {"
! 234: */
! 235: else if (curbuf->b_p_si && *saved_line != NUL &&
! 236: (p_extra == NULL || first_char != '{'))
! 237: {
! 238: char_u *ptr;
! 239: char_u last_char;
! 240:
! 241: old_cursor = curwin->w_cursor;
! 242: ptr = saved_line;
! 243: lead_len = get_leader_len(ptr, NULL);
! 244: if (dir == FORWARD)
! 245: {
! 246: /*
! 247: * Skip preprocessor directives, unless they are
! 248: * recognised as comments.
! 249: */
! 250: if (lead_len == 0 && ptr[0] == '#')
! 251: {
! 252: while (ptr[0] == '#' && curwin->w_cursor.lnum > 1)
! 253: ptr = ml_get(--curwin->w_cursor.lnum);
! 254: newindent = get_indent();
! 255: }
! 256: lead_len = get_leader_len(ptr, NULL);
! 257: if (lead_len > 0)
! 258: {
! 259: /*
! 260: * This case gets the following right:
! 261: * \*
! 262: * * A comment (read "\" as "/").
! 263: * *\
! 264: * #define IN_THE_WAY
! 265: * This should line up here;
! 266: */
! 267: p = skipwhite(ptr);
! 268: if (p[0] == '/' && p[1] == '*')
! 269: p++;
! 270: if (p[0] == '*')
! 271: {
! 272: for (p++; *p; p++)
! 273: {
! 274: if (p[0] == '/' && p[-1] == '*')
! 275: {
! 276: /*
! 277: * End of C comment, indent should line up
! 278: * with the line containing the start of
! 279: * the comment
! 280: */
! 281: curwin->w_cursor.col = p - ptr;
! 282: if ((pos = findmatch(NUL)) != NULL)
! 283: {
! 284: curwin->w_cursor.lnum = pos->lnum;
! 285: newindent = get_indent();
! 286: }
! 287: }
! 288: }
! 289: }
! 290: }
! 291: else /* Not a comment line */
! 292: {
! 293: /* Find last non-blank in line */
! 294: p = ptr + STRLEN(ptr) - 1;
! 295: while (p > ptr && vim_iswhite(*p))
! 296: --p;
! 297: last_char = *p;
! 298:
! 299: /*
! 300: * find the character just before the '{' or ';'
! 301: */
! 302: if (last_char == '{' || last_char == ';')
! 303: {
! 304: if (p > ptr)
! 305: --p;
! 306: while (p > ptr && vim_iswhite(*p))
! 307: --p;
! 308: }
! 309: /*
! 310: * Try to catch lines that are split over multiple
! 311: * lines. eg:
! 312: * if (condition &&
! 313: * condition) {
! 314: * Should line up here!
! 315: * }
! 316: */
! 317: if (*p == ')')
! 318: {
! 319: curwin->w_cursor.col = p - ptr;
! 320: if ((pos = findmatch('(')) != NULL)
! 321: {
! 322: curwin->w_cursor.lnum = pos->lnum;
! 323: newindent = get_indent();
! 324: ptr = ml_get_curline();
! 325: }
! 326: }
! 327: /*
! 328: * If last character is '{' do indent, without
! 329: * checking for "if" and the like.
! 330: */
! 331: if (last_char == '{')
! 332: {
! 333: did_si = TRUE; /* do indent */
! 334: no_si = TRUE; /* don't delete it when '{' typed */
! 335: }
! 336: /*
! 337: * Look for "if" and the like, use 'cinwords'.
! 338: * Don't do this if the previous line ended in ';' or
! 339: * '}'.
! 340: */
! 341: else if (last_char != ';' && last_char != '}' &&
! 342: is_cinword(ptr))
! 343: did_si = TRUE;
! 344: }
! 345: }
! 346: else /* dir == BACKWARD */
! 347: {
! 348: /*
! 349: * Skip preprocessor directives, unless they are
! 350: * recognised as comments.
! 351: */
! 352: if (lead_len == 0 && ptr[0] == '#')
! 353: {
! 354: int was_backslashed = FALSE;
! 355:
! 356: while ((ptr[0] == '#' || was_backslashed) &&
! 357: curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
! 358: {
! 359: if (*ptr && ptr[STRLEN(ptr) - 1] == '\\')
! 360: was_backslashed = TRUE;
! 361: else
! 362: was_backslashed = FALSE;
! 363: ptr = ml_get(++curwin->w_cursor.lnum);
! 364: }
! 365: if (was_backslashed)
! 366: newindent = 0; /* Got to end of file */
! 367: else
! 368: newindent = get_indent();
! 369: }
! 370: p = skipwhite(ptr);
! 371: if (*p == '}') /* if line starts with '}': do indent */
! 372: did_si = TRUE;
! 373: else /* can delete indent when '{' typed */
! 374: can_si_back = TRUE;
! 375: }
! 376: curwin->w_cursor = old_cursor;
! 377: }
! 378: if (curbuf->b_p_si)
! 379: can_si = TRUE;
! 380: #endif /* SMARTINDENT */
! 381:
! 382: did_ai = TRUE;
! 383: }
! 384:
! 385: /*
! 386: * Find out if the current line starts with a comment leader.
! 387: * This may then be inserted in front of the new line.
! 388: */
! 389: lead_len = get_leader_len(saved_line, &lead_flags);
! 390: if (lead_len > 0)
! 391: {
! 392: char_u *lead_repl = NULL; /* replaces comment leader */
! 393: int lead_repl_len = 0; /* length of *lead_repl */
! 394: char_u lead_middle[COM_MAX_LEN]; /* middle-comment string */
! 395: char_u lead_end[COM_MAX_LEN]; /* end-comment string */
! 396: char_u *comment_end = NULL; /* where lead_end has been found */
! 397: int extra_space = FALSE; /* append extra space */
! 398: int current_flag;
! 399:
! 400: /*
! 401: * If the comment leader has the start, middle or end flag, it may not
! 402: * be used or may be replaced with the middle leader.
! 403: */
! 404: for (p = lead_flags; *p && *p != ':'; ++p)
! 405: {
! 406: if (*p == COM_START || *p == COM_MIDDLE)
! 407: {
! 408: current_flag = *p;
! 409: if (*p == COM_START)
! 410: {
! 411: /*
! 412: * Doing "O" on a start of comment does not insert leader.
! 413: */
! 414: if (dir == BACKWARD)
! 415: {
! 416: lead_len = 0;
! 417: break;
! 418: }
! 419:
! 420: /* find start of middle part */
! 421: (void)copy_option_part(&p, lead_middle, COM_MAX_LEN, ",");
! 422: }
! 423:
! 424: /*
! 425: * Isolate the strings of the middle and end leader.
! 426: */
! 427: while (*p && p[-1] != ':') /* find end of middle flags */
! 428: ++p;
! 429: (void)copy_option_part(&p, lead_middle, COM_MAX_LEN, ",");
! 430: while (*p && p[-1] != ':') /* find end of end flags */
! 431: ++p;
! 432: (void)copy_option_part(&p, lead_end, COM_MAX_LEN, ",");
! 433:
! 434: /*
! 435: * If the end of the comment is in the same line, don't use
! 436: * the comment leader.
! 437: */
! 438: if (dir == FORWARD)
! 439: {
! 440: n = STRLEN(lead_end);
! 441: for (p = saved_line + lead_len; *p; ++p)
! 442: if (STRNCMP(p, lead_end, n) == 0)
! 443: {
! 444: comment_end = p;
! 445: lead_len = 0;
! 446: break;
! 447: }
! 448: }
! 449:
! 450: /*
! 451: * Doing "o" on a start of comment inserts the middle leader.
! 452: */
! 453: if (lead_len)
! 454: {
! 455: if (current_flag == COM_START)
! 456: {
! 457: lead_repl = lead_middle;
! 458: lead_repl_len = STRLEN(lead_middle);
! 459: }
! 460:
! 461: /*
! 462: * If we have hit RETURN immediately after the start
! 463: * comment leader, then put a space after the middle
! 464: * comment leader on the next line.
! 465: */
! 466: if (!vim_iswhite(saved_line[lead_len - 1]) &&
! 467: ((p_extra != NULL &&
! 468: (int)curwin->w_cursor.col == lead_len) ||
! 469: (p_extra == NULL && saved_line[lead_len] == NUL)))
! 470: extra_space = TRUE;
! 471: }
! 472: break;
! 473: }
! 474: if (*p == COM_END)
! 475: {
! 476: /*
! 477: * Doing "o" on the end of a comment does not insert leader.
! 478: * Remember where the end is, might want to use it to find the
! 479: * start (for C-comments).
! 480: */
! 481: if (dir == FORWARD)
! 482: {
! 483: comment_end = skipwhite(saved_line);
! 484: lead_len = 0;
! 485: break;
! 486: }
! 487:
! 488: /*
! 489: * Doing "O" on the end of a comment inserts the middle leader.
! 490: * Find the string for the middle leader, searching backwards.
! 491: */
! 492: while (p > curbuf->b_p_com && *p != ',')
! 493: --p;
! 494: for (lead_repl = p; lead_repl > curbuf->b_p_com &&
! 495: lead_repl[-1] != ':'; --lead_repl)
! 496: ;
! 497: lead_repl_len = p - lead_repl;
! 498: break;
! 499: }
! 500: if (*p == COM_FIRST)
! 501: {
! 502: /*
! 503: * Comment leader for first line only: Don't repeat leader
! 504: * when using "O", blank out leader when using "o".
! 505: */
! 506: if (dir == BACKWARD)
! 507: lead_len = 0;
! 508: else
! 509: {
! 510: lead_repl = (char_u *)"";
! 511: lead_repl_len = 0;
! 512: }
! 513: break;
! 514: }
! 515: }
! 516: if (lead_len)
! 517: {
! 518: /* allocate buffer (may concatenate p_exta later) */
! 519: leader = alloc(lead_len + lead_repl_len + extra_space +
! 520: extra_len + 1);
! 521: allocated = leader; /* remember to free it later */
! 522:
! 523: if (leader == NULL)
! 524: lead_len = 0;
! 525: else
! 526: {
! 527: STRNCPY(leader, saved_line, lead_len);
! 528: leader[lead_len] = NUL;
! 529:
! 530: /*
! 531: * Replace leader with lead_repl, right or left adjusted
! 532: */
! 533: if (lead_repl != NULL)
! 534: {
! 535: for (p = lead_flags; *p && *p != ':'; ++p)
! 536: if (*p == COM_RIGHT || *p == COM_LEFT)
! 537: break;
! 538: if (*p == COM_RIGHT) /* right adjusted leader */
! 539: {
! 540: /* find last non-white in the leader to line up with */
! 541: for (p = leader + lead_len - 1; p > leader &&
! 542: vim_iswhite(*p); --p)
! 543: ;
! 544:
! 545: ++p;
! 546: if (p < leader + lead_repl_len)
! 547: p = leader;
! 548: else
! 549: p -= lead_repl_len;
! 550: vim_memmove(p, lead_repl, (size_t)lead_repl_len);
! 551: if (p + lead_repl_len > leader + lead_len)
! 552: p[lead_repl_len] = NUL;
! 553:
! 554: /* blank-out any other chars from the old leader. */
! 555: while (--p >= leader)
! 556: if (!vim_iswhite(*p))
! 557: *p = ' ';
! 558: }
! 559: else /* left adjusted leader */
! 560: {
! 561: p = skipwhite(leader);
! 562: vim_memmove(p, lead_repl, (size_t)lead_repl_len);
! 563:
! 564: /* blank-out any other chars from the old leader. */
! 565: for (p += lead_repl_len; p < leader + lead_len; ++p)
! 566: if (!vim_iswhite(*p))
! 567: *p = ' ';
! 568: *p = NUL;
! 569: }
! 570:
! 571: /* Recompute the indent, it may have changed. */
! 572: if (curbuf->b_p_ai
! 573: #ifdef SMARTINDENT
! 574: || curbuf->b_p_si
! 575: #endif
! 576: )
! 577: newindent = get_indent_str(leader);
! 578: }
! 579:
! 580: lead_len = STRLEN(leader);
! 581: if (extra_space)
! 582: {
! 583: leader[lead_len++] = ' ';
! 584: leader[lead_len] = NUL;
! 585: }
! 586:
! 587: newcol = lead_len;
! 588:
! 589: /*
! 590: * if a new indent will be set below, remove the indent that
! 591: * is in the comment leader
! 592: */
! 593: if (newindent
! 594: #ifdef SMARTINDENT
! 595: || did_si
! 596: #endif
! 597: )
! 598: {
! 599: while (lead_len && vim_iswhite(*leader))
! 600: {
! 601: --lead_len;
! 602: --newcol;
! 603: ++leader;
! 604: }
! 605: }
! 606:
! 607: }
! 608: #ifdef SMARTINDENT
! 609: did_si = can_si = FALSE;
! 610: #endif
! 611: }
! 612: else if (comment_end != NULL)
! 613: {
! 614: /*
! 615: * We have finished a comment, so we don't use the leader.
! 616: * If this was a C-comment and 'ai' or 'si' is set do a normal
! 617: * indent to align with the line containing the start of the
! 618: * comment.
! 619: */
! 620: if (comment_end[0] == '*' && comment_end[1] == '/' &&
! 621: (curbuf->b_p_ai
! 622: #ifdef SMARTINDENT
! 623: || curbuf->b_p_si
! 624: #endif
! 625: ))
! 626: {
! 627: old_cursor = curwin->w_cursor;
! 628: curwin->w_cursor.col = comment_end - saved_line;
! 629: if ((pos = findmatch(NUL)) != NULL)
! 630: {
! 631: curwin->w_cursor.lnum = pos->lnum;
! 632: newindent = get_indent();
! 633: }
! 634: curwin->w_cursor = old_cursor;
! 635: }
! 636: }
! 637: }
! 638:
! 639: /* (State == INSERT || State == REPLACE), only when dir == FORWARD */
! 640: if (p_extra != NULL)
! 641: {
! 642: *p_extra = saved_char; /* restore char that NUL replaced */
! 643:
! 644: /*
! 645: * When 'ai' set or "del_spaces" TRUE, skip to the first non-blank.
! 646: *
! 647: * When in REPLACE mode, put the deleted blanks on the replace
! 648: * stack, followed by a NUL, so they can be put back when
! 649: * a BS is entered.
! 650: */
! 651: if (State == REPLACE)
! 652: replace_push(NUL); /* end of extra blanks */
! 653: if (curbuf->b_p_ai || del_spaces)
! 654: {
! 655: while (*p_extra == ' ' || *p_extra == '\t')
! 656: {
! 657: if (State == REPLACE)
! 658: replace_push(*p_extra);
! 659: ++p_extra;
! 660: }
! 661: }
! 662: if (*p_extra != NUL)
! 663: did_ai = FALSE; /* append some text, don't trucate now */
! 664: }
! 665:
! 666: if (p_extra == NULL)
! 667: p_extra = (char_u *)""; /* append empty line */
! 668:
! 669: /* concatenate leader and p_extra, if there is a leader */
! 670: if (lead_len)
! 671: {
! 672: STRCAT(leader, p_extra);
! 673: p_extra = leader;
! 674: }
! 675:
! 676: old_cursor = curwin->w_cursor;
! 677: if (dir == BACKWARD)
! 678: --curwin->w_cursor.lnum;
! 679: if (ml_append(curwin->w_cursor.lnum, p_extra, (colnr_t)0, FALSE) == FAIL)
! 680: goto theend;
! 681: mark_adjust(curwin->w_cursor.lnum + 1, MAXLNUM, 1L, 0L);
! 682: if (newindent
! 683: #ifdef SMARTINDENT
! 684: || did_si
! 685: #endif
! 686: )
! 687: {
! 688: ++curwin->w_cursor.lnum;
! 689: #ifdef SMARTINDENT
! 690: if (did_si)
! 691: {
! 692: if (p_sr)
! 693: newindent -= newindent % (int)curbuf->b_p_sw;
! 694: newindent += (int)curbuf->b_p_sw;
! 695: }
! 696: #endif
! 697: set_indent(newindent, FALSE);
! 698: /*
! 699: * In REPLACE mode the new indent must be put on
! 700: * the replace stack for when it is deleted with BS
! 701: */
! 702: if (State == REPLACE)
! 703: for (n = 0; n < (int)curwin->w_cursor.col; ++n)
! 704: replace_push(NUL);
! 705: newcol += curwin->w_cursor.col;
! 706: #ifdef SMARTINDENT
! 707: if (no_si)
! 708: did_si = FALSE;
! 709: #endif
! 710: }
! 711: /*
! 712: * In REPLACE mode the extra leader must be put on the replace stack for
! 713: * when it is deleted with BS.
! 714: */
! 715: if (State == REPLACE)
! 716: while (lead_len-- > 0)
! 717: replace_push(NUL);
! 718:
! 719: curwin->w_cursor = old_cursor;
! 720:
! 721: if (dir == FORWARD)
! 722: {
! 723: if (redraw) /* want to know the old number of screen lines */
! 724: {
! 725: old_plines = plines(curwin->w_cursor.lnum);
! 726: new_plines = old_plines;
! 727: }
! 728: if (trunc_line || State == INSERT || State == REPLACE)
! 729: {
! 730: if (trunc_line)
! 731: {
! 732: /* find start of trailing white space */
! 733: for (n = STRLEN(saved_line); n > 0 &&
! 734: vim_iswhite(saved_line[n - 1]); --n)
! 735: ;
! 736: saved_line[n] = NUL;
! 737: }
! 738: else /* truncate current line at cursor */
! 739: *(saved_line + curwin->w_cursor.col) = NUL;
! 740: ml_replace(curwin->w_cursor.lnum, saved_line, FALSE);
! 741: saved_line = NULL;
! 742: new_plines = plines(curwin->w_cursor.lnum);
! 743: }
! 744:
! 745: /*
! 746: * Get the cursor to the start of the line, so that 'curwin->w_row'
! 747: * gets set to the right physical line number for the stuff that
! 748: * follows...
! 749: */
! 750: curwin->w_cursor.col = 0;
! 751:
! 752: if (redraw)
! 753: {
! 754: /*
! 755: * Call cursupdate() to compute w_row.
! 756: * But we don't want it to update the srceen.
! 757: */
! 758: ++RedrawingDisabled;
! 759: cursupdate();
! 760: --RedrawingDisabled;
! 761:
! 762: /*
! 763: * If we're doing an open on the last logical line, then go ahead
! 764: * and scroll the screen up. Otherwise, just insert a blank line
! 765: * at the right place if the number of screen lines changed.
! 766: * We use calls to plines() in case the cursor is resting on a
! 767: * long line, we want to know the row below the line.
! 768: */
! 769: n = curwin->w_row + new_plines;
! 770: if (n == curwin->w_winpos + curwin->w_height)
! 771: scrollup(1L);
! 772: else
! 773: win_ins_lines(curwin, n,
! 774: plines(curwin->w_cursor.lnum + 1) + new_plines - old_plines,
! 775: TRUE, TRUE);
! 776: }
! 777:
! 778: /*
! 779: * Put the cursor on the new line. Careful: the cursupdate() and
! 780: * scrollup() above may have moved w_cursor, we must use old_cursor.
! 781: */
! 782: curwin->w_cursor.lnum = old_cursor.lnum + 1;
! 783: }
! 784: else if (redraw) /* insert physical line above current line */
! 785: win_ins_lines(curwin, curwin->w_row, 1, TRUE, TRUE);
! 786:
! 787: curwin->w_cursor.col = newcol;
! 788:
! 789: #ifdef LISPINDENT
! 790: /*
! 791: * May do lisp indenting.
! 792: */
! 793: if (leader == NULL && curbuf->b_p_lisp && curbuf->b_p_ai)
! 794: fixthisline(get_lisp_indent);
! 795: #endif
! 796: #ifdef CINDENT
! 797: /*
! 798: * May do indenting after opening a new line.
! 799: */
! 800: if (leader == NULL && curbuf->b_p_cin &&
! 801: in_cinkeys(dir == FORWARD ? KEY_OPEN_FORW :
! 802: KEY_OPEN_BACK, ' ', linewhite(curwin->w_cursor.lnum)))
! 803: fixthisline(get_c_indent);
! 804: #endif
! 805:
! 806: if (redraw)
! 807: {
! 808: updateScreen(VALID_TO_CURSCHAR);
! 809: cursupdate(); /* update curwin->w_row */
! 810: }
! 811: CHANGED;
! 812:
! 813: retval = TRUE; /* success! */
! 814: theend:
! 815: vim_free(saved_line);
! 816: vim_free(allocated);
! 817: return retval;
! 818: }
! 819:
! 820: /*
! 821: * get_leader_len() returns the length of the prefix of the given string
! 822: * which introduces a comment. If this string is not a comment then 0 is
! 823: * returned.
! 824: * When "flags" is non-zero, it is set to point to the flags of the recognized
! 825: * comment leader.
! 826: */
! 827: int
! 828: get_leader_len(line, flags)
! 829: char_u *line;
! 830: char_u **flags;
! 831: {
! 832: int i, j;
! 833: int got_com = FALSE;
! 834: int found_one;
! 835: char_u part_buf[COM_MAX_LEN]; /* buffer for one option part */
! 836: char_u *string; /* pointer to comment string */
! 837: char_u *list;
! 838:
! 839: if (!fo_do_comments) /* don't format comments at all */
! 840: return 0;
! 841:
! 842: i = 0;
! 843: while (vim_iswhite(line[i])) /* leading white space is ignored */
! 844: ++i;
! 845:
! 846: /*
! 847: * Repeat to match several nested comment strings.
! 848: */
! 849: while (line[i])
! 850: {
! 851: /*
! 852: * scan through the 'comments' option for a match
! 853: */
! 854: found_one = FALSE;
! 855: for (list = curbuf->b_p_com; *list; )
! 856: {
! 857: /*
! 858: * Get one option part into part_buf[]. Advance list to next one.
! 859: * put string at start of string.
! 860: */
! 861: if (!got_com && flags != NULL) /* remember where flags started */
! 862: *flags = list;
! 863: (void)copy_option_part(&list, part_buf, COM_MAX_LEN, ",");
! 864: string = vim_strchr(part_buf, ':');
! 865: if (string == NULL) /* missing ':', ignore this part */
! 866: continue;
! 867: *string++ = NUL; /* isolate flags from string */
! 868:
! 869: /*
! 870: * When already found a nested comment, only accept further
! 871: * nested comments.
! 872: */
! 873: if (got_com && vim_strchr(part_buf, COM_NEST) == NULL)
! 874: continue;
! 875:
! 876: /*
! 877: * Line contents and string must match.
! 878: */
! 879: for (j = 0; string[j] != NUL && string[j] == line[i + j]; ++j)
! 880: ;
! 881: if (string[j] != NUL)
! 882: continue;
! 883:
! 884: /*
! 885: * When 'b' flag used, there must be white space or an
! 886: * end-of-line after the string in the line.
! 887: */
! 888: if (vim_strchr(part_buf, COM_BLANK) != NULL &&
! 889: !vim_iswhite(line[i + j]) && line[i + j] != NUL)
! 890: continue;
! 891:
! 892: /*
! 893: * We have found a match, stop searching.
! 894: */
! 895: i += j;
! 896: got_com = TRUE;
! 897: found_one = TRUE;
! 898: break;
! 899: }
! 900:
! 901: /*
! 902: * No match found, stop scanning.
! 903: */
! 904: if (!found_one)
! 905: break;
! 906:
! 907: /*
! 908: * Include any trailing white space.
! 909: */
! 910: while (vim_iswhite(line[i]))
! 911: ++i;
! 912:
! 913: /*
! 914: * If this comment doesn't nest, stop here.
! 915: */
! 916: if (vim_strchr(part_buf, COM_NEST) == NULL)
! 917: break;
! 918: }
! 919: return (got_com ? i : 0);
! 920: }
! 921:
! 922: /*
! 923: * plines(p) - return the number of physical screen lines taken by line 'p'
! 924: */
! 925: int
! 926: plines(p)
! 927: linenr_t p;
! 928: {
! 929: return plines_win(curwin, p);
! 930: }
! 931:
! 932: int
! 933: plines_win(wp, p)
! 934: WIN *wp;
! 935: linenr_t p;
! 936: {
! 937: register long col;
! 938: register char_u *s;
! 939: register int lines;
! 940:
! 941: if (!wp->w_p_wrap)
! 942: return 1;
! 943:
! 944: s = ml_get_buf(wp->w_buffer, p, FALSE);
! 945: if (*s == NUL) /* empty line */
! 946: return 1;
! 947:
! 948: col = linetabsize(s);
! 949:
! 950: /*
! 951: * If list mode is on, then the '$' at the end of the line takes up one
! 952: * extra column.
! 953: */
! 954: if (wp->w_p_list)
! 955: col += 1;
! 956:
! 957: /*
! 958: * If 'number' mode is on, add another 8.
! 959: */
! 960: if (wp->w_p_nu)
! 961: col += 8;
! 962:
! 963: lines = (col + (Columns - 1)) / Columns;
! 964: if (lines <= wp->w_height)
! 965: return lines;
! 966: return (int)(wp->w_height); /* maximum length */
! 967: }
! 968:
! 969: /*
! 970: * Count the physical lines (rows) for the lines "first" to "last" inclusive.
! 971: */
! 972: int
! 973: plines_m(first, last)
! 974: linenr_t first, last;
! 975: {
! 976: return plines_m_win(curwin, first, last);
! 977: }
! 978:
! 979: int
! 980: plines_m_win(wp, first, last)
! 981: WIN *wp;
! 982: linenr_t first, last;
! 983: {
! 984: int count = 0;
! 985:
! 986: while (first <= last)
! 987: count += plines_win(wp, first++);
! 988: return (count);
! 989: }
! 990:
! 991: /*
! 992: * Insert or replace a single character at the cursor position.
! 993: * When in REPLACE mode, replace any existing character.
! 994: */
! 995: void
! 996: ins_char(c)
! 997: int c;
! 998: {
! 999: register char_u *p;
! 1000: char_u *newp;
! 1001: char_u *oldp;
! 1002: int oldlen;
! 1003: int extra;
! 1004: colnr_t col = curwin->w_cursor.col;
! 1005: linenr_t lnum = curwin->w_cursor.lnum;
! 1006:
! 1007: oldp = ml_get(lnum);
! 1008: oldlen = STRLEN(oldp) + 1;
! 1009:
! 1010: if (State != REPLACE || *(oldp + col) == NUL)
! 1011: extra = 1;
! 1012: else
! 1013: extra = 0;
! 1014:
! 1015: /*
! 1016: * a character has to be put on the replace stack if there is a
! 1017: * character that is replaced, so it can be put back when BS is used.
! 1018: * Otherwise a 0 is put on the stack, indicating that a new character
! 1019: * was inserted, which can be deleted when BS is used.
! 1020: */
! 1021: if (State == REPLACE)
! 1022: replace_push(!extra ? *(oldp + col) : 0);
! 1023: newp = alloc_check((unsigned)(oldlen + extra));
! 1024: if (newp == NULL)
! 1025: return;
! 1026: vim_memmove(newp, oldp, (size_t)col);
! 1027: p = newp + col;
! 1028: vim_memmove(p + extra, oldp + col, (size_t)(oldlen - col));
! 1029: *p = c;
! 1030: ml_replace(lnum, newp, FALSE);
! 1031:
! 1032: /*
! 1033: * If we're in insert or replace mode and 'showmatch' is set, then check for
! 1034: * right parens and braces. If there isn't a match, then beep. If there
! 1035: * is a match AND it's on the screen, then flash to it briefly. If it
! 1036: * isn't on the screen, don't do anything.
! 1037: */
! 1038: #ifdef RIGHTLEFT
! 1039: if (p_sm && (State & INSERT) &&
! 1040: ((!curwin->w_p_rl && (c == ')' || c == '}' || c == ']')) ||
! 1041: (curwin->w_p_rl && (c == '(' || c == '{' || c == '['))))
! 1042: #else
! 1043: if (p_sm && (State & INSERT) && (c == ')' || c == '}' || c == ']'))
! 1044: #endif
! 1045: showmatch();
! 1046:
! 1047: #ifdef RIGHTLEFT
! 1048: if (!p_ri || State == REPLACE) /* normal insert: cursor right */
! 1049: #endif
! 1050: ++curwin->w_cursor.col;
! 1051: CHANGED;
! 1052: }
! 1053:
! 1054: /*
! 1055: * Insert a string at the cursor position.
! 1056: * Note: Nothing special for replace mode.
! 1057: */
! 1058: void
! 1059: ins_str(s)
! 1060: char_u *s;
! 1061: {
! 1062: register char_u *oldp, *newp;
! 1063: register int newlen = STRLEN(s);
! 1064: int oldlen;
! 1065: colnr_t col = curwin->w_cursor.col;
! 1066: linenr_t lnum = curwin->w_cursor.lnum;
! 1067:
! 1068: oldp = ml_get(lnum);
! 1069: oldlen = STRLEN(oldp);
! 1070:
! 1071: newp = alloc_check((unsigned)(oldlen + newlen + 1));
! 1072: if (newp == NULL)
! 1073: return;
! 1074: vim_memmove(newp, oldp, (size_t)col);
! 1075: vim_memmove(newp + col, s, (size_t)newlen);
! 1076: vim_memmove(newp + col + newlen, oldp + col, (size_t)(oldlen - col + 1));
! 1077: ml_replace(lnum, newp, FALSE);
! 1078: curwin->w_cursor.col += newlen;
! 1079: CHANGED;
! 1080: }
! 1081:
! 1082: /*
! 1083: * delete one character under the cursor
! 1084: *
! 1085: * return FAIL for failure, OK otherwise
! 1086: */
! 1087: int
! 1088: delchar(fixpos)
! 1089: int fixpos; /* if TRUE fix the cursor position when done */
! 1090: {
! 1091: char_u *oldp, *newp;
! 1092: colnr_t oldlen;
! 1093: linenr_t lnum = curwin->w_cursor.lnum;
! 1094: colnr_t col = curwin->w_cursor.col;
! 1095: int was_alloced;
! 1096:
! 1097: oldp = ml_get(lnum);
! 1098: oldlen = STRLEN(oldp);
! 1099:
! 1100: if (col >= oldlen) /* can't do anything (happens with replace mode) */
! 1101: return FAIL;
! 1102:
! 1103: /*
! 1104: * If the old line has been allocated the deletion can be done in the
! 1105: * existing line. Otherwise a new line has to be allocated
! 1106: */
! 1107: was_alloced = ml_line_alloced(); /* check if oldp was allocated */
! 1108: if (was_alloced)
! 1109: newp = oldp; /* use same allocated memory */
! 1110: else
! 1111: {
! 1112: newp = alloc((unsigned)oldlen); /* need to allocated a new line */
! 1113: if (newp == NULL)
! 1114: return FAIL;
! 1115: vim_memmove(newp, oldp, (size_t)col);
! 1116: }
! 1117: vim_memmove(newp + col, oldp + col + 1, (size_t)(oldlen - col));
! 1118: if (!was_alloced)
! 1119: ml_replace(lnum, newp, FALSE);
! 1120:
! 1121: /*
! 1122: * If we just took off the last character of a non-blank line, we don't
! 1123: * want to end up positioned at the NUL.
! 1124: */
! 1125: if (fixpos && curwin->w_cursor.col > 0 && col == oldlen - 1)
! 1126: --curwin->w_cursor.col;
! 1127:
! 1128: CHANGED;
! 1129: return OK;
! 1130: }
! 1131:
! 1132: /*
! 1133: * Delete from cursor to end of line.
! 1134: *
! 1135: * return FAIL for failure, OK otherwise
! 1136: */
! 1137: int
! 1138: truncate_line(fixpos)
! 1139: int fixpos; /* if TRUE fix the cursor position when done */
! 1140: {
! 1141: char_u *newp;
! 1142: linenr_t lnum = curwin->w_cursor.lnum;
! 1143: colnr_t col = curwin->w_cursor.col;
! 1144:
! 1145: if (col == 0)
! 1146: newp = strsave((char_u *)"");
! 1147: else
! 1148: newp = strnsave(ml_get(lnum), col);
! 1149:
! 1150: if (newp == NULL)
! 1151: return FAIL;
! 1152:
! 1153: ml_replace(lnum, newp, FALSE);
! 1154:
! 1155: /*
! 1156: * If "fixpos" is TRUE we don't want to end up positioned at the NUL.
! 1157: */
! 1158: if (fixpos && curwin->w_cursor.col > 0)
! 1159: --curwin->w_cursor.col;
! 1160:
! 1161: CHANGED;
! 1162: return OK;
! 1163: }
! 1164:
! 1165: void
! 1166: dellines(nlines, dowindow, undo)
! 1167: long nlines; /* number of lines to delete */
! 1168: int dowindow; /* if true, update the window */
! 1169: int undo; /* if true, prepare for undo */
! 1170: {
! 1171: int num_plines = 0;
! 1172:
! 1173: if (nlines <= 0)
! 1174: return;
! 1175: /*
! 1176: * There's no point in keeping the window updated if redrawing is disabled
! 1177: * or we're deleting more than a window's worth of lines.
! 1178: */
! 1179: if (RedrawingDisabled)
! 1180: dowindow = FALSE;
! 1181: else if (nlines > (curwin->w_height - curwin->w_row) && dowindow)
! 1182: {
! 1183: dowindow = FALSE;
! 1184: /* flaky way to clear rest of window */
! 1185: win_del_lines(curwin, curwin->w_row, curwin->w_height, TRUE, TRUE);
! 1186: }
! 1187: /* save the deleted lines for undo */
! 1188: if (undo && u_savedel(curwin->w_cursor.lnum, nlines) == FAIL)
! 1189: return;
! 1190:
! 1191: /* adjust marks for deleted lines and lines that follow */
! 1192: mark_adjust(curwin->w_cursor.lnum, curwin->w_cursor.lnum + nlines - 1,
! 1193: MAXLNUM, -nlines);
! 1194:
! 1195: while (nlines-- > 0)
! 1196: {
! 1197: if (curbuf->b_ml.ml_flags & ML_EMPTY) /* nothing to delete */
! 1198: break;
! 1199:
! 1200: /*
! 1201: * Set up to delete the correct number of physical lines on the
! 1202: * window
! 1203: */
! 1204: if (dowindow)
! 1205: num_plines += plines(curwin->w_cursor.lnum);
! 1206:
! 1207: ml_delete(curwin->w_cursor.lnum, TRUE);
! 1208:
! 1209: CHANGED;
! 1210:
! 1211: /* If we delete the last line in the file, stop */
! 1212: if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
! 1213: {
! 1214: curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
! 1215: break;
! 1216: }
! 1217: }
! 1218: curwin->w_cursor.col = 0;
! 1219: /*
! 1220: * Delete the correct number of physical lines on the window
! 1221: */
! 1222: if (dowindow && num_plines > 0)
! 1223: win_del_lines(curwin, curwin->w_row, num_plines, TRUE, TRUE);
! 1224: }
! 1225:
! 1226: int
! 1227: gchar(pos)
! 1228: FPOS *pos;
! 1229: {
! 1230: return (int)(*(ml_get_pos(pos)));
! 1231: }
! 1232:
! 1233: int
! 1234: gchar_cursor()
! 1235: {
! 1236: return (int)(*(ml_get_cursor()));
! 1237: }
! 1238:
! 1239: /*
! 1240: * Write a character at the current cursor position.
! 1241: * It is directly written into the block.
! 1242: */
! 1243: void
! 1244: pchar_cursor(c)
! 1245: int c;
! 1246: {
! 1247: *(ml_get_buf(curbuf, curwin->w_cursor.lnum, TRUE) +
! 1248: curwin->w_cursor.col) = c;
! 1249: }
! 1250:
! 1251: /*
! 1252: * Put *pos at end of current buffer
! 1253: */
! 1254: void
! 1255: goto_endofbuf(pos)
! 1256: FPOS *pos;
! 1257: {
! 1258: char_u *p;
! 1259:
! 1260: pos->lnum = curbuf->b_ml.ml_line_count;
! 1261: pos->col = 0;
! 1262: p = ml_get(pos->lnum);
! 1263: while (*p++)
! 1264: ++pos->col;
! 1265: }
! 1266:
! 1267: /*
! 1268: * When extra == 0: Return TRUE if the cursor is before or on the first
! 1269: * non-blank in the line.
! 1270: * When extra == 1: Return TRUE if the cursor is before the first non-blank in
! 1271: * the line.
! 1272: */
! 1273: int
! 1274: inindent(extra)
! 1275: int extra;
! 1276: {
! 1277: register char_u *ptr;
! 1278: register colnr_t col;
! 1279:
! 1280: for (col = 0, ptr = ml_get_curline(); vim_iswhite(*ptr); ++col)
! 1281: ++ptr;
! 1282: if (col >= curwin->w_cursor.col + extra)
! 1283: return TRUE;
! 1284: else
! 1285: return FALSE;
! 1286: }
! 1287:
! 1288: /*
! 1289: * skipwhite: skip over ' ' and '\t'.
! 1290: */
! 1291: char_u *
! 1292: skipwhite(p)
! 1293: register char_u *p;
! 1294: {
! 1295: while (vim_iswhite(*p)) /* skip to next non-white */
! 1296: ++p;
! 1297: return p;
! 1298: }
! 1299:
! 1300: /*
! 1301: * skipdigits: skip over digits;
! 1302: */
! 1303: char_u *
! 1304: skipdigits(p)
! 1305: register char_u *p;
! 1306: {
! 1307: while (isdigit(*p)) /* skip to next non-digit */
! 1308: ++p;
! 1309: return p;
! 1310: }
! 1311:
! 1312: /*
! 1313: * skiptowhite: skip over text until ' ' or '\t' or NUL.
! 1314: */
! 1315: char_u *
! 1316: skiptowhite(p)
! 1317: register char_u *p;
! 1318: {
! 1319: while (*p != ' ' && *p != '\t' && *p != NUL)
! 1320: ++p;
! 1321: return p;
! 1322: }
! 1323:
! 1324: /*
! 1325: * skiptowhite_esc: Like skiptowhite(), but also skip escaped chars
! 1326: */
! 1327: char_u *
! 1328: skiptowhite_esc(p)
! 1329: register char_u *p;
! 1330: {
! 1331: while (*p != ' ' && *p != '\t' && *p != NUL)
! 1332: {
! 1333: if ((*p == '\\' || *p == Ctrl('V')) && *(p + 1) != NUL)
! 1334: ++p;
! 1335: ++p;
! 1336: }
! 1337: return p;
! 1338: }
! 1339:
! 1340: /*
! 1341: * getdigits: get a number from a string and skip over it
! 1342: *
! 1343: * note: you must give a pointer to a char_u pointer!
! 1344: */
! 1345:
! 1346: long
! 1347: getdigits(pp)
! 1348: char_u **pp;
! 1349: {
! 1350: register char_u *p;
! 1351: long retval;
! 1352:
! 1353: p = *pp;
! 1354: retval = atol((char *)p);
! 1355: p = skipdigits(p); /* skip to next non-digit */
! 1356: *pp = p;
! 1357: return retval;
! 1358: }
! 1359:
! 1360: /*
! 1361: * Skip to next part of an option argument: Skip space and comma.
! 1362: */
! 1363: char_u *
! 1364: skip_to_option_part(p)
! 1365: char_u *p;
! 1366: {
! 1367: if (*p == ',')
! 1368: ++p;
! 1369: while (*p == ' ')
! 1370: ++p;
! 1371: return p;
! 1372: }
! 1373:
! 1374: char *
! 1375: plural(n)
! 1376: long n;
! 1377: {
! 1378: static char buf[2] = "s";
! 1379:
! 1380: if (n == 1)
! 1381: return &(buf[1]);
! 1382: return &(buf[0]);
! 1383: }
! 1384:
! 1385: /*
! 1386: * set_Changed is called when something in the current buffer is changed
! 1387: */
! 1388: void
! 1389: set_Changed()
! 1390: {
! 1391: if (!curbuf->b_changed)
! 1392: {
! 1393: change_warning();
! 1394: curbuf->b_changed = TRUE;
! 1395: check_status(curbuf);
! 1396: }
! 1397: modified = TRUE; /* used for redrawing */
! 1398: }
! 1399:
! 1400: /*
! 1401: * unset_Changed is called when the changed flag must be reset for buffer 'buf'
! 1402: */
! 1403: void
! 1404: unset_Changed(buf)
! 1405: BUF *buf;
! 1406: {
! 1407: if (buf->b_changed)
! 1408: {
! 1409: buf->b_changed = 0;
! 1410: check_status(buf);
! 1411: }
! 1412: }
! 1413:
! 1414: /*
! 1415: * check_status: called when the status bars for the buffer 'buf'
! 1416: * need to be updated
! 1417: */
! 1418: static void
! 1419: check_status(buf)
! 1420: BUF *buf;
! 1421: {
! 1422: WIN *wp;
! 1423: int i;
! 1424:
! 1425: i = 0;
! 1426: for (wp = firstwin; wp != NULL; wp = wp->w_next)
! 1427: if (wp->w_buffer == buf && wp->w_status_height)
! 1428: {
! 1429: wp->w_redr_status = TRUE;
! 1430: ++i;
! 1431: }
! 1432: if (i)
! 1433: redraw_later(NOT_VALID);
! 1434: }
! 1435:
! 1436: /*
! 1437: * If the file is readonly, give a warning message with the first change.
! 1438: * Don't do this for autocommands.
! 1439: * Don't use emsg(), because it flushes the macro buffer.
! 1440: * If we have undone all changes b_changed will be FALSE, but b_did_warn
! 1441: * will be TRUE.
! 1442: */
! 1443: void
! 1444: change_warning()
! 1445: {
! 1446: if (curbuf->b_did_warn == FALSE && curbuf->b_changed == 0 &&
! 1447: #ifdef AUTOCMD
! 1448: !autocmd_busy &&
! 1449: #endif
! 1450: curbuf->b_p_ro)
! 1451: {
! 1452: curbuf->b_did_warn = TRUE;
! 1453: MSG("Warning: Changing a readonly file");
! 1454: mch_delay(1000L, TRUE); /* give him some time to think about it */
! 1455: }
! 1456: }
! 1457:
! 1458: /*
! 1459: * Ask for a reply from the user, a 'y' or a 'n'.
! 1460: * No other characters are accepted, the message is repeated until a valid
! 1461: * reply is entered or CTRL-C is hit.
! 1462: * If direct is TRUE, don't use vgetc but mch_inchar, don't get characters from
! 1463: * any buffers but directly from the user.
! 1464: *
! 1465: * return the 'y' or 'n'
! 1466: */
! 1467: int
! 1468: ask_yesno(str, direct)
! 1469: char_u *str;
! 1470: int direct;
! 1471: {
! 1472: int r = ' ';
! 1473: char_u buf[20];
! 1474: int len = 0;
! 1475: int idx = 0;
! 1476:
! 1477: if (exiting) /* put terminal in raw mode for this question */
! 1478: settmode(1);
! 1479: while (r != 'y' && r != 'n')
! 1480: {
! 1481: (void)set_highlight('r'); /* same highlighting as for wait_return */
! 1482: msg_highlight = TRUE;
! 1483: smsg((char_u *)"%s (y/n)?", str);
! 1484: if (direct)
! 1485: {
! 1486: flushbuf();
! 1487: if (idx >= len)
! 1488: {
! 1489: len = mch_inchar(buf, 20, -1L);
! 1490: idx = 0;
! 1491: }
! 1492: r = buf[idx++];
! 1493: }
! 1494: else
! 1495: r = vgetc();
! 1496: if (r == Ctrl('C') || r == ESC)
! 1497: r = 'n';
! 1498: msg_outchar(r); /* show what you typed */
! 1499: flushbuf();
! 1500: }
! 1501: return r;
! 1502: }
! 1503:
! 1504: /*
! 1505: * get a number from the user
! 1506: */
! 1507: int
! 1508: get_number()
! 1509: {
! 1510: int n = 0;
! 1511: int c;
! 1512:
! 1513: for (;;)
! 1514: {
! 1515: windgoto(msg_row, msg_col);
! 1516: c = vgetc();
! 1517: if (isdigit(c))
! 1518: {
! 1519: n = n * 10 + c - '0';
! 1520: msg_outchar(c);
! 1521: }
! 1522: else if (c == K_DEL || c == K_BS || c == Ctrl('H'))
! 1523: {
! 1524: n /= 10;
! 1525: MSG_OUTSTR("\b \b");
! 1526: }
! 1527: else if (c == CR || c == NL || c == Ctrl('C'))
! 1528: break;
! 1529: }
! 1530: return n;
! 1531: }
! 1532:
! 1533: void
! 1534: msgmore(n)
! 1535: long n;
! 1536: {
! 1537: long pn;
! 1538:
! 1539: if (global_busy || /* no messages now, wait until global is finished */
! 1540: keep_msg) /* there is a message already, skip this one */
! 1541: return;
! 1542:
! 1543: if (n > 0)
! 1544: pn = n;
! 1545: else
! 1546: pn = -n;
! 1547:
! 1548: if (pn > p_report)
! 1549: {
! 1550: sprintf((char *)msg_buf, "%ld %s line%s %s",
! 1551: pn, n > 0 ? "more" : "fewer", plural(pn),
! 1552: got_int ? "(Interrupted)" : "");
! 1553: if (msg(msg_buf))
! 1554: keep_msg = msg_buf;
! 1555: }
! 1556: }
! 1557:
! 1558: /*
! 1559: * flush map and typeahead buffers and give a warning for an error
! 1560: */
! 1561: void
! 1562: beep_flush()
! 1563: {
! 1564: flush_buffers(FALSE);
! 1565: vim_beep();
! 1566: }
! 1567:
! 1568: /*
! 1569: * give a warning for an error
! 1570: */
! 1571: void
! 1572: vim_beep()
! 1573: {
! 1574: if (p_vb)
! 1575: {
! 1576: #ifdef DJGPP
! 1577: ScreenVisualBell();
! 1578: #else
! 1579: outstr(T_VB);
! 1580: #endif
! 1581: }
! 1582: else
! 1583: {
! 1584: #if defined MSDOS || defined WIN32 /* ? gvr */
! 1585: /*
! 1586: * The number of beeps outputted is reduced to avoid having to wait
! 1587: * for all the beeps to finish. This is only a problem on systems
! 1588: * where the beeps don't overlap.
! 1589: */
! 1590: if (beep_count == 0 || beep_count == 10)
! 1591: {
! 1592: outchar('\007');
! 1593: beep_count = 1;
! 1594: }
! 1595: else
! 1596: ++beep_count;
! 1597: #else
! 1598: outchar('\007');
! 1599: #endif
! 1600: }
! 1601: }
! 1602:
! 1603: /*
! 1604: * To get the "real" home directory:
! 1605: * - get value of $HOME
! 1606: * For Unix:
! 1607: * - go to that directory
! 1608: * - do mch_dirname() to get the real name of that directory.
! 1609: * This also works with mounts and links.
! 1610: * Don't do this for MS-DOS, it will change the "current dir" for a drive.
! 1611: */
! 1612: static char_u *homedir = NULL;
! 1613:
! 1614: void
! 1615: init_homedir()
! 1616: {
! 1617: char_u *var;
! 1618:
! 1619: var = vim_getenv((char_u *)"HOME");
! 1620: #if defined(OS2) || defined(MSDOS) || defined(WIN32)
! 1621: /*
! 1622: * Default home dir is C:/
! 1623: * Best assumption we can make in such a situation.
! 1624: */
! 1625: if (var == NULL)
! 1626: var = "C:/";
! 1627: #endif
! 1628: if (var != NULL)
! 1629: {
! 1630: #ifdef UNIX
! 1631: if (mch_dirname(NameBuff, MAXPATHL) == OK)
! 1632: {
! 1633: if (!vim_chdir((char *)var) && mch_dirname(IObuff, IOSIZE) == OK)
! 1634: var = IObuff;
! 1635: vim_chdir((char *)NameBuff);
! 1636: }
! 1637: #endif
! 1638: homedir = strsave(var);
! 1639: }
! 1640: }
! 1641:
! 1642: /*
! 1643: * Expand environment variable with path name.
! 1644: * For Unix and OS/2 "~/" is also expanded, like $HOME.
! 1645: * If anything fails no expansion is done and dst equals src.
! 1646: * Note that IObuff must NOT be used as either src or dst! This is because
! 1647: * vim_getenv() may use IObuff to do its expansion.
! 1648: */
! 1649: void
! 1650: expand_env(src, dst, dstlen)
! 1651: char_u *src; /* input string e.g. "$HOME/vim.hlp" */
! 1652: char_u *dst; /* where to put the result */
! 1653: int dstlen; /* maximum length of the result */
! 1654: {
! 1655: char_u *tail;
! 1656: int c;
! 1657: char_u *var;
! 1658: int copy_char;
! 1659: #if defined(UNIX) || defined(OS2)
! 1660: int mustfree;
! 1661: int at_start = TRUE;
! 1662: #endif
! 1663:
! 1664: src = skipwhite(src);
! 1665: --dstlen; /* leave one char space for "\," */
! 1666: while (*src && dstlen > 0)
! 1667: {
! 1668: copy_char = TRUE;
! 1669: if (*src == '$'
! 1670: #if defined(UNIX) || defined(OS2)
! 1671: || (*src == '~' && at_start)
! 1672: #endif
! 1673: )
! 1674: {
! 1675: #if defined(UNIX) || defined(OS2)
! 1676: mustfree = FALSE;
! 1677:
! 1678: /*
! 1679: * The variable name is copied into dst temporarily, because it may
! 1680: * be a string in read-only memory and a NUL needs to be inserted.
! 1681: */
! 1682: if (*src == '$') /* environment var */
! 1683: {
! 1684: #endif
! 1685: tail = src + 1;
! 1686: var = dst;
! 1687: c = dstlen - 1;
! 1688: while (c-- > 0 && *tail && isidchar(*tail))
! 1689: #ifdef OS2
! 1690: { /* env vars only in uppercase */
! 1691: *var++ = toupper(*tail); /* toupper() may be a macro! */
! 1692: tail++;
! 1693: }
! 1694: #else
! 1695: *var++ = *tail++;
! 1696: #endif
! 1697: *var = NUL;
! 1698: #if defined(OS2) || defined(MSDOS) || defined(WIN32)
! 1699: /* use "C:/" when $HOME is not set */
! 1700: if (STRCMP(dst, "HOME") == 0)
! 1701: var = homedir;
! 1702: else
! 1703: #endif
! 1704: var = vim_getenv(dst);
! 1705: #if defined(UNIX) || defined(OS2)
! 1706: }
! 1707: /* home directory */
! 1708: else if (src[1] == NUL ||
! 1709: vim_strchr((char_u *)"/ ,\t\n", src[1]) != NULL)
! 1710: {
! 1711: var = homedir;
! 1712: tail = src + 1;
! 1713: }
! 1714: else /* user directory */
! 1715: # ifdef OS2
! 1716: {
! 1717: /* cannot expand user's home directory, so don't try */
! 1718: var = NULL;
! 1719: tail = ""; /* shut gcc up about "may be used uninitialized" */
! 1720: }
! 1721: # else
! 1722: {
! 1723: /*
! 1724: * Copy ~user to dst[], so we can put a NUL after it.
! 1725: */
! 1726: tail = src;
! 1727: var = dst;
! 1728: c = dstlen - 1;
! 1729: while (c-- > 0 && *tail &&
! 1730: isfilechar(*tail) && !ispathsep(*tail))
! 1731: *var++ = *tail++;
! 1732: *var = NUL;
! 1733:
! 1734: /*
! 1735: * If the system supports getpwnam(), use it.
! 1736: * Otherwise, or if getpwnam() fails, the shell is used to
! 1737: * expand ~user. This is slower and may fail if the shell
! 1738: * does not support ~user (old versions of /bin/sh).
! 1739: */
! 1740: # if defined(HAVE_GETPWNAM) && defined(HAVE_PWD_H)
! 1741: {
! 1742: struct passwd *pw;
! 1743:
! 1744: pw = getpwnam((char *)dst + 1);
! 1745: if (pw != NULL)
! 1746: var = (char_u *)pw->pw_dir;
! 1747: else
! 1748: var = NULL;
! 1749: }
! 1750: if (var == NULL)
! 1751: # endif
! 1752: {
! 1753: var = ExpandOne(dst, NULL, 0, WILD_EXPAND_FREE);
! 1754: mustfree = TRUE;
! 1755: }
! 1756: }
! 1757: # endif /* OS2 */
! 1758: #endif /* UNIX || OS2 */
! 1759: if (var != NULL && *var != NUL &&
! 1760: (STRLEN(var) + STRLEN(tail) + 1 < (unsigned)dstlen))
! 1761: {
! 1762: STRCPY(dst, var);
! 1763: dstlen -= STRLEN(var);
! 1764: dst += STRLEN(var);
! 1765: /* if var[] ends in a path separator and tail[] starts
! 1766: * with it, skip a character */
! 1767: if (*var && ispathsep(*(dst-1)) && ispathsep(*tail))
! 1768: ++tail;
! 1769: src = tail;
! 1770: copy_char = FALSE;
! 1771: }
! 1772: #if defined(UNIX) || defined(OS2)
! 1773: if (mustfree)
! 1774: vim_free(var);
! 1775: #endif
! 1776: }
! 1777:
! 1778: if (copy_char) /* copy at least one char */
! 1779: {
! 1780: #if defined(UNIX) || defined(OS2)
! 1781: /*
! 1782: * Recogize the start of a new name, for '~'.
! 1783: */
! 1784: at_start = FALSE;
! 1785: #endif
! 1786: if (src[0] == '\\')
! 1787: {
! 1788: *dst++ = *src++;
! 1789: --dstlen;
! 1790: }
! 1791: #if defined(UNIX) || defined(OS2)
! 1792: else if (src[0] == ' ' || src[0] == ',')
! 1793: at_start = TRUE;
! 1794: #endif
! 1795: *dst++ = *src++;
! 1796: --dstlen;
! 1797: }
! 1798: }
! 1799: *dst = NUL;
! 1800: }
! 1801:
! 1802: /*
! 1803: * Replace home directory by "~/" in each space or comma separated filename in
! 1804: * 'src'. If anything fails (except when out of space) dst equals src.
! 1805: */
! 1806: void
! 1807: home_replace(buf, src, dst, dstlen)
! 1808: BUF *buf; /* when not NULL, check for help files */
! 1809: char_u *src; /* input file name */
! 1810: char_u *dst; /* where to put the result */
! 1811: int dstlen; /* maximum length of the result */
! 1812: {
! 1813: size_t dirlen = 0, envlen = 0;
! 1814: size_t len;
! 1815: char_u *homedir_env;
! 1816: char_u *p;
! 1817:
! 1818: if (src == NULL)
! 1819: {
! 1820: *dst = NUL;
! 1821: return;
! 1822: }
! 1823:
! 1824: /*
! 1825: * If the file is a help file, remove the path completely.
! 1826: */
! 1827: if (buf != NULL && buf->b_help)
! 1828: {
! 1829: STRCPY(dst, gettail(src));
! 1830: return;
! 1831: }
! 1832:
! 1833: /*
! 1834: * We check both the value of the $HOME environment variable and the
! 1835: * "real" home directory.
! 1836: */
! 1837: if (homedir != NULL)
! 1838: dirlen = STRLEN(homedir);
! 1839: homedir_env = vim_getenv((char_u *)"HOME");
! 1840: if (homedir_env != NULL)
! 1841: envlen = STRLEN(homedir_env);
! 1842:
! 1843: src = skipwhite(src);
! 1844: while (*src && dstlen > 0)
! 1845: {
! 1846: /*
! 1847: * Here we are at the beginning of a filename.
! 1848: * First, check to see if the beginning of the filename matches
! 1849: * $HOME or the "real" home directory. Check that there is a '/'
! 1850: * after the match (so that if e.g. the file is "/home/pieter/bla",
! 1851: * and the home directory is "/home/piet", the file does not end up
! 1852: * as "~er/bla" (which would seem to indicate the file "bla" in user
! 1853: * er's home directory)).
! 1854: */
! 1855: p = homedir;
! 1856: len = dirlen;
! 1857: for (;;)
! 1858: {
! 1859: if (len && fnamencmp(src, p, len) == 0 && (ispathsep(src[len]) ||
! 1860: src[len] == ',' || src[len] == ' ' || src[len] == NUL))
! 1861: {
! 1862: src += len;
! 1863: if (--dstlen > 0)
! 1864: *dst++ = '~';
! 1865: /*
! 1866: * If it's just the home directory, make it "~/".
! 1867: */
! 1868: if (!ispathsep(src[0]) && --dstlen > 0)
! 1869: *dst++ = '/';
! 1870: }
! 1871: if (p == homedir_env)
! 1872: break;
! 1873: p = homedir_env;
! 1874: len = envlen;
! 1875: }
! 1876:
! 1877: /* skip to separator: space or comma */
! 1878: while (*src && *src != ',' && *src != ' ' && --dstlen > 0)
! 1879: *dst++ = *src++;
! 1880: /* skip separator */
! 1881: while ((*src == ' ' || *src == ',') && --dstlen > 0)
! 1882: *dst++ = *src++;
! 1883: }
! 1884: /* if (dstlen == 0) out of space, what to do??? */
! 1885:
! 1886: *dst = NUL;
! 1887: }
! 1888:
! 1889: /*
! 1890: * Like home_replace, store the replaced string in allocated memory.
! 1891: * When something fails, NULL is returned.
! 1892: */
! 1893: char_u *
! 1894: home_replace_save(buf, src)
! 1895: BUF *buf; /* when not NULL, check for help files */
! 1896: char_u *src; /* input file name */
! 1897: {
! 1898: char_u *dst;
! 1899: unsigned len;
! 1900:
! 1901: if (src == NULL) /* just in case */
! 1902: len = 3;
! 1903: else
! 1904: len = STRLEN(src) + 3; /* extra space for "~/" and trailing NUL */
! 1905: dst = alloc(len);
! 1906: if (dst != NULL)
! 1907: home_replace(buf, src, dst, len);
! 1908: return dst;
! 1909: }
! 1910:
! 1911: /*
! 1912: * Compare two file names and return:
! 1913: * FPC_SAME if they both exist and are the same file.
! 1914: * FPC_DIFF if they both exist and are different files.
! 1915: * FPC_NOTX if they both don't exist.
! 1916: * FPC_DIFFX if one of them doesn't exist.
! 1917: * For the first name environment variables are expanded
! 1918: */
! 1919: int
! 1920: fullpathcmp(s1, s2)
! 1921: char_u *s1, *s2;
! 1922: {
! 1923: #ifdef UNIX
! 1924: char_u buf1[MAXPATHL];
! 1925: struct stat st1, st2;
! 1926: int r1, r2;
! 1927:
! 1928: expand_env(s1, buf1, MAXPATHL);
! 1929: r1 = stat((char *)buf1, &st1);
! 1930: r2 = stat((char *)s2, &st2);
! 1931: if (r1 != 0 && r2 != 0)
! 1932: return FPC_NOTX;
! 1933: if (r1 != 0 || r2 != 0)
! 1934: return FPC_DIFFX;
! 1935: if (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino)
! 1936: return FPC_SAME;
! 1937: return FPC_DIFF;
! 1938: #else
! 1939: char_u *buf1 = NULL;
! 1940: char_u *buf2 = NULL;
! 1941: int retval = FPC_DIFF;
! 1942: int r1, r2;
! 1943:
! 1944: if ((buf1 = alloc(MAXPATHL)) != NULL && (buf2 = alloc(MAXPATHL)) != NULL)
! 1945: {
! 1946: expand_env(s1, buf2, MAXPATHL);
! 1947: /*
! 1948: * If FullName() failed, the file probably doesn't exist.
! 1949: */
! 1950: r1 = FullName(buf2, buf1, MAXPATHL, FALSE);
! 1951: r2 = FullName(s2, buf2, MAXPATHL, FALSE);
! 1952: if (r1 != OK && r2 != OK)
! 1953: retval = FPC_NOTX;
! 1954: else if (r1 != OK || r2 != OK)
! 1955: retval = FPC_DIFFX;
! 1956: else if (fnamecmp(buf1, buf2))
! 1957: retval = FPC_DIFF;
! 1958: else
! 1959: retval = FPC_SAME;
! 1960: }
! 1961: vim_free(buf1);
! 1962: vim_free(buf2);
! 1963: return retval;
! 1964: #endif
! 1965: }
! 1966:
! 1967: /*
! 1968: * get the tail of a path: the file name.
! 1969: */
! 1970: char_u *
! 1971: gettail(fname)
! 1972: char_u *fname;
! 1973: {
! 1974: register char_u *p1, *p2;
! 1975:
! 1976: if (fname == NULL)
! 1977: return (char_u *)"";
! 1978: for (p1 = p2 = fname; *p2; ++p2) /* find last part of path */
! 1979: {
! 1980: if (ispathsep(*p2))
! 1981: p1 = p2 + 1;
! 1982: }
! 1983: return p1;
! 1984: }
! 1985:
! 1986: /*
! 1987: * return TRUE if 'c' is a path separator.
! 1988: */
! 1989: int
! 1990: ispathsep(c)
! 1991: int c;
! 1992: {
! 1993: #ifdef UNIX
! 1994: return (c == PATHSEP); /* UNIX has ':' inside file names */
! 1995: #else
! 1996: # ifdef BACKSLASH_IN_FILENAME
! 1997: return (c == ':' || c == PATHSEP || c == '\\');
! 1998: # else
! 1999: return (c == ':' || c == PATHSEP);
! 2000: # endif
! 2001: #endif
! 2002: }
! 2003:
! 2004: /*
! 2005: * Concatenate filenames fname1 and fname2 into allocated memory.
! 2006: * Only add a '/' when 'sep' is TRUE and it is neccesary.
! 2007: */
! 2008: char_u *
! 2009: concat_fnames(fname1, fname2, sep)
! 2010: char_u *fname1;
! 2011: char_u *fname2;
! 2012: int sep;
! 2013: {
! 2014: char_u *dest;
! 2015:
! 2016: dest = alloc((unsigned)(STRLEN(fname1) + STRLEN(fname2) + 2));
! 2017: if (dest != NULL)
! 2018: {
! 2019: STRCPY(dest, fname1);
! 2020: if (sep && *dest && !ispathsep(*(dest + STRLEN(dest) - 1)))
! 2021: STRCAT(dest, PATHSEPSTR);
! 2022: STRCAT(dest, fname2);
! 2023: }
! 2024: return dest;
! 2025: }
! 2026:
! 2027: /*
! 2028: * FullName_save - Make an allocated copy of a full file name.
! 2029: * Returns NULL when failed.
! 2030: */
! 2031: char_u *
! 2032: FullName_save(fname)
! 2033: char_u *fname;
! 2034: {
! 2035: char_u *buf;
! 2036: char_u *new_fname = NULL;
! 2037:
! 2038: buf = alloc((unsigned)MAXPATHL);
! 2039: if (buf != NULL)
! 2040: {
! 2041: if (FullName(fname, buf, MAXPATHL, FALSE) != FAIL)
! 2042: new_fname = strsave(buf);
! 2043: vim_free(buf);
! 2044: }
! 2045: return new_fname;
! 2046: }
! 2047:
! 2048: #ifdef CINDENT
! 2049:
! 2050: /*
! 2051: * Functions for C-indenting.
! 2052: * Most of this originally comes from Eric Fischer.
! 2053: */
! 2054: /*
! 2055: * Below "XXX" means that this function may unlock the current line.
! 2056: */
! 2057:
! 2058: static int isdefault __ARGS((char_u *));
! 2059: static char_u *after_label __ARGS((char_u *l));
! 2060: static int get_indent_nolabel __ARGS((linenr_t lnum));
! 2061: static int skip_label __ARGS((linenr_t, char_u **pp, int ind_maxcomment));
! 2062: static int ispreproc __ARGS((char_u *));
! 2063: static int iscomment __ARGS((char_u *));
! 2064: static int commentorempty __ARGS((char_u *));
! 2065: static int isterminated __ARGS((char_u *));
! 2066: static int isfuncdecl __ARGS((char_u *));
! 2067: static char_u *skip_string __ARGS((char_u *p));
! 2068: static int isif __ARGS((char_u *));
! 2069: static int iselse __ARGS((char_u *));
! 2070: static int isdo __ARGS((char_u *));
! 2071: static int iswhileofdo __ARGS((char_u *, linenr_t, int));
! 2072: static FPOS *find_start_comment __ARGS((int ind_maxcomment));
! 2073: static FPOS *find_start_brace __ARGS((int));
! 2074: static FPOS *find_match_paren __ARGS((int, int));
! 2075: static int find_last_paren __ARGS((char_u *l));
! 2076: static int find_match __ARGS((int lookfor, linenr_t ourscope,
! 2077: int ind_maxparen, int ind_maxcomment));
! 2078:
! 2079: /*
! 2080: * Recognize a label: "label:".
! 2081: * Note: curwin->w_cursor must be where we are looking for the label.
! 2082: */
! 2083: int
! 2084: islabel(ind_maxcomment) /* XXX */
! 2085: int ind_maxcomment;
! 2086: {
! 2087: char_u *s;
! 2088:
! 2089: s = skipwhite(ml_get_curline());
! 2090:
! 2091: /*
! 2092: * Exclude "default" from labels, since it should be indented
! 2093: * like a switch label.
! 2094: */
! 2095:
! 2096: if (isdefault(s))
! 2097: return FALSE;
! 2098:
! 2099: if (!isidchar(*s)) /* need at least one ID character */
! 2100: return FALSE;
! 2101:
! 2102: while (isidchar(*s))
! 2103: s++;
! 2104:
! 2105: s = skipwhite(s);
! 2106:
! 2107: /* "::" is not a label, it's C++ */
! 2108: if (*s == ':' && s[1] != ':')
! 2109: {
! 2110: /*
! 2111: * Only accept a label if the previous line is terminated or is a case
! 2112: * label.
! 2113: */
! 2114: FPOS cursor_save;
! 2115: FPOS *trypos;
! 2116: char_u *line;
! 2117:
! 2118: cursor_save = curwin->w_cursor;
! 2119: while (curwin->w_cursor.lnum > 1)
! 2120: {
! 2121: --curwin->w_cursor.lnum;
! 2122:
! 2123: /*
! 2124: * If we're in a comment now, skip to the start of the comment.
! 2125: */
! 2126: curwin->w_cursor.col = 0;
! 2127: if ((trypos = find_start_comment(ind_maxcomment)) != NULL) /* XXX */
! 2128: curwin->w_cursor = *trypos;
! 2129:
! 2130: line = ml_get_curline();
! 2131: if (ispreproc(line)) /* ignore #defines, #if, etc. */
! 2132: continue;
! 2133: if (commentorempty(line))
! 2134: continue;
! 2135:
! 2136: curwin->w_cursor = cursor_save;
! 2137: if (isterminated(line) || iscase(line))
! 2138: return TRUE;
! 2139: return FALSE;
! 2140: }
! 2141: curwin->w_cursor = cursor_save;
! 2142: return TRUE; /* label at start of file??? */
! 2143: }
! 2144: return FALSE;
! 2145: }
! 2146:
! 2147: /*
! 2148: * Recognize a switch label: "case .*:" or "default:".
! 2149: */
! 2150: int
! 2151: iscase(s)
! 2152: char_u *s;
! 2153: {
! 2154: s = skipwhite(s);
! 2155: if (STRNCMP(s, "case", 4) == 0 && !isidchar(s[4]))
! 2156: {
! 2157: for (s += 4; *s; ++s)
! 2158: if (*s == ':')
! 2159: {
! 2160: if (s[1] == ':') /* skip over "::" for C++ */
! 2161: ++s;
! 2162: else
! 2163: return TRUE;
! 2164: }
! 2165: return FALSE;
! 2166: }
! 2167:
! 2168: if (isdefault(s))
! 2169: return TRUE;
! 2170: return FALSE;
! 2171: }
! 2172:
! 2173: /*
! 2174: * Recognize a "default" switch label.
! 2175: */
! 2176: static int
! 2177: isdefault(s)
! 2178: char_u *s;
! 2179: {
! 2180: return (STRNCMP(s, "default", 7) == 0 &&
! 2181: *(s = skipwhite(s + 7)) == ':' &&
! 2182: s[1] != ':');
! 2183: }
! 2184:
! 2185: /*
! 2186: * Return a pointer to the first non-empty non-comment character after a ':'.
! 2187: * Return NULL if not found.
! 2188: * case 234: a = b;
! 2189: * ^
! 2190: */
! 2191: static char_u *
! 2192: after_label(l)
! 2193: char_u *l;
! 2194: {
! 2195: for ( ; *l; ++l)
! 2196: if (*l == ':')
! 2197: {
! 2198: if (l[1] == ':') /* skip over "::" for C++ */
! 2199: ++l;
! 2200: else
! 2201: break;
! 2202: }
! 2203: if (*l == NUL)
! 2204: return NULL;
! 2205: l = skipwhite(l + 1);
! 2206: if (commentorempty(l))
! 2207: return NULL;
! 2208: return l;
! 2209: }
! 2210:
! 2211: /*
! 2212: * Get indent of line "lnum", skipping a label.
! 2213: * Return 0 if there is nothing after the label.
! 2214: */
! 2215: static int
! 2216: get_indent_nolabel(lnum) /* XXX */
! 2217: linenr_t lnum;
! 2218: {
! 2219: char_u *l;
! 2220: FPOS fp;
! 2221: colnr_t col;
! 2222: char_u *p;
! 2223:
! 2224: l = ml_get(lnum);
! 2225: p = after_label(l);
! 2226: if (p == NULL)
! 2227: return 0;
! 2228:
! 2229: fp.col = p - l;
! 2230: fp.lnum = lnum;
! 2231: getvcol(curwin, &fp, &col, NULL, NULL);
! 2232: return (int)col;
! 2233: }
! 2234:
! 2235: /*
! 2236: * Find indent for line "lnum", ignoring any case or jump label.
! 2237: * Also return a pointer to the text (after the label).
! 2238: * label: if (asdf && asdfasdf)
! 2239: * ^
! 2240: */
! 2241: static int
! 2242: skip_label(lnum, pp, ind_maxcomment)
! 2243: linenr_t lnum;
! 2244: char_u **pp;
! 2245: int ind_maxcomment;
! 2246: {
! 2247: char_u *l;
! 2248: int amount;
! 2249: FPOS cursor_save;
! 2250:
! 2251: cursor_save = curwin->w_cursor;
! 2252: curwin->w_cursor.lnum = lnum;
! 2253: l = ml_get_curline();
! 2254: if (iscase(l) || islabel(ind_maxcomment)) /* XXX */
! 2255: {
! 2256: amount = get_indent_nolabel(lnum);
! 2257: l = after_label(ml_get_curline());
! 2258: if (l == NULL) /* just in case */
! 2259: l = ml_get_curline();
! 2260: }
! 2261: else
! 2262: {
! 2263: amount = get_indent();
! 2264: l = ml_get_curline();
! 2265: }
! 2266: *pp = l;
! 2267:
! 2268: curwin->w_cursor = cursor_save;
! 2269: return amount;
! 2270: }
! 2271:
! 2272: /*
! 2273: * Recognize a preprocessor statement: Any line that starts with '#'.
! 2274: */
! 2275: static int
! 2276: ispreproc(s)
! 2277: char_u *s;
! 2278: {
! 2279: s = skipwhite(s);
! 2280: if (*s == '#')
! 2281: return TRUE;
! 2282: return 0;
! 2283: }
! 2284:
! 2285: /*
! 2286: * Recognize the start of a C or C++ comment.
! 2287: */
! 2288: static int
! 2289: iscomment(p)
! 2290: char_u *p;
! 2291: {
! 2292: return (p[0] == '/' && (p[1] == '*' || p[1] == '/'));
! 2293: }
! 2294:
! 2295: /*
! 2296: * Recognize an empty or comment line.
! 2297: */
! 2298: static int
! 2299: commentorempty(s)
! 2300: char_u *s;
! 2301: {
! 2302: s = skipwhite(s);
! 2303: if (*s == NUL || iscomment(s))
! 2304: return TRUE;
! 2305: return FALSE;
! 2306: }
! 2307:
! 2308: /*
! 2309: * Recognize a line that starts with '{' or '}', or ends with ';' or '}'.
! 2310: * Also consider a line terminated if it ends in ','. This is not 100%
! 2311: * correct, but this mostly means we are in initializations and then it's OK.
! 2312: */
! 2313: static int
! 2314: isterminated(s)
! 2315: char_u *s;
! 2316: {
! 2317: s = skipwhite(s);
! 2318:
! 2319: if (*s == '{' || *s == '}')
! 2320: return TRUE;
! 2321:
! 2322: while (*s)
! 2323: {
! 2324: if (iscomment(s)) /* at start of comment ignore rest of line */
! 2325: return FALSE;
! 2326: s = skip_string(s);
! 2327: if ((*s == ';' || *s == '{' || *s == ',') && commentorempty(s + 1))
! 2328: return TRUE;
! 2329: s++;
! 2330: }
! 2331: return FALSE;
! 2332: }
! 2333:
! 2334: /*
! 2335: * Recognize the basic picture of a function declaration -- it needs to
! 2336: * have an open paren somewhere and a close paren at the end of the line and
! 2337: * no semicolons anywhere.
! 2338: */
! 2339: static int
! 2340: isfuncdecl(s)
! 2341: char_u *s;
! 2342: {
! 2343: while (*s && *s != '(' && *s != ';')
! 2344: if (iscomment(s++))
! 2345: return FALSE; /* comment before () ??? */
! 2346: if (*s != '(')
! 2347: return FALSE; /* ';' before any () or no '(' */
! 2348:
! 2349: while (*s && *s != ';')
! 2350: {
! 2351: if (*s == ')' && commentorempty(s + 1))
! 2352: return TRUE;
! 2353: if (iscomment(s++))
! 2354: return FALSE; /* comment between ( and ) ??? */
! 2355: }
! 2356: return FALSE;
! 2357: }
! 2358:
! 2359: /*
! 2360: * Skip over a "string" and a 'c' character.
! 2361: */
! 2362: static char_u *
! 2363: skip_string(p)
! 2364: char_u *p;
! 2365: {
! 2366: int i;
! 2367:
! 2368: /*
! 2369: * We loop, because strings may be concatenated: "date""time".
! 2370: */
! 2371: for ( ; ; ++p)
! 2372: {
! 2373: if (p[0] == '\'') /* 'c' or '\n' or '\000' */
! 2374: {
! 2375: if (!p[1]) /* ' at end of line */
! 2376: break;
! 2377: i = 2;
! 2378: if (p[1] == '\\') /* '\n' or '\000' */
! 2379: {
! 2380: ++i;
! 2381: while (isdigit(p[i - 1])) /* '\000' */
! 2382: ++i;
! 2383: }
! 2384: if (p[i] == '\'') /* check for trailing ' */
! 2385: {
! 2386: p += i;
! 2387: continue;
! 2388: }
! 2389: }
! 2390: else if (p[0] == '"') /* start of string */
! 2391: {
! 2392: for (++p; p[0]; ++p)
! 2393: {
! 2394: if (p[0] == '\\' && p[1])
! 2395: ++p;
! 2396: else if (p[0] == '"') /* end of string */
! 2397: break;
! 2398: }
! 2399: continue;
! 2400: }
! 2401: break; /* no string found */
! 2402: }
! 2403: if (!*p)
! 2404: --p; /* backup from NUL */
! 2405: return p;
! 2406: }
! 2407:
! 2408: static int
! 2409: isif(p)
! 2410: char_u *p;
! 2411: {
! 2412: return (STRNCMP(p, "if", 2) == 0 && !isidchar(p[2]));
! 2413: }
! 2414:
! 2415: static int
! 2416: iselse(p)
! 2417: char_u *p;
! 2418: {
! 2419: return (STRNCMP(p, "else", 4) == 0 && !isidchar(p[4]));
! 2420: }
! 2421:
! 2422: static int
! 2423: isdo(p)
! 2424: char_u *p;
! 2425: {
! 2426: return (STRNCMP(p, "do", 2) == 0 && !isidchar(p[2]));
! 2427: }
! 2428:
! 2429: /*
! 2430: * Check if this is a "while" that should have a matching "do".
! 2431: * We only accept a "while (condition) ;", with only white space between the
! 2432: * ')' and ';'. The condition may be spread over several lines.
! 2433: */
! 2434: static int
! 2435: iswhileofdo(p, lnum, ind_maxparen) /* XXX */
! 2436: char_u *p;
! 2437: linenr_t lnum;
! 2438: int ind_maxparen;
! 2439: {
! 2440: FPOS cursor_save;
! 2441: FPOS *trypos;
! 2442: int retval = FALSE;
! 2443:
! 2444: p = skipwhite(p);
! 2445: if (STRNCMP(p, "while", 5) == 0 && !isidchar(p[5]))
! 2446: {
! 2447: cursor_save = curwin->w_cursor;
! 2448: curwin->w_cursor.lnum = lnum;
! 2449: curwin->w_cursor.col = 0;
! 2450: if ((trypos = findmatchlimit(0, 0, ind_maxparen)) != NULL)
! 2451: {
! 2452: p = ml_get_pos(trypos) + 1;
! 2453: p = skipwhite(p);
! 2454: if (*p == ';')
! 2455: retval = TRUE;
! 2456: }
! 2457: curwin->w_cursor = cursor_save;
! 2458: }
! 2459: return retval;
! 2460: }
! 2461:
! 2462: /*
! 2463: * Find the start of a comment, not knowing if we are in a comment right now.
! 2464: * Search starts at w_cursor.lnum and goes backwards.
! 2465: */
! 2466: static FPOS *
! 2467: find_start_comment(ind_maxcomment) /* XXX */
! 2468: int ind_maxcomment;
! 2469: {
! 2470: FPOS *pos;
! 2471: char_u *line;
! 2472: char_u *p;
! 2473:
! 2474: if ((pos = findmatchlimit('*', FM_BACKWARD, ind_maxcomment)) == NULL)
! 2475: return NULL;
! 2476:
! 2477: /*
! 2478: * Check if the comment start we found is inside a string.
! 2479: */
! 2480: line = ml_get(pos->lnum);
! 2481: for (p = line; *p && (unsigned)(p - line) < pos->col; ++p)
! 2482: p = skip_string(p);
! 2483: if ((unsigned)(p - line) > pos->col)
! 2484: return NULL;
! 2485: return pos;
! 2486: }
! 2487:
! 2488: /*
! 2489: * Find the '{' at the start of the block we are in.
! 2490: * Return NULL of no match found.
! 2491: * Ignore a '{' that is in a comment, makes indenting the next three lines
! 2492: * work. */
! 2493: /* foo() */
! 2494: /* { */
! 2495: /* } */
! 2496:
! 2497: static FPOS *
! 2498: find_start_brace(ind_maxcomment) /* XXX */
! 2499: int ind_maxcomment;
! 2500: {
! 2501: FPOS cursor_save;
! 2502: FPOS *trypos;
! 2503: FPOS *pos;
! 2504: static FPOS pos_copy;
! 2505:
! 2506: cursor_save = curwin->w_cursor;
! 2507: while ((trypos = findmatchlimit('{', FM_BLOCKSTOP, 0)) != NULL)
! 2508: {
! 2509: pos_copy = *trypos; /* copy FPOS, next findmatch will change it */
! 2510: trypos = &pos_copy;
! 2511: curwin->w_cursor = *trypos;
! 2512: pos = NULL;
! 2513: if (!iscomment(skipwhite(ml_get(trypos->lnum))) &&
! 2514: (pos = find_start_comment(ind_maxcomment)) == NULL) /* XXX */
! 2515: break;
! 2516: if (pos != NULL)
! 2517: curwin->w_cursor.lnum = pos->lnum;
! 2518: }
! 2519: curwin->w_cursor = cursor_save;
! 2520: return trypos;
! 2521: }
! 2522:
! 2523: /*
! 2524: * Find the matching '(', failing if it is in a comment.
! 2525: * Return NULL of no match found.
! 2526: */
! 2527: static FPOS *
! 2528: find_match_paren(ind_maxparen, ind_maxcomment) /* XXX */
! 2529: int ind_maxparen;
! 2530: int ind_maxcomment;
! 2531: {
! 2532: FPOS cursor_save;
! 2533: FPOS *trypos;
! 2534: static FPOS pos_copy;
! 2535:
! 2536: cursor_save = curwin->w_cursor;
! 2537: if ((trypos = findmatchlimit('(', 0, ind_maxparen)) != NULL)
! 2538: {
! 2539: if (iscomment(skipwhite(ml_get(trypos->lnum))))
! 2540: trypos = NULL;
! 2541: else
! 2542: {
! 2543: pos_copy = *trypos; /* copy trypos, findmatch will change it */
! 2544: trypos = &pos_copy;
! 2545: curwin->w_cursor = *trypos;
! 2546: if (find_start_comment(ind_maxcomment) != NULL) /* XXX */
! 2547: trypos = NULL;
! 2548: }
! 2549: }
! 2550: curwin->w_cursor = cursor_save;
! 2551: return trypos;
! 2552: }
! 2553:
! 2554: /*
! 2555: * Set w_cursor.col to the column number of the last ')' in line "l".
! 2556: */
! 2557: static int
! 2558: find_last_paren(l)
! 2559: char_u *l;
! 2560: {
! 2561: int i;
! 2562: int retval = FALSE;
! 2563:
! 2564: curwin->w_cursor.col = 0; /* default is start of line */
! 2565:
! 2566: for (i = 0; l[i]; i++)
! 2567: {
! 2568: i = skip_string(l + i) - l; /* ignore parens in quotes */
! 2569: if (l[i] == ')')
! 2570: {
! 2571: curwin->w_cursor.col = i;
! 2572: retval = TRUE;
! 2573: }
! 2574: }
! 2575: return retval;
! 2576: }
! 2577:
! 2578: int
! 2579: get_c_indent()
! 2580: {
! 2581: /*
! 2582: * spaces from a block's opening brace the prevailing indent for that
! 2583: * block should be
! 2584: */
! 2585: int ind_level = curbuf->b_p_sw;
! 2586:
! 2587: /*
! 2588: * spaces from the edge of the line an open brace that's at the end of a
! 2589: * line is imagined to be.
! 2590: */
! 2591: int ind_open_imag = 0;
! 2592:
! 2593: /*
! 2594: * spaces from the prevailing indent for a line that is not precededof by
! 2595: * an opening brace.
! 2596: */
! 2597: int ind_no_brace = 0;
! 2598:
! 2599: /*
! 2600: * column where the first { of a function should be located
! 2601: */
! 2602: int ind_first_open = 0;
! 2603:
! 2604: /*
! 2605: * spaces from the prevailing indent a leftmost open brace should be
! 2606: * located
! 2607: */
! 2608: int ind_open_extra = 0;
! 2609:
! 2610: /*
! 2611: * spaces from the matching open brace (real location for one at the left
! 2612: * edge; imaginary location from one that ends a line) the matching close
! 2613: * brace should be located
! 2614: */
! 2615: int ind_close_extra = 0;
! 2616:
! 2617: /*
! 2618: * spaces from the edge of the line an open brace sitting in the leftmost
! 2619: * column is imagined to be
! 2620: */
! 2621: int ind_open_left_imag = 0;
! 2622:
! 2623: /*
! 2624: * spaces from the switch() indent a "case xx" label should be located
! 2625: */
! 2626: int ind_case = curbuf->b_p_sw;
! 2627:
! 2628: /*
! 2629: * spaces from the "case xx:" code after a switch() should be located
! 2630: */
! 2631: int ind_case_code = curbuf->b_p_sw;
! 2632:
! 2633: /*
! 2634: * amount K&R-style parameters should be indented
! 2635: */
! 2636: int ind_param = curbuf->b_p_sw;
! 2637:
! 2638: /*
! 2639: * amount a function type spec should be indented
! 2640: */
! 2641: int ind_func_type = curbuf->b_p_sw;
! 2642:
! 2643: /*
! 2644: * additional spaces beyond the prevailing indent a continuation line
! 2645: * should be located
! 2646: */
! 2647: int ind_continuation = curbuf->b_p_sw;
! 2648:
! 2649: /*
! 2650: * spaces from the indent of the line with an unclosed parentheses
! 2651: */
! 2652: int ind_unclosed = curbuf->b_p_sw * 2;
! 2653:
! 2654: /*
! 2655: * spaces from the comment opener when there is nothing after it.
! 2656: */
! 2657: int ind_in_comment = 3;
! 2658:
! 2659: /*
! 2660: * max lines to search for an open paren
! 2661: */
! 2662: int ind_maxparen = 20;
! 2663:
! 2664: /*
! 2665: * max lines to search for an open comment
! 2666: */
! 2667: int ind_maxcomment = 30;
! 2668:
! 2669: FPOS cur_curpos;
! 2670: int amount;
! 2671: int scope_amount;
! 2672: int cur_amount;
! 2673: colnr_t col;
! 2674: char_u *theline;
! 2675: char_u *linecopy;
! 2676: FPOS *trypos;
! 2677: FPOS our_paren_pos;
! 2678: char_u *start;
! 2679: int start_brace;
! 2680: #define BRACE_IN_COL0 1 /* '{' is in comumn 0 */
! 2681: #define BRACE_AT_START 2 /* '{' is at start of line */
! 2682: #define BRACE_AT_END 3 /* '{' is at end of line */
! 2683: linenr_t ourscope;
! 2684: char_u *l;
! 2685: char_u *look;
! 2686: int lookfor;
! 2687: #define LOOKFOR_IF 1
! 2688: #define LOOKFOR_DO 2
! 2689: #define LOOKFOR_CASE 3
! 2690: #define LOOKFOR_ANY 4
! 2691: #define LOOKFOR_TERM 5
! 2692: #define LOOKFOR_UNTERM 6
! 2693: int whilelevel;
! 2694: linenr_t lnum;
! 2695: char_u *options;
! 2696: int fraction = 0; /* init for GCC */
! 2697: int divider;
! 2698: int n;
! 2699:
! 2700: for (options = curbuf->b_p_cino; *options; )
! 2701: {
! 2702: l = options++;
! 2703: if (*options == '-')
! 2704: ++options;
! 2705: n = getdigits(&options);
! 2706: divider = 0;
! 2707: if (*options == '.') /* ".5s" means a fraction */
! 2708: {
! 2709: fraction = atol((char *)++options);
! 2710: while (isdigit(*options))
! 2711: {
! 2712: ++options;
! 2713: if (divider)
! 2714: divider *= 10;
! 2715: else
! 2716: divider = 10;
! 2717: }
! 2718: }
! 2719: if (*options == 's') /* "2s" means two times 'shiftwidth' */
! 2720: {
! 2721: if (n == 0 && fraction == 0)
! 2722: n = curbuf->b_p_sw; /* just "s" is one 'shiftwidth' */
! 2723: else
! 2724: {
! 2725: n *= curbuf->b_p_sw;
! 2726: if (divider)
! 2727: n += (curbuf->b_p_sw * fraction + divider / 2) / divider;
! 2728: }
! 2729: ++options;
! 2730: }
! 2731: if (l[1] == '-')
! 2732: n = -n;
! 2733: switch (*l)
! 2734: {
! 2735: case '>': ind_level = n; break;
! 2736: case 'e': ind_open_imag = n; break;
! 2737: case 'n': ind_no_brace = n; break;
! 2738: case 'f': ind_first_open = n; break;
! 2739: case '{': ind_open_extra = n; break;
! 2740: case '}': ind_close_extra = n; break;
! 2741: case '^': ind_open_left_imag = n; break;
! 2742: case ':': ind_case = n; break;
! 2743: case '=': ind_case_code = n; break;
! 2744: case 'p': ind_param = n; break;
! 2745: case 't': ind_func_type = n; break;
! 2746: case 'c': ind_in_comment = n; break;
! 2747: case '+': ind_continuation = n; break;
! 2748: case '(': ind_unclosed = n; break;
! 2749: case ')': ind_maxparen = n; break;
! 2750: case '*': ind_maxcomment = n; break;
! 2751: }
! 2752: }
! 2753:
! 2754: /* remember where the cursor was when we started */
! 2755:
! 2756: cur_curpos = curwin->w_cursor;
! 2757:
! 2758: /* get the current contents of the line.
! 2759: * This is required, because onle the most recent line obtained with
! 2760: * ml_get is valid! */
! 2761:
! 2762: linecopy = strsave(ml_get(cur_curpos.lnum));
! 2763: if (linecopy == NULL)
! 2764: return 0;
! 2765:
! 2766: /*
! 2767: * In insert mode and the cursor is on a ')' trunctate the line at the
! 2768: * cursor position. We don't want to line up with the matching '(' when
! 2769: * inserting new stuff.
! 2770: */
! 2771: if ((State & INSERT) && linecopy[curwin->w_cursor.col] == ')')
! 2772: linecopy[curwin->w_cursor.col] = NUL;
! 2773:
! 2774: theline = skipwhite(linecopy);
! 2775:
! 2776: /* move the cursor to the start of the line */
! 2777:
! 2778: curwin->w_cursor.col = 0;
! 2779:
! 2780: /*
! 2781: * #defines and so on always go at the left when included in 'cinkeys'.
! 2782: */
! 2783: if (*theline == '#' && (*linecopy == '#' || in_cinkeys('#', ' ', TRUE)))
! 2784: {
! 2785: amount = 0;
! 2786: }
! 2787:
! 2788: /*
! 2789: * Is it a non-case label? Then that goes at the left margin too.
! 2790: */
! 2791: else if (islabel(ind_maxcomment)) /* XXX */
! 2792: {
! 2793: amount = 0;
! 2794: }
! 2795:
! 2796: /*
! 2797: * If we're inside a comment and not looking at the start of the
! 2798: * comment...
! 2799: */
! 2800: else if (!iscomment(theline) &&
! 2801: (trypos = find_start_comment(ind_maxcomment)) != NULL) /* XXX */
! 2802: {
! 2803:
! 2804: /* find how indented the line beginning the comment is */
! 2805: getvcol(curwin, trypos, &col, NULL, NULL);
! 2806: amount = col;
! 2807:
! 2808: /* if our line starts with an asterisk, line up with the
! 2809: * asterisk in the comment opener; otherwise, line up
! 2810: * with the first character of the comment text.
! 2811: */
! 2812: if (theline[0] == '*')
! 2813: {
! 2814: amount += 1;
! 2815: }
! 2816: else
! 2817: {
! 2818: /*
! 2819: * If we are more than one line away from the comment opener, take
! 2820: * the indent of the previous non-empty line.
! 2821: * If we are just below the comment opener and there are any
! 2822: * white characters after it line up with the text after it.
! 2823: * up with them; otherwise, just use a single space.
! 2824: */
! 2825: amount = -1;
! 2826: for (lnum = cur_curpos.lnum - 1; lnum > trypos->lnum; --lnum)
! 2827: {
! 2828: if (linewhite(lnum)) /* skip blank lines */
! 2829: continue;
! 2830: amount = get_indent_lnum(lnum); /* XXX */
! 2831: break;
! 2832: }
! 2833: if (amount == -1) /* use the comment opener */
! 2834: {
! 2835: start = ml_get(trypos->lnum);
! 2836: look = start + trypos->col + 2; /* skip / and * */
! 2837: if (*look) /* if something after it */
! 2838: trypos->col = skipwhite(look) - start;
! 2839: getvcol(curwin, trypos, &col, NULL, NULL);
! 2840: amount = col;
! 2841: if (!*look)
! 2842: amount += ind_in_comment;
! 2843: }
! 2844: }
! 2845: }
! 2846:
! 2847: /*
! 2848: * Are we inside parentheses?
! 2849: */ /* XXX */
! 2850: else if ((trypos = find_match_paren(ind_maxparen, ind_maxcomment)) != NULL)
! 2851: {
! 2852: /*
! 2853: * If the matching paren is more than one line away, use the indent of
! 2854: * a previous non-empty line that matches the same paren.
! 2855: */
! 2856: amount = -1;
! 2857: our_paren_pos = *trypos;
! 2858: if (theline[0] != ')')
! 2859: {
! 2860: for (lnum = cur_curpos.lnum - 1; lnum > our_paren_pos.lnum; --lnum)
! 2861: {
! 2862: l = skipwhite(ml_get(lnum));
! 2863: if (commentorempty(l)) /* skip comment lines */
! 2864: continue;
! 2865: if (ispreproc(l)) /* ignore #defines, #if, etc. */
! 2866: continue;
! 2867: curwin->w_cursor.lnum = lnum;
! 2868: /* XXX */
! 2869: if ((trypos = find_match_paren(ind_maxparen,
! 2870: ind_maxcomment)) != NULL &&
! 2871: trypos->lnum == our_paren_pos.lnum &&
! 2872: trypos->col == our_paren_pos.col)
! 2873: {
! 2874: amount = get_indent_lnum(lnum); /* XXX */
! 2875: break;
! 2876: }
! 2877: }
! 2878: }
! 2879:
! 2880: /*
! 2881: * Line up with line where the matching paren is.
! 2882: * If the line starts with a '(' or the indent for unclosed
! 2883: * parentheses is zero, line up with the unclosed parentheses.
! 2884: */
! 2885: if (amount == -1)
! 2886: {
! 2887: amount = skip_label(our_paren_pos.lnum, &look, ind_maxcomment);
! 2888: if (theline[0] == ')' || ind_unclosed == 0 ||
! 2889: *skipwhite(look) == '(')
! 2890: {
! 2891:
! 2892: /*
! 2893: * If we're looking at a close paren, line up right there;
! 2894: * otherwise, line up with the next non-white character.
! 2895: */
! 2896: if (theline[0] != ')')
! 2897: {
! 2898: col = our_paren_pos.col + 1;
! 2899: look = ml_get(our_paren_pos.lnum);
! 2900: while (vim_iswhite(look[col]))
! 2901: col++;
! 2902: if (look[col] != NUL) /* In case of trailing space */
! 2903: our_paren_pos.col = col;
! 2904: else
! 2905: our_paren_pos.col++;
! 2906: }
! 2907:
! 2908: /*
! 2909: * Find how indented the paren is, or the character after it if
! 2910: * we did the above "if".
! 2911: */
! 2912: getvcol(curwin, &our_paren_pos, &col, NULL, NULL);
! 2913: amount = col;
! 2914: }
! 2915: else
! 2916: amount += ind_unclosed;
! 2917: }
! 2918: }
! 2919:
! 2920: /*
! 2921: * Are we at least inside braces, then?
! 2922: */
! 2923: else if ((trypos = find_start_brace(ind_maxcomment)) != NULL) /* XXX */
! 2924: {
! 2925: ourscope = trypos->lnum;
! 2926: start = ml_get(ourscope);
! 2927:
! 2928: /*
! 2929: * Now figure out how indented the line is in general.
! 2930: * If the brace was at the start of the line, we use that;
! 2931: * otherwise, check out the indentation of the line as
! 2932: * a whole and then add the "imaginary indent" to that.
! 2933: */
! 2934: look = skipwhite(start);
! 2935: if (*look == '{')
! 2936: {
! 2937: getvcol(curwin, trypos, &col, NULL, NULL);
! 2938: amount = col;
! 2939: if (*start == '{')
! 2940: start_brace = BRACE_IN_COL0;
! 2941: else
! 2942: start_brace = BRACE_AT_START;
! 2943: }
! 2944: else
! 2945: {
! 2946: /*
! 2947: * that opening brace might have been on a continuation
! 2948: * line. if so, find the start of the line.
! 2949: */
! 2950: curwin->w_cursor.lnum = ourscope;
! 2951:
! 2952: /*
! 2953: * position the cursor over the rightmost paren, so that
! 2954: * matching it will take us back to the start of the line.
! 2955: */
! 2956: lnum = ourscope;
! 2957: if (find_last_paren(start) &&
! 2958: (trypos = find_match_paren(ind_maxparen,
! 2959: ind_maxcomment)) != NULL)
! 2960: lnum = trypos->lnum;
! 2961:
! 2962: /*
! 2963: * It could have been something like
! 2964: * case 1: if (asdf &&
! 2965: * ldfd) {
! 2966: * }
! 2967: */
! 2968: amount = skip_label(lnum, &l, ind_maxcomment);
! 2969:
! 2970: start_brace = BRACE_AT_END;
! 2971: }
! 2972:
! 2973: /*
! 2974: * if we're looking at a closing brace, that's where
! 2975: * we want to be. otherwise, add the amount of room
! 2976: * that an indent is supposed to be.
! 2977: */
! 2978: if (theline[0] == '}')
! 2979: {
! 2980: /*
! 2981: * they may want closing braces to line up with something
! 2982: * other than the open brace. indulge them, if so.
! 2983: */
! 2984: amount += ind_close_extra;
! 2985: }
! 2986: else
! 2987: {
! 2988: /*
! 2989: * If we're looking at an "else", try to find an "if"
! 2990: * to match it with.
! 2991: * If we're looking at a "while", try to find a "do"
! 2992: * to match it with.
! 2993: */
! 2994: lookfor = 0;
! 2995: if (iselse(theline))
! 2996: lookfor = LOOKFOR_IF;
! 2997: else if (iswhileofdo(theline, cur_curpos.lnum, ind_maxparen))
! 2998: /* XXX */
! 2999: lookfor = LOOKFOR_DO;
! 3000: if (lookfor)
! 3001: {
! 3002: curwin->w_cursor.lnum = cur_curpos.lnum;
! 3003: if (find_match(lookfor, ourscope, ind_maxparen,
! 3004: ind_maxcomment) == OK)
! 3005: {
! 3006: amount = get_indent(); /* XXX */
! 3007: goto theend;
! 3008: }
! 3009: }
! 3010:
! 3011: /*
! 3012: * We get here if we are not on an "while-of-do" or "else" (or
! 3013: * failed to find a matching "if").
! 3014: * Search backwards for something to line up with.
! 3015: * First set amount for when we don't find anything.
! 3016: */
! 3017:
! 3018: /*
! 3019: * if the '{' is _really_ at the left margin, use the imaginary
! 3020: * location of a left-margin brace. Otherwise, correct the
! 3021: * location for ind_open_extra.
! 3022: */
! 3023:
! 3024: if (start_brace == BRACE_IN_COL0) /* '{' is in column 0 */
! 3025: {
! 3026: amount = ind_open_left_imag;
! 3027: }
! 3028: else
! 3029: {
! 3030: if (start_brace == BRACE_AT_END) /* '{' is at end of line */
! 3031: amount += ind_open_imag;
! 3032: else
! 3033: {
! 3034: amount -= ind_open_extra;
! 3035: if (amount < 0)
! 3036: amount = 0;
! 3037: }
! 3038: }
! 3039:
! 3040: if (iscase(theline)) /* it's a switch() label */
! 3041: {
! 3042: lookfor = LOOKFOR_CASE; /* find a previous switch() label */
! 3043: amount += ind_case;
! 3044: }
! 3045: else
! 3046: {
! 3047: lookfor = LOOKFOR_ANY;
! 3048: amount += ind_level; /* ind_level from start of block */
! 3049: }
! 3050: scope_amount = amount;
! 3051: whilelevel = 0;
! 3052:
! 3053: /*
! 3054: * Search backwards. If we find something we recognize, line up
! 3055: * with that.
! 3056: *
! 3057: * if we're looking at an open brace, indent
! 3058: * the usual amount relative to the conditional
! 3059: * that opens the block.
! 3060: */
! 3061: curwin->w_cursor = cur_curpos;
! 3062: for (;;)
! 3063: {
! 3064: curwin->w_cursor.lnum--;
! 3065: curwin->w_cursor.col = 0;
! 3066:
! 3067: /*
! 3068: * If we went all the way back to the start of our scope, line
! 3069: * up with it.
! 3070: */
! 3071: if (curwin->w_cursor.lnum <= ourscope)
! 3072: {
! 3073: if (lookfor == LOOKFOR_UNTERM)
! 3074: amount += ind_continuation;
! 3075: else if (lookfor != LOOKFOR_TERM)
! 3076: amount = scope_amount;
! 3077: break;
! 3078: }
! 3079:
! 3080: /*
! 3081: * If we're in a comment now, skip to the start of the comment.
! 3082: */ /* XXX */
! 3083: if ((trypos = find_start_comment(ind_maxcomment)) != NULL)
! 3084: {
! 3085: curwin->w_cursor.lnum = trypos->lnum + 1;
! 3086: continue;
! 3087: }
! 3088:
! 3089: l = ml_get_curline();
! 3090:
! 3091: /*
! 3092: * If this is a switch() label, may line up relative to that.
! 3093: */
! 3094: if (iscase(l))
! 3095: {
! 3096: /*
! 3097: * case xx:
! 3098: * c = 99 + <- this indent plus continuation
! 3099: *-> here;
! 3100: */
! 3101: if (lookfor == LOOKFOR_UNTERM)
! 3102: {
! 3103: amount += ind_continuation;
! 3104: break;
! 3105: }
! 3106:
! 3107: /*
! 3108: * case xx: <- line up with this case
! 3109: * x = 333;
! 3110: * case yy:
! 3111: */
! 3112: if (lookfor == LOOKFOR_CASE)
! 3113: {
! 3114: /*
! 3115: * Check that this case label is not for another
! 3116: * switch()
! 3117: */ /* XXX */
! 3118: if ((trypos = find_start_brace(ind_maxcomment)) ==
! 3119: NULL || trypos->lnum == ourscope)
! 3120: {
! 3121: amount = get_indent(); /* XXX */
! 3122: break;
! 3123: }
! 3124: continue;
! 3125: }
! 3126:
! 3127: n = get_indent_nolabel(curwin->w_cursor.lnum); /* XXX */
! 3128:
! 3129: /*
! 3130: * case xx: if (cond) <- line up with this if
! 3131: * y = y + 1;
! 3132: * -> s = 99;
! 3133: *
! 3134: * case xx:
! 3135: * if (cond) <- line up with this line
! 3136: * y = y + 1;
! 3137: * -> s = 99;
! 3138: */
! 3139: if (lookfor == LOOKFOR_TERM)
! 3140: {
! 3141: if (n)
! 3142: amount = n;
! 3143: break;
! 3144: }
! 3145:
! 3146: /*
! 3147: * case xx: x = x + 1; <- line up with this x
! 3148: * -> y = y + 1;
! 3149: *
! 3150: * case xx: if (cond) <- line up with this if
! 3151: * -> y = y + 1;
! 3152: */
! 3153: if (n)
! 3154: {
! 3155: amount = n;
! 3156: l = after_label(ml_get_curline());
! 3157: if (l != NULL && is_cinword(l))
! 3158: amount += ind_level + ind_no_brace;
! 3159: break;
! 3160: }
! 3161:
! 3162: /*
! 3163: * Try to get the indent of a statement before the
! 3164: * switch label. If nothing is found, line up relative
! 3165: * to the switch label.
! 3166: * break; <- may line up with this line
! 3167: * case xx:
! 3168: * -> y = 1;
! 3169: */
! 3170: scope_amount = get_indent() + ind_case_code; /* XXX */
! 3171: lookfor = LOOKFOR_ANY;
! 3172: continue;
! 3173: }
! 3174:
! 3175: /*
! 3176: * Looking for a switch() label, ignore other lines.
! 3177: */
! 3178: if (lookfor == LOOKFOR_CASE)
! 3179: continue;
! 3180:
! 3181: /*
! 3182: * Ignore jump labels with nothing after them.
! 3183: */
! 3184: if (islabel(ind_maxcomment))
! 3185: {
! 3186: l = after_label(ml_get_curline());
! 3187: if (l == NULL || commentorempty(l))
! 3188: continue;
! 3189: }
! 3190:
! 3191: /*
! 3192: * Ignore #defines, #if, etc.
! 3193: * Ignore comment and empty lines.
! 3194: * (need to get the line again, islabel() may have unlocked it)
! 3195: */
! 3196: l = ml_get_curline();
! 3197: if (ispreproc(l) || commentorempty(l))
! 3198: continue;
! 3199:
! 3200: /*
! 3201: * What happens next depends on the line being terminated.
! 3202: */
! 3203: if (!isterminated(l))
! 3204: {
! 3205: /*
! 3206: * if we're in the middle of a paren thing,
! 3207: * go back to the line that starts it so
! 3208: * we can get the right prevailing indent
! 3209: * if ( foo &&
! 3210: * bar )
! 3211: */
! 3212: /*
! 3213: * position the cursor over the rightmost paren, so that
! 3214: * matching it will take us back to the start of the line.
! 3215: */
! 3216: (void)find_last_paren(l);
! 3217: if ((trypos = find_match_paren(ind_maxparen,
! 3218: ind_maxcomment)) != NULL)
! 3219: {
! 3220: /*
! 3221: * Check if we are on a case label now. This is
! 3222: * handled above.
! 3223: * case xx: if ( asdf &&
! 3224: * asdf)
! 3225: */
! 3226: curwin->w_cursor.lnum = trypos->lnum;
! 3227: l = ml_get_curline();
! 3228: if (iscase(l))
! 3229: {
! 3230: ++curwin->w_cursor.lnum;
! 3231: continue;
! 3232: }
! 3233: }
! 3234:
! 3235: /*
! 3236: * Get indent and pointer to text for current line,
! 3237: * ignoring any jump label. XXX
! 3238: */
! 3239: cur_amount = skip_label(curwin->w_cursor.lnum,
! 3240: &l, ind_maxcomment);
! 3241:
! 3242: /*
! 3243: * If this is just above the line we are indenting, and it
! 3244: * starts with a '{', line it up with this line.
! 3245: * while (not)
! 3246: * -> {
! 3247: * }
! 3248: */
! 3249: if (lookfor != LOOKFOR_TERM && theline[0] == '{')
! 3250: {
! 3251: amount = cur_amount + ind_open_extra;
! 3252: break;
! 3253: }
! 3254:
! 3255: /*
! 3256: * Check if we are after an "if", "while", etc.
! 3257: */
! 3258: if (is_cinword(l))
! 3259: {
! 3260: /*
! 3261: * Found an unterminated line after an if (), line up
! 3262: * with the last one.
! 3263: * if (cond)
! 3264: * 100 +
! 3265: * -> here;
! 3266: */
! 3267: if (lookfor == LOOKFOR_UNTERM)
! 3268: {
! 3269: amount += ind_continuation;
! 3270: break;
! 3271: }
! 3272:
! 3273: /*
! 3274: * If this is just above the line we are indenting, we
! 3275: * are finished.
! 3276: * while (not)
! 3277: * -> here;
! 3278: * Otherwise this indent can be used when the line
! 3279: * before this is terminated.
! 3280: * yyy;
! 3281: * if (stat)
! 3282: * while (not)
! 3283: * xxx;
! 3284: * -> here;
! 3285: */
! 3286: amount = cur_amount;
! 3287: if (lookfor != LOOKFOR_TERM)
! 3288: {
! 3289: amount += ind_level + ind_no_brace;
! 3290: break;
! 3291: }
! 3292:
! 3293: /*
! 3294: * Special trick: when expecting the while () after a
! 3295: * do, line up with the while()
! 3296: * do
! 3297: * x = 1;
! 3298: * -> here
! 3299: */
! 3300: l = skipwhite(ml_get_curline());
! 3301: if (isdo(l))
! 3302: {
! 3303: if (whilelevel == 0)
! 3304: break;
! 3305: --whilelevel;
! 3306: }
! 3307:
! 3308: /*
! 3309: * When searching for a terminated line, don't use the
! 3310: * one between the "if" and the "else".
! 3311: */
! 3312: if (iselse(l))
! 3313: {
! 3314: if (find_match(LOOKFOR_IF, ourscope,
! 3315: ind_maxparen, ind_maxcomment) == FAIL)
! 3316: break;
! 3317: }
! 3318: }
! 3319:
! 3320: /*
! 3321: * If we're below an unterminated line that is not an
! 3322: * "if" or something, we may line up with this line or
! 3323: * add someting for a continuation line, depending on
! 3324: * the line before this one.
! 3325: */
! 3326: else
! 3327: {
! 3328: /*
! 3329: * Found two unterminated lines on a row, line up with
! 3330: * the last one.
! 3331: * c = 99 +
! 3332: * 100 +
! 3333: * -> here;
! 3334: */
! 3335: if (lookfor == LOOKFOR_UNTERM)
! 3336: break;
! 3337:
! 3338: /*
! 3339: * Found first unterminated line on a row, may line up
! 3340: * with this line, remember its indent
! 3341: * 100 +
! 3342: * -> here;
! 3343: */
! 3344: amount = cur_amount;
! 3345: if (lookfor != LOOKFOR_TERM)
! 3346: lookfor = LOOKFOR_UNTERM;
! 3347: }
! 3348: }
! 3349:
! 3350: /*
! 3351: * Check if we are after a while (cond);
! 3352: * If so: Ignore the matching "do".
! 3353: */
! 3354: /* XXX */
! 3355: else if (iswhileofdo(l, curwin->w_cursor.lnum, ind_maxparen))
! 3356: {
! 3357: /*
! 3358: * Found an unterminated line after a while ();, line up
! 3359: * with the last one.
! 3360: * while (cond);
! 3361: * 100 + <- line up with this one
! 3362: * -> here;
! 3363: */
! 3364: if (lookfor == LOOKFOR_UNTERM)
! 3365: {
! 3366: amount += ind_continuation;
! 3367: break;
! 3368: }
! 3369:
! 3370: if (whilelevel == 0)
! 3371: {
! 3372: lookfor = LOOKFOR_TERM;
! 3373: amount = get_indent(); /* XXX */
! 3374: if (theline[0] == '{')
! 3375: amount += ind_open_extra;
! 3376: }
! 3377: ++whilelevel;
! 3378: }
! 3379:
! 3380: /*
! 3381: * We are after a "normal" statement.
! 3382: * If we had another statement we can stop now and use the
! 3383: * indent of that other statement.
! 3384: * Otherwise the indent of the current statement may be used,
! 3385: * search backwards for the next "normal" statement.
! 3386: */
! 3387: else
! 3388: {
! 3389: /*
! 3390: * Found a terminated line above an unterminated line. Add
! 3391: * the amount for a continuation line.
! 3392: * x = 1;
! 3393: * y = foo +
! 3394: * -> here;
! 3395: */
! 3396: if (lookfor == LOOKFOR_UNTERM)
! 3397: {
! 3398: amount += ind_continuation;
! 3399: break;
! 3400: }
! 3401:
! 3402: /*
! 3403: * Found a terminated line above a terminated line or "if"
! 3404: * etc. line. Use the amount of the line below us.
! 3405: * x = 1; x = 1;
! 3406: * if (asdf) y = 2;
! 3407: * while (asdf) ->here;
! 3408: * here;
! 3409: * ->foo;
! 3410: */
! 3411: if (lookfor == LOOKFOR_TERM)
! 3412: {
! 3413: if (whilelevel == 0)
! 3414: break;
! 3415: }
! 3416:
! 3417: /*
! 3418: * First line above the one we're indenting is terminated.
! 3419: * To know what needs to be done look further backward for
! 3420: * a terminated line.
! 3421: */
! 3422: else
! 3423: {
! 3424: /*
! 3425: * position the cursor over the rightmost paren, so
! 3426: * that matching it will take us back to the start of
! 3427: * the line. Helps for:
! 3428: * func(asdr,
! 3429: * asdfasdf);
! 3430: * here;
! 3431: */
! 3432: l = ml_get_curline();
! 3433: if (find_last_paren(l) &&
! 3434: (trypos = find_match_paren(ind_maxparen,
! 3435: ind_maxcomment)) != NULL)
! 3436: {
! 3437: /*
! 3438: * Check if we are on a case label now. This is
! 3439: * handled above.
! 3440: * case xx: if ( asdf &&
! 3441: * asdf)
! 3442: */
! 3443: curwin->w_cursor.lnum = trypos->lnum;
! 3444: l = ml_get_curline();
! 3445: if (iscase(l))
! 3446: {
! 3447: ++curwin->w_cursor.lnum;
! 3448: continue;
! 3449: }
! 3450: }
! 3451:
! 3452: /*
! 3453: * Get indent and pointer to text for current line,
! 3454: * ignoring any jump label.
! 3455: */
! 3456: amount = skip_label(curwin->w_cursor.lnum,
! 3457: &l, ind_maxcomment);
! 3458:
! 3459: if (theline[0] == '{')
! 3460: amount += ind_open_extra;
! 3461: lookfor = LOOKFOR_TERM;
! 3462:
! 3463: /*
! 3464: * If we're at the end of a block, skip to the start of
! 3465: * that block.
! 3466: */
! 3467: if (*skipwhite(l) == '}' &&
! 3468: (trypos = find_start_brace(ind_maxcomment))
! 3469: != NULL) /* XXX */
! 3470: curwin->w_cursor.lnum = trypos->lnum;
! 3471: }
! 3472: }
! 3473: }
! 3474: }
! 3475: }
! 3476:
! 3477: /*
! 3478: * ok -- we're not inside any sort of structure at all!
! 3479: *
! 3480: * this means we're at the top level, and everything should
! 3481: * basically just match where the previous line is, except
! 3482: * for the lines immediately following a function declaration,
! 3483: * which are K&R-style parameters and need to be indented.
! 3484: */
! 3485: else
! 3486: {
! 3487: /*
! 3488: * if our line starts with an open brace, forget about any
! 3489: * prevailing indent and make sure it looks like the start
! 3490: * of a function
! 3491: */
! 3492:
! 3493: if (theline[0] == '{')
! 3494: {
! 3495: amount = ind_first_open;
! 3496: }
! 3497:
! 3498: /*
! 3499: * If the NEXT line is a function declaration, the current
! 3500: * line needs to be indented as a function type spec.
! 3501: * Don't do this if the current line looks like a comment.
! 3502: */
! 3503: else if (cur_curpos.lnum < curbuf->b_ml.ml_line_count &&
! 3504: !commentorempty(theline) &&
! 3505: isfuncdecl(ml_get(cur_curpos.lnum + 1)))
! 3506: {
! 3507: amount = ind_func_type;
! 3508: }
! 3509: else
! 3510: {
! 3511: amount = 0;
! 3512: curwin->w_cursor = cur_curpos;
! 3513:
! 3514: /* search backwards until we find something we recognize */
! 3515:
! 3516: while (curwin->w_cursor.lnum > 1)
! 3517: {
! 3518: curwin->w_cursor.lnum--;
! 3519: curwin->w_cursor.col = 0;
! 3520:
! 3521: l = ml_get_curline();
! 3522:
! 3523: /*
! 3524: * If we're in a comment now, skip to the start of the comment.
! 3525: */ /* XXX */
! 3526: if ((trypos = find_start_comment(ind_maxcomment)) != NULL)
! 3527: {
! 3528: curwin->w_cursor.lnum = trypos->lnum + 1;
! 3529: continue;
! 3530: }
! 3531:
! 3532: /*
! 3533: * If the line looks like a function declaration, and we're
! 3534: * not in a comment, put it the left margin.
! 3535: */
! 3536: if (isfuncdecl(theline))
! 3537: break;
! 3538:
! 3539: /*
! 3540: * Skip preprocessor directives and blank lines.
! 3541: */
! 3542: if (ispreproc(l))
! 3543: continue;
! 3544:
! 3545: if (commentorempty(l))
! 3546: continue;
! 3547:
! 3548: /*
! 3549: * If the PREVIOUS line is a function declaration, the current
! 3550: * line (and the ones that follow) needs to be indented as
! 3551: * parameters.
! 3552: */
! 3553: if (isfuncdecl(l))
! 3554: {
! 3555: amount = ind_param;
! 3556: break;
! 3557: }
! 3558:
! 3559: /*
! 3560: * Doesn't look like anything interesting -- so just
! 3561: * use the indent of this line.
! 3562: *
! 3563: * Position the cursor over the rightmost paren, so that
! 3564: * matching it will take us back to the start of the line.
! 3565: */
! 3566: find_last_paren(l);
! 3567:
! 3568: if ((trypos = find_match_paren(ind_maxparen,
! 3569: ind_maxcomment)) != NULL)
! 3570: curwin->w_cursor.lnum = trypos->lnum;
! 3571: amount = get_indent(); /* XXX */
! 3572: break;
! 3573: }
! 3574: }
! 3575: }
! 3576:
! 3577: theend:
! 3578: /* put the cursor back where it belongs */
! 3579: curwin->w_cursor = cur_curpos;
! 3580:
! 3581: vim_free(linecopy);
! 3582:
! 3583: if (amount < 0)
! 3584: return 0;
! 3585: return amount;
! 3586: }
! 3587:
! 3588: static int
! 3589: find_match(lookfor, ourscope, ind_maxparen, ind_maxcomment)
! 3590: int lookfor;
! 3591: linenr_t ourscope;
! 3592: int ind_maxparen;
! 3593: int ind_maxcomment;
! 3594: {
! 3595: char_u *look;
! 3596: FPOS *theirscope;
! 3597: char_u *mightbeif;
! 3598: int elselevel;
! 3599: int whilelevel;
! 3600:
! 3601: if (lookfor == LOOKFOR_IF)
! 3602: {
! 3603: elselevel = 1;
! 3604: whilelevel = 0;
! 3605: }
! 3606: else
! 3607: {
! 3608: elselevel = 0;
! 3609: whilelevel = 1;
! 3610: }
! 3611:
! 3612: curwin->w_cursor.col = 0;
! 3613:
! 3614: while (curwin->w_cursor.lnum > ourscope + 1)
! 3615: {
! 3616: curwin->w_cursor.lnum--;
! 3617: curwin->w_cursor.col = 0;
! 3618:
! 3619: look = skipwhite(ml_get_curline());
! 3620: if (iselse(look) || isif(look) || isdo(look) ||
! 3621: iswhileofdo(look, curwin->w_cursor.lnum, ind_maxparen)) /* XXX */
! 3622: {
! 3623: /*
! 3624: * if we've gone outside the braces entirely,
! 3625: * we must be out of scope...
! 3626: */
! 3627: theirscope = find_start_brace(ind_maxcomment); /* XXX */
! 3628: if (theirscope == NULL)
! 3629: break;
! 3630:
! 3631: /*
! 3632: * and if the brace enclosing this is further
! 3633: * back than the one enclosing the else, we're
! 3634: * out of luck too.
! 3635: */
! 3636: if (theirscope->lnum < ourscope)
! 3637: break;
! 3638:
! 3639: /*
! 3640: * and if they're enclosed in a *deeper* brace,
! 3641: * then we can ignore it because it's in a
! 3642: * different scope...
! 3643: */
! 3644: if (theirscope->lnum > ourscope)
! 3645: continue;
! 3646:
! 3647: /*
! 3648: * if it was an "else" (that's not an "else if")
! 3649: * then we need to go back to another if, so
! 3650: * increment elselevel
! 3651: */
! 3652: look = skipwhite(ml_get_curline());
! 3653: if (iselse(look))
! 3654: {
! 3655: mightbeif = skipwhite(look + 4);
! 3656: if (!isif(mightbeif))
! 3657: ++elselevel;
! 3658: continue;
! 3659: }
! 3660:
! 3661: /*
! 3662: * if it was a "while" then we need to go back to
! 3663: * another "do", so increment whilelevel.
! 3664: */
! 3665: if (iswhileofdo(look, curwin->w_cursor.lnum, ind_maxparen))/* XXX */
! 3666: {
! 3667: ++whilelevel;
! 3668: continue;
! 3669: }
! 3670:
! 3671: /* If it's an "if" decrement elselevel */
! 3672: look = skipwhite(ml_get_curline());
! 3673: if (isif(look))
! 3674: {
! 3675: elselevel--;
! 3676: /*
! 3677: * When looking for an "if" ignore "while"s that
! 3678: * get in the way.
! 3679: */
! 3680: if (elselevel == 0 && lookfor == LOOKFOR_IF)
! 3681: whilelevel = 0;
! 3682: }
! 3683:
! 3684: /* If it's a "do" decrement whilelevel */
! 3685: if (isdo(look))
! 3686: whilelevel--;
! 3687:
! 3688: /*
! 3689: * if we've used up all the elses, then
! 3690: * this must be the if that we want!
! 3691: * match the indent level of that if.
! 3692: */
! 3693: if (elselevel <= 0 && whilelevel <= 0)
! 3694: {
! 3695: return OK;
! 3696: }
! 3697: }
! 3698: }
! 3699: return FAIL;
! 3700: }
! 3701:
! 3702: #endif /* CINDENT */
! 3703:
! 3704: #ifdef LISPINDENT
! 3705: int
! 3706: get_lisp_indent()
! 3707: {
! 3708: FPOS *pos, realpos;
! 3709: long amount = 0;
! 3710: char_u *that;
! 3711: colnr_t col;
! 3712: colnr_t maybe;
! 3713: colnr_t firsttry;
! 3714:
! 3715:
! 3716: realpos = curwin->w_cursor;
! 3717: curwin->w_cursor.col = 0;
! 3718:
! 3719: if ((pos = findmatch('(')) != NULL)
! 3720: {
! 3721: curwin->w_cursor.lnum = pos->lnum;
! 3722: curwin->w_cursor.col = pos->col;
! 3723: col = pos->col;
! 3724:
! 3725: that = ml_get_curline();
! 3726: maybe = get_indent(); /* XXX */
! 3727:
! 3728: if (maybe == 0)
! 3729: amount = 2;
! 3730: else
! 3731: {
! 3732: while (*that && col)
! 3733: {
! 3734: amount += lbr_chartabsize(that, (colnr_t)amount);
! 3735: col--;
! 3736: that++;
! 3737: }
! 3738:
! 3739: that++;
! 3740: amount++;
! 3741: firsttry = amount;
! 3742:
! 3743: /*
! 3744: * Go to the start of the second word.
! 3745: * If there is no second word, go back to firsttry.
! 3746: * Also stop at a '('.
! 3747: */
! 3748:
! 3749: while (vim_iswhite(*that))
! 3750: {
! 3751: amount += lbr_chartabsize(that, (colnr_t)amount);
! 3752: that++;
! 3753: }
! 3754: while (*that && !vim_iswhite(*that) && *that != '(')
! 3755: {
! 3756: amount += lbr_chartabsize(that, (colnr_t)amount);
! 3757: that++;
! 3758: }
! 3759: while (vim_iswhite(*that))
! 3760: {
! 3761: amount += lbr_chartabsize(that, (colnr_t)amount);
! 3762: that++;
! 3763: }
! 3764: if (! *that)
! 3765: amount = firsttry;
! 3766: }
! 3767: }
! 3768: else /* no matching '(' found, use indent of previous non-empty line */
! 3769: {
! 3770: while (curwin->w_cursor.lnum > 1)
! 3771: {
! 3772: --curwin->w_cursor.lnum;
! 3773: if (!linewhite(curwin->w_cursor.lnum))
! 3774: break;
! 3775: }
! 3776: amount = get_indent(); /* XXX */
! 3777: }
! 3778:
! 3779: curwin->w_cursor = realpos;
! 3780:
! 3781: if (amount < 0)
! 3782: amount = 0;
! 3783: return (int)amount;
! 3784: }
! 3785: #endif /* LISPINDENT */
! 3786:
! 3787: #if defined(UNIX) || defined(WIN32) || defined(__EMX__)
! 3788: /*
! 3789: * Preserve files and exit.
! 3790: * When called IObuff must contain a message.
! 3791: */
! 3792: void
! 3793: preserve_exit()
! 3794: {
! 3795: BUF *buf;
! 3796:
! 3797: #ifdef USE_GUI
! 3798: if (gui.in_use)
! 3799: {
! 3800: gui.dying = TRUE;
! 3801: trash_output_buf(); /* trash any pending output */
! 3802: }
! 3803: else
! 3804: #endif
! 3805: {
! 3806: windgoto((int)Rows - 1, 0);
! 3807:
! 3808: /*
! 3809: * Switch terminal mode back now, so these messages end up on the
! 3810: * "normal" screen (if there are two screens).
! 3811: */
! 3812: settmode(0);
! 3813: #ifdef WIN32
! 3814: if (can_end_termcap_mode(FALSE) == TRUE)
! 3815: #endif
! 3816: stoptermcap();
! 3817: flushbuf();
! 3818: }
! 3819:
! 3820: outstr(IObuff);
! 3821: screen_start(); /* don't know where cursor is now */
! 3822: flushbuf();
! 3823:
! 3824: ml_close_notmod(); /* close all not-modified buffers */
! 3825:
! 3826: for (buf = firstbuf; buf != NULL; buf = buf->b_next)
! 3827: {
! 3828: if (buf->b_ml.ml_mfp != NULL && buf->b_ml.ml_mfp->mf_fname != NULL)
! 3829: {
! 3830: OUTSTR("Vim: preserving files...\n");
! 3831: screen_start(); /* don't know where cursor is now */
! 3832: flushbuf();
! 3833: ml_sync_all(FALSE, FALSE); /* preserve all swap files */
! 3834: break;
! 3835: }
! 3836: }
! 3837:
! 3838: ml_close_all(FALSE); /* close all memfiles, without deleting */
! 3839:
! 3840: OUTSTR("Vim: Finished.\n");
! 3841:
! 3842: getout(1);
! 3843: }
! 3844: #endif /* defined(UNIX) || defined(WIN32) || defined(__EMX__) */
! 3845:
! 3846: /*
! 3847: * return TRUE if "fname" exists.
! 3848: */
! 3849: int
! 3850: vim_fexists(fname)
! 3851: char_u *fname;
! 3852: {
! 3853: struct stat st;
! 3854:
! 3855: if (stat((char *)fname, &st))
! 3856: return FALSE;
! 3857: return TRUE;
! 3858: }
! 3859:
! 3860: /*
! 3861: * Check for CTRL-C pressed, but only once in a while.
! 3862: * Should be used instead of mch_breakcheck() for functions that check for
! 3863: * each line in the file. Calling mch_breakcheck() each time takes too much
! 3864: * time, because it can be a system call.
! 3865: */
! 3866:
! 3867: #ifndef BREAKCHECK_SKIP
! 3868: # define BREAKCHECK_SKIP 32
! 3869: #endif
! 3870:
! 3871: void
! 3872: line_breakcheck()
! 3873: {
! 3874: static int count = 0;
! 3875:
! 3876: if (++count == BREAKCHECK_SKIP)
! 3877: {
! 3878: count = 0;
! 3879: mch_breakcheck();
! 3880: }
! 3881: }
! 3882:
! 3883: /*
! 3884: * Free the list of files returned by ExpandWildCards() or other expansion
! 3885: * functions.
! 3886: */
! 3887: void
! 3888: FreeWild(num, file)
! 3889: int num;
! 3890: char_u **file;
! 3891: {
! 3892: if (file == NULL || num == 0)
! 3893: return;
! 3894: #if defined(__EMX__) && defined(__ALWAYS_HAS_TRAILING_NULL_POINTER) /* XXX */
! 3895: /*
! 3896: * Is this still OK for when other functions thatn ExpandWildCards() have
! 3897: * been used???
! 3898: */
! 3899: _fnexplodefree((char **)file);
! 3900: #else
! 3901: while (num--)
! 3902: vim_free(file[num]);
! 3903: vim_free(file);
! 3904: #endif
! 3905: }
! 3906: