Annotation of src/usr.bin/vim/window.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 a list of people who contributed.
! 7: * Do ":help credits" in Vim to see a list of people who contributed.
! 8: */
! 9:
! 10: #include "vim.h"
! 11: #include "globals.h"
! 12: #include "proto.h"
! 13: #include "option.h"
! 14:
! 15: static void reset_VIsual __ARGS((void));
! 16: static int win_comp_pos __ARGS((void));
! 17: static void win_exchange __ARGS((long));
! 18: static void win_rotate __ARGS((int, int));
! 19: static void win_append __ARGS((WIN *, WIN *));
! 20: static void win_remove __ARGS((WIN *));
! 21: static void win_new_height __ARGS((WIN *, int));
! 22:
! 23: static WIN *prevwin = NULL; /* previous window */
! 24:
! 25: /*
! 26: * all CTRL-W window commands are handled here, called from normal().
! 27: */
! 28: void
! 29: do_window(nchar, Prenum)
! 30: int nchar;
! 31: long Prenum;
! 32: {
! 33: long Prenum1;
! 34: WIN *wp;
! 35: char_u *ptr;
! 36: int len;
! 37: int type = -1;
! 38: WIN *wp2;
! 39:
! 40: if (Prenum == 0)
! 41: Prenum1 = 1;
! 42: else
! 43: Prenum1 = Prenum;
! 44:
! 45: switch (nchar)
! 46: {
! 47: /* split current window in two parts */
! 48: case 'S':
! 49: case Ctrl('S'):
! 50: case 's': reset_VIsual(); /* stop Visual mode */
! 51: win_split((int)Prenum, TRUE);
! 52: break;
! 53:
! 54: /* split current window and edit alternate file */
! 55: case K_CCIRCM:
! 56: case '^':
! 57: reset_VIsual(); /* stop Visual mode */
! 58: stuffReadbuff((char_u *)":split #");
! 59: if (Prenum)
! 60: stuffnumReadbuff(Prenum); /* buffer number */
! 61: stuffcharReadbuff('\n');
! 62: break;
! 63:
! 64: /* open new window */
! 65: case Ctrl('N'):
! 66: case 'n': reset_VIsual(); /* stop Visual mode */
! 67: stuffcharReadbuff(':');
! 68: if (Prenum)
! 69: stuffnumReadbuff(Prenum); /* window height */
! 70: stuffReadbuff((char_u *)"new\n"); /* it is cmdline.c */
! 71: break;
! 72:
! 73: /* quit current window */
! 74: case Ctrl('Q'):
! 75: case 'q': reset_VIsual(); /* stop Visual mode */
! 76: stuffReadbuff((char_u *)":quit\n"); /* it is cmdline.c */
! 77: break;
! 78:
! 79: /* close current window */
! 80: case Ctrl('C'):
! 81: case 'c': reset_VIsual(); /* stop Visual mode */
! 82: stuffReadbuff((char_u *)":close\n"); /* it is cmdline.c */
! 83: break;
! 84:
! 85: /* close all but current window */
! 86: case Ctrl('O'):
! 87: case 'o': reset_VIsual(); /* stop Visual mode */
! 88: stuffReadbuff((char_u *)":only\n"); /* it is cmdline.c */
! 89: break;
! 90:
! 91: /* cursor to next window */
! 92: case 'j':
! 93: case K_DOWN:
! 94: case Ctrl('J'):
! 95: for (wp = curwin; wp->w_next != NULL && Prenum1-- > 0;
! 96: wp = wp->w_next)
! 97: ;
! 98: new_win:
! 99: /*
! 100: * When jumping to another buffer, stop visual mode
! 101: * Do this before changing windows so we can yank the
! 102: * selection into the '"*' register.
! 103: */
! 104: if (wp->w_buffer != curbuf && VIsual_active)
! 105: {
! 106: end_visual_mode();
! 107: for (wp2 = firstwin; wp2 != NULL; wp2 = wp2->w_next)
! 108: if (wp2->w_buffer == curbuf &&
! 109: wp2->w_redr_type < NOT_VALID)
! 110: {
! 111: wp2->w_redr_type = NOT_VALID;
! 112: redraw_later(NOT_VALID);
! 113: }
! 114: }
! 115: win_enter(wp, TRUE);
! 116: cursupdate();
! 117: break;
! 118:
! 119: /* cursor to next window with wrap around */
! 120: case Ctrl('W'):
! 121: case 'w':
! 122: /* cursor to previous window with wrap around */
! 123: case 'W':
! 124: if (lastwin == firstwin) /* just one window */
! 125: beep_flush();
! 126: else
! 127: {
! 128: if (Prenum) /* go to specified window */
! 129: {
! 130: for (wp = firstwin; --Prenum > 0; )
! 131: {
! 132: if (wp->w_next == NULL)
! 133: break;
! 134: else
! 135: wp = wp->w_next;
! 136: }
! 137: }
! 138: else
! 139: {
! 140: if (nchar == 'W') /* go to previous window */
! 141: {
! 142: wp = curwin->w_prev;
! 143: if (wp == NULL)
! 144: wp = lastwin; /* wrap around */
! 145: }
! 146: else /* go to next window */
! 147: {
! 148: wp = curwin->w_next;
! 149: if (wp == NULL)
! 150: wp = firstwin; /* wrap around */
! 151: }
! 152: }
! 153: goto new_win;
! 154: }
! 155: break;
! 156:
! 157: /* cursor to window above */
! 158: case 'k':
! 159: case K_UP:
! 160: case Ctrl('K'):
! 161: for (wp = curwin; wp->w_prev != NULL && Prenum1-- > 0;
! 162: wp = wp->w_prev)
! 163: ;
! 164: goto new_win;
! 165:
! 166: /* cursor to top window */
! 167: case 't':
! 168: case Ctrl('T'):
! 169: wp = firstwin;
! 170: goto new_win;
! 171:
! 172: /* cursor to bottom window */
! 173: case 'b':
! 174: case Ctrl('B'):
! 175: wp = lastwin;
! 176: goto new_win;
! 177:
! 178: /* cursor to last accessed (previous) window */
! 179: case 'p':
! 180: case Ctrl('P'):
! 181: if (prevwin == NULL)
! 182: beep_flush();
! 183: else
! 184: {
! 185: wp = prevwin;
! 186: goto new_win;
! 187: }
! 188: break;
! 189:
! 190: /* exchange current and next window */
! 191: case 'x':
! 192: case Ctrl('X'):
! 193: win_exchange(Prenum);
! 194: break;
! 195:
! 196: /* rotate windows downwards */
! 197: case Ctrl('R'):
! 198: case 'r': reset_VIsual(); /* stop Visual mode */
! 199: win_rotate(FALSE, (int)Prenum1); /* downwards */
! 200: break;
! 201:
! 202: /* rotate windows upwards */
! 203: case 'R': reset_VIsual(); /* stop Visual mode */
! 204: win_rotate(TRUE, (int)Prenum1); /* upwards */
! 205: break;
! 206:
! 207: /* make all windows the same height */
! 208: case '=': win_equal(NULL, TRUE);
! 209: break;
! 210:
! 211: /* increase current window height */
! 212: case '+': win_setheight(curwin->w_height + (int)Prenum1);
! 213: break;
! 214:
! 215: /* decrease current window height */
! 216: case '-': win_setheight(curwin->w_height - (int)Prenum1);
! 217: break;
! 218:
! 219: /* set current window height */
! 220: case Ctrl('_'):
! 221: case '_': win_setheight(Prenum ? (int)Prenum : 9999);
! 222: break;
! 223:
! 224: /* jump to tag and split window if tag exists */
! 225: case ']':
! 226: case Ctrl(']'):
! 227: reset_VIsual(); /* stop Visual mode */
! 228: postponed_split = TRUE;
! 229: stuffcharReadbuff(Ctrl(']'));
! 230: break;
! 231:
! 232: /* edit file name under cursor in a new window */
! 233: case 'f':
! 234: case Ctrl('F'):
! 235: reset_VIsual(); /* stop Visual mode */
! 236: ptr = file_name_at_cursor(FNAME_MESS|FNAME_HYP|FNAME_EXP);
! 237: if (ptr != NULL)
! 238: {
! 239: setpcmark();
! 240: if (win_split(0, FALSE) == OK)
! 241: (void)do_ecmd(0, ptr, NULL, NULL, p_hid, (linenr_t)0, FALSE);
! 242: vim_free(ptr);
! 243: }
! 244: break;
! 245:
! 246: /* Go to the first occurence of the identifier under cursor along path in a
! 247: * new window -- webb
! 248: */
! 249: case 'i': /* Go to any match */
! 250: case Ctrl('I'):
! 251: type = FIND_ANY;
! 252: /* FALLTHROUGH */
! 253: case 'd': /* Go to definition, using p_def */
! 254: case Ctrl('D'):
! 255: if (type == -1)
! 256: type = FIND_DEFINE;
! 257:
! 258: if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0)
! 259: break;
! 260: find_pattern_in_path(ptr, len, TRUE, TRUE, type,
! 261: Prenum1, ACTION_SPLIT, (linenr_t)1, (linenr_t)MAXLNUM);
! 262: curwin->w_set_curswant = TRUE;
! 263: break;
! 264:
! 265: default: beep_flush();
! 266: break;
! 267: }
! 268: }
! 269:
! 270: static void
! 271: reset_VIsual()
! 272: {
! 273: if (VIsual_active)
! 274: {
! 275: end_visual_mode();
! 276: update_curbuf(NOT_VALID); /* delete the inversion */
! 277: }
! 278: }
! 279:
! 280: /*
! 281: * split the current window, implements CTRL-W s and :split
! 282: *
! 283: * new_height is the height for the new window, 0 to make half of current
! 284: * height redraw is TRUE when redraw now
! 285: *
! 286: * return FAIL for failure, OK otherwise
! 287: */
! 288: int
! 289: win_split(new_height, redraw)
! 290: int new_height;
! 291: int redraw;
! 292: {
! 293: WIN *wp;
! 294: linenr_t lnum;
! 295: int h;
! 296: int i;
! 297: int need_status;
! 298: int do_equal = (p_ea && new_height == 0);
! 299: int needed;
! 300: int available;
! 301: int curwin_height;
! 302:
! 303: /* add a status line when p_ls == 1 and splitting the first window */
! 304: if (lastwin == firstwin && p_ls == 1 && curwin->w_status_height == 0)
! 305: need_status = STATUS_HEIGHT;
! 306: else
! 307: need_status = 0;
! 308:
! 309: /*
! 310: * check if we are able to split the current window and compute its height
! 311: */
! 312: available = curwin->w_height;
! 313: needed = 2 * MIN_ROWS + STATUS_HEIGHT + need_status;
! 314: if (p_ea)
! 315: {
! 316: for (wp = firstwin; wp != NULL; wp = wp->w_next)
! 317: if (wp != curwin)
! 318: {
! 319: available += wp->w_height;
! 320: needed += MIN_ROWS;
! 321: }
! 322: }
! 323: if (available < needed)
! 324: {
! 325: EMSG(e_noroom);
! 326: return FAIL;
! 327: }
! 328: curwin_height = curwin->w_height;
! 329: if (need_status)
! 330: {
! 331: curwin->w_status_height = STATUS_HEIGHT;
! 332: curwin_height -= STATUS_HEIGHT;
! 333: }
! 334: if (new_height == 0)
! 335: new_height = curwin_height / 2;
! 336:
! 337: if (new_height > curwin_height - MIN_ROWS - STATUS_HEIGHT)
! 338: new_height = curwin_height - MIN_ROWS - STATUS_HEIGHT;
! 339:
! 340: if (new_height < MIN_ROWS)
! 341: new_height = MIN_ROWS;
! 342:
! 343: /* if it doesn't fit in the current window, need win_equal() */
! 344: if (curwin_height - new_height - STATUS_HEIGHT < MIN_ROWS)
! 345: do_equal = TRUE;
! 346: /*
! 347: * allocate new window structure and link it in the window list
! 348: */
! 349: if (p_sb) /* new window below current one */
! 350: wp = win_alloc(curwin);
! 351: else
! 352: wp = win_alloc(curwin->w_prev);
! 353: if (wp == NULL)
! 354: return FAIL;
! 355: /*
! 356: * compute the new screen positions
! 357: */
! 358: win_new_height(wp, new_height);
! 359: win_new_height(curwin, curwin_height - (new_height + STATUS_HEIGHT));
! 360: if (p_sb) /* new window below current one */
! 361: {
! 362: wp->w_winpos = curwin->w_winpos + curwin->w_height + STATUS_HEIGHT;
! 363: wp->w_status_height = curwin->w_status_height;
! 364: curwin->w_status_height = STATUS_HEIGHT;
! 365: }
! 366: else /* new window above current one */
! 367: {
! 368: wp->w_winpos = curwin->w_winpos;
! 369: wp->w_status_height = STATUS_HEIGHT;
! 370: curwin->w_winpos = wp->w_winpos + wp->w_height + STATUS_HEIGHT;
! 371: }
! 372: /*
! 373: * make the contents of the new window the same as the current one
! 374: */
! 375: wp->w_buffer = curbuf;
! 376: curbuf->b_nwindows++;
! 377: wp->w_cursor = curwin->w_cursor;
! 378: wp->w_row = curwin->w_row;
! 379: wp->w_col = curwin->w_col;
! 380: wp->w_virtcol = curwin->w_virtcol;
! 381: wp->w_curswant = curwin->w_curswant;
! 382: wp->w_set_curswant = curwin->w_set_curswant;
! 383: wp->w_empty_rows = curwin->w_empty_rows;
! 384: wp->w_leftcol = curwin->w_leftcol;
! 385: wp->w_pcmark = curwin->w_pcmark;
! 386: wp->w_prev_pcmark = curwin->w_prev_pcmark;
! 387: wp->w_alt_fnum = curwin->w_alt_fnum;
! 388:
! 389: wp->w_arg_idx = curwin->w_arg_idx;
! 390: /*
! 391: * copy tagstack and options from existing window
! 392: */
! 393: for (i = 0; i < curwin->w_tagstacklen; i++)
! 394: {
! 395: wp->w_tagstack[i].fmark = curwin->w_tagstack[i].fmark;
! 396: wp->w_tagstack[i].tagname = strsave(curwin->w_tagstack[i].tagname);
! 397: }
! 398: wp->w_tagstackidx = curwin->w_tagstackidx;
! 399: wp->w_tagstacklen = curwin->w_tagstacklen;
! 400: win_copy_options(curwin, wp);
! 401: /*
! 402: * Both windows need redrawing
! 403: */
! 404: wp->w_redr_type = NOT_VALID;
! 405: wp->w_redr_status = TRUE;
! 406: curwin->w_redr_type = NOT_VALID;
! 407: curwin->w_redr_status = TRUE;
! 408: /*
! 409: * Cursor is put in middle of window in both windows
! 410: */
! 411: if (wp->w_height < curwin->w_height) /* use smallest of two heights */
! 412: h = wp->w_height;
! 413: else
! 414: h = curwin->w_height;
! 415: h >>= 1;
! 416: for (lnum = wp->w_cursor.lnum; lnum > 1; --lnum)
! 417: {
! 418: h -= plines(lnum);
! 419: if (h <= 0)
! 420: break;
! 421: }
! 422: wp->w_topline = lnum;
! 423: curwin->w_topline = lnum;
! 424: if (need_status)
! 425: {
! 426: msg_pos((int)Rows - 1, sc_col);
! 427: msg_clr_eos(); /* Old command/ruler may still be there -- webb */
! 428: comp_col();
! 429: msg_pos((int)Rows - 1, 0); /* put position back at start of line */
! 430: }
! 431: /*
! 432: * make the new window the current window and redraw
! 433: */
! 434: if (do_equal)
! 435: win_equal(wp, FALSE);
! 436: win_enter(wp, FALSE);
! 437:
! 438: if (redraw)
! 439: updateScreen(NOT_VALID);
! 440:
! 441: return OK;
! 442: }
! 443:
! 444: /*
! 445: * Return the number of windows.
! 446: */
! 447: int
! 448: win_count()
! 449: {
! 450: WIN *wp;
! 451: int count = 0;
! 452:
! 453: for (wp = firstwin; wp != NULL; wp = wp->w_next)
! 454: ++count;
! 455: return count;
! 456: }
! 457:
! 458: /*
! 459: * Make 'count' windows on the screen.
! 460: * Return actual number of windows on the screen.
! 461: * Must be called when there is just one window, filling the whole screen
! 462: * (excluding the command line).
! 463: */
! 464: int
! 465: make_windows(count)
! 466: int count;
! 467: {
! 468: int maxcount;
! 469: int todo;
! 470: int p_sb_save;
! 471:
! 472: /*
! 473: * Each window needs at least MIN_ROWS lines and a status line.
! 474: * Add 4 lines for one window, otherwise we may end up with all one-line
! 475: * windows. Use value of 'winheight' if it is set
! 476: */
! 477: maxcount = (curwin->w_height + curwin->w_status_height -
! 478: (p_wh ? (p_wh - 1) : 4)) / (MIN_ROWS + STATUS_HEIGHT);
! 479: if (maxcount < 2)
! 480: maxcount = 2;
! 481: if (count > maxcount)
! 482: count = maxcount;
! 483:
! 484: /*
! 485: * add status line now, otherwise first window will be too big
! 486: */
! 487: if ((p_ls == 2 || (count > 1 && p_ls == 1)) && curwin->w_status_height == 0)
! 488: {
! 489: curwin->w_status_height = STATUS_HEIGHT;
! 490: win_new_height(curwin, curwin->w_height - STATUS_HEIGHT);
! 491: }
! 492:
! 493: /*
! 494: * set 'splitbelow' off for a moment, don't want that now
! 495: */
! 496: p_sb_save = p_sb;
! 497: p_sb = FALSE;
! 498: /* todo is number of windows left to create */
! 499: for (todo = count - 1; todo > 0; --todo)
! 500: if (win_split(curwin->w_height - (curwin->w_height - todo
! 501: * STATUS_HEIGHT) / (todo + 1) - STATUS_HEIGHT, FALSE) == FAIL)
! 502: break;
! 503: p_sb = p_sb_save;
! 504:
! 505: /* return actual number of windows */
! 506: return (count - todo);
! 507: }
! 508:
! 509: /*
! 510: * Exchange current and next window
! 511: */
! 512: static void
! 513: win_exchange(Prenum)
! 514: long Prenum;
! 515: {
! 516: WIN *wp;
! 517: WIN *wp2;
! 518: int temp;
! 519:
! 520: if (lastwin == firstwin) /* just one window */
! 521: {
! 522: beep_flush();
! 523: return;
! 524: }
! 525:
! 526: /*
! 527: * find window to exchange with
! 528: */
! 529: if (Prenum)
! 530: {
! 531: wp = firstwin;
! 532: while (wp != NULL && --Prenum > 0)
! 533: wp = wp->w_next;
! 534: }
! 535: else if (curwin->w_next != NULL) /* Swap with next */
! 536: wp = curwin->w_next;
! 537: else /* Swap last window with previous */
! 538: wp = curwin->w_prev;
! 539:
! 540: if (wp == curwin || wp == NULL)
! 541: return;
! 542:
! 543: /*
! 544: * 1. remove curwin from the list. Remember after which window it was in wp2
! 545: * 2. insert curwin before wp in the list
! 546: * if wp != wp2
! 547: * 3. remove wp from the list
! 548: * 4. insert wp after wp2
! 549: * 5. exchange the status line height
! 550: */
! 551: wp2 = curwin->w_prev;
! 552: win_remove(curwin);
! 553: win_append(wp->w_prev, curwin);
! 554: if (wp != wp2)
! 555: {
! 556: win_remove(wp);
! 557: win_append(wp2, wp);
! 558: }
! 559: temp = curwin->w_status_height;
! 560: curwin->w_status_height = wp->w_status_height;
! 561: wp->w_status_height = temp;
! 562:
! 563: win_comp_pos(); /* recompute window positions */
! 564:
! 565: win_enter(wp, TRUE);
! 566: cursupdate();
! 567: updateScreen(CLEAR);
! 568:
! 569: #ifdef USE_GUI
! 570: if (gui.in_use)
! 571: {
! 572: if (gui.which_scrollbars[SB_LEFT])
! 573: gui_mch_reorder_scrollbars(SB_LEFT);
! 574: if (gui.which_scrollbars[SB_RIGHT])
! 575: gui_mch_reorder_scrollbars(SB_RIGHT);
! 576: }
! 577: #endif
! 578: }
! 579:
! 580: /*
! 581: * rotate windows: if upwards TRUE the second window becomes the first one
! 582: * if upwards FALSE the first window becomes the second one
! 583: */
! 584: static void
! 585: win_rotate(upwards, count)
! 586: int upwards;
! 587: int count;
! 588: {
! 589: WIN *wp;
! 590: int height;
! 591:
! 592: if (firstwin == lastwin) /* nothing to do */
! 593: {
! 594: beep_flush();
! 595: return;
! 596: }
! 597: while (count--)
! 598: {
! 599: if (upwards) /* first window becomes last window */
! 600: {
! 601: wp = firstwin;
! 602: win_remove(wp);
! 603: win_append(lastwin, wp);
! 604: wp = lastwin->w_prev; /* previously last window */
! 605: }
! 606: else /* last window becomes first window */
! 607: {
! 608: wp = lastwin;
! 609: win_remove(lastwin);
! 610: win_append(NULL, wp);
! 611: wp = firstwin; /* previously last window */
! 612: }
! 613: /* exchange status height of old and new last window */
! 614: height = lastwin->w_status_height;
! 615: lastwin->w_status_height = wp->w_status_height;
! 616: wp->w_status_height = height;
! 617:
! 618: /* recompute w_winpos for all windows */
! 619: (void) win_comp_pos();
! 620: }
! 621:
! 622: cursupdate();
! 623: updateScreen(CLEAR);
! 624:
! 625: #ifdef USE_GUI
! 626: if (gui.in_use)
! 627: {
! 628: if (gui.which_scrollbars[SB_LEFT])
! 629: gui_mch_reorder_scrollbars(SB_LEFT);
! 630: if (gui.which_scrollbars[SB_RIGHT])
! 631: gui_mch_reorder_scrollbars(SB_RIGHT);
! 632: }
! 633: #endif
! 634: }
! 635:
! 636: /*
! 637: * Make all windows the same height.
! 638: * 'next_curwin' will soon be the current window, make sure it has enough
! 639: * rows.
! 640: */
! 641: void
! 642: win_equal(next_curwin, redraw)
! 643: WIN *next_curwin; /* pointer to current window to be */
! 644: int redraw;
! 645: {
! 646: int total;
! 647: int less;
! 648: int wincount;
! 649: int winpos;
! 650: int temp;
! 651: WIN *wp;
! 652: int new_height;
! 653:
! 654: /*
! 655: * count the number of lines available
! 656: */
! 657: total = 0;
! 658: wincount = 0;
! 659: for (wp = firstwin; wp; wp = wp->w_next)
! 660: {
! 661: total += wp->w_height - MIN_ROWS;
! 662: wincount++;
! 663: }
! 664:
! 665: /*
! 666: * If next_curwin given and 'winheight' set, make next_curwin p_wh lines.
! 667: */
! 668: less = 0;
! 669: if (next_curwin != NULL)
! 670: {
! 671: if (p_wh)
! 672: {
! 673: if (p_wh - MIN_ROWS > total) /* all lines go to current window */
! 674: less = total;
! 675: else
! 676: {
! 677: less = p_wh - MIN_ROWS - total / wincount;
! 678: if (less < 0)
! 679: less = 0;
! 680: }
! 681: }
! 682: }
! 683:
! 684: /*
! 685: * spread the available lines over the windows
! 686: */
! 687: winpos = 0;
! 688: for (wp = firstwin; wp != NULL; wp = wp->w_next)
! 689: {
! 690: if (wp == next_curwin && less)
! 691: {
! 692: less = 0;
! 693: temp = p_wh - MIN_ROWS;
! 694: if (temp > total)
! 695: temp = total;
! 696: }
! 697: else
! 698: temp = (total - less + (wincount >> 1)) / wincount;
! 699: new_height = MIN_ROWS + temp;
! 700: if (wp->w_winpos != winpos || wp->w_height != new_height)
! 701: {
! 702: wp->w_redr_type = NOT_VALID;
! 703: wp->w_redr_status = TRUE;
! 704: }
! 705: wp->w_winpos = winpos;
! 706: win_new_height(wp, new_height);
! 707: total -= temp;
! 708: --wincount;
! 709: winpos += wp->w_height + wp->w_status_height;
! 710: }
! 711: if (redraw)
! 712: {
! 713: cursupdate();
! 714: updateScreen(CLEAR);
! 715: }
! 716: }
! 717:
! 718: /*
! 719: * close all windows for buffer 'buf'
! 720: */
! 721: void
! 722: close_windows(buf)
! 723: BUF *buf;
! 724: {
! 725: WIN *win;
! 726:
! 727: ++RedrawingDisabled;
! 728: for (win = firstwin; win != NULL && lastwin != firstwin; )
! 729: {
! 730: if (win->w_buffer == buf)
! 731: {
! 732: close_window(win, FALSE);
! 733: win = firstwin; /* go back to the start */
! 734: }
! 735: else
! 736: win = win->w_next;
! 737: }
! 738: --RedrawingDisabled;
! 739: }
! 740:
! 741: /*
! 742: * close window "win"
! 743: * If "free_buf" is TRUE related buffer may be freed.
! 744: *
! 745: * called by :quit, :close, :xit, :wq and findtag()
! 746: */
! 747: void
! 748: close_window(win, free_buf)
! 749: WIN *win;
! 750: int free_buf;
! 751: {
! 752: WIN *wp;
! 753:
! 754: if (lastwin == firstwin)
! 755: {
! 756: EMSG("Cannot close last window");
! 757: return;
! 758: }
! 759:
! 760: /*
! 761: * Remove the window.
! 762: * if 'splitbelow' the free space goes to the window above it.
! 763: * if 'nosplitbelow' the free space goes to the window below it.
! 764: * This makes opening a window and closing it immediately keep the same window
! 765: * layout.
! 766: */
! 767: /* freed space goes to next window */
! 768: if ((!p_sb && win->w_next != NULL) || win->w_prev == NULL)
! 769: {
! 770: wp = win->w_next;
! 771: wp->w_winpos = win->w_winpos;
! 772: }
! 773: else /* freed space goes to previous window */
! 774: wp = win->w_prev;
! 775: win_new_height(wp, wp->w_height + win->w_height + win->w_status_height);
! 776:
! 777: #ifdef AUTOCMD
! 778: if (win == curwin)
! 779: {
! 780: if (wp->w_buffer != curbuf)
! 781: apply_autocmds(EVENT_BUFLEAVE, NULL, NULL);
! 782: apply_autocmds(EVENT_WINLEAVE, NULL, NULL);
! 783: }
! 784: #endif
! 785:
! 786: /*
! 787: * Close the link to the buffer.
! 788: */
! 789: close_buffer(win, win->w_buffer, free_buf, FALSE);
! 790:
! 791: win_free(win);
! 792: if (win == curwin)
! 793: curwin = NULL;
! 794: if (p_ea)
! 795: win_equal(wp, FALSE);
! 796: if (curwin == NULL)
! 797: win_enter(wp, FALSE);
! 798: /*
! 799: * if last window has status line now and we don't want one,
! 800: * remove the status line
! 801: */
! 802: if (lastwin->w_status_height &&
! 803: (p_ls == 0 || (p_ls == 1 && firstwin == lastwin)))
! 804: {
! 805: win_new_height(lastwin, lastwin->w_height + lastwin->w_status_height);
! 806: lastwin->w_status_height = 0;
! 807: comp_col();
! 808: }
! 809:
! 810: updateScreen(NOT_VALID);
! 811: if (RedrawingDisabled)
! 812: comp_Botline(wp); /* need to do this before cursupdate() */
! 813: }
! 814:
! 815: /*
! 816: * close all windows except current one
! 817: * buffers in the windows become hidden
! 818: *
! 819: * called by :only and do_arg_all();
! 820: */
! 821: void
! 822: close_others(message)
! 823: int message;
! 824: {
! 825: WIN *wp;
! 826: WIN *nextwp;
! 827:
! 828: if (lastwin == firstwin)
! 829: {
! 830: if (message
! 831: #ifdef AUTOCMD
! 832: && !autocmd_busy
! 833: #endif
! 834: )
! 835: MSG("Already only one window");
! 836: return;
! 837: }
! 838:
! 839: for (wp = firstwin; wp != NULL; wp = nextwp)
! 840: {
! 841: nextwp = wp->w_next;
! 842: if (wp == curwin) /* don't close current window */
! 843: continue;
! 844: /*
! 845: * Close the link to the buffer.
! 846: */
! 847: close_buffer(wp, wp->w_buffer, FALSE, FALSE);
! 848:
! 849: /*
! 850: * Remove the window. All lines go to current window.
! 851: */
! 852: win_new_height(curwin,
! 853: curwin->w_height + wp->w_height + wp->w_status_height);
! 854: win_free(wp);
! 855: }
! 856:
! 857: /*
! 858: * If current window has status line and we don't want one,
! 859: * remove the status line.
! 860: */
! 861: if (curwin->w_status_height && p_ls != 2)
! 862: {
! 863: win_new_height(curwin, curwin->w_height + curwin->w_status_height);
! 864: curwin->w_status_height = 0;
! 865: }
! 866: curwin->w_winpos = 0; /* put current window at top of the screen */
! 867: if (message)
! 868: updateScreen(NOT_VALID);
! 869: }
! 870:
! 871: /*
! 872: * init the cursor in the window
! 873: *
! 874: * called when a new file is being edited
! 875: */
! 876: void
! 877: win_init(wp)
! 878: WIN *wp;
! 879: {
! 880: wp->w_redr_type = NOT_VALID;
! 881: wp->w_cursor.lnum = 1;
! 882: wp->w_curswant = wp->w_cursor.col = 0;
! 883: wp->w_pcmark.lnum = 1; /* pcmark not cleared but set to line 1 */
! 884: wp->w_pcmark.col = 0;
! 885: wp->w_prev_pcmark.lnum = 0;
! 886: wp->w_prev_pcmark.col = 0;
! 887: wp->w_topline = 1;
! 888: wp->w_botline = 2;
! 889: }
! 890:
! 891: /*
! 892: * make window wp the current window
! 893: */
! 894: void
! 895: win_enter(wp, undo_sync)
! 896: WIN *wp;
! 897: int undo_sync;
! 898: {
! 899: #ifdef AUTOCMD
! 900: int other_buffer = FALSE;
! 901: #endif
! 902:
! 903: if (wp == curwin) /* nothing to do */
! 904: return;
! 905:
! 906: #ifdef AUTOCMD
! 907: if (curwin != NULL)
! 908: {
! 909: if (wp->w_buffer != curbuf)
! 910: {
! 911: apply_autocmds(EVENT_BUFLEAVE, NULL, NULL);
! 912: other_buffer = TRUE;
! 913: }
! 914: apply_autocmds(EVENT_WINLEAVE, NULL, NULL);
! 915: }
! 916: #endif
! 917:
! 918: /* sync undo before leaving the current buffer */
! 919: if (undo_sync && curbuf != wp->w_buffer)
! 920: u_sync();
! 921: /* may have to copy the buffer options when 'cpo' contains 'S' */
! 922: if (wp->w_buffer != curbuf)
! 923: buf_copy_options(curbuf, wp->w_buffer, TRUE);
! 924: if (curwin != NULL)
! 925: prevwin = curwin; /* remember for CTRL-W p */
! 926: curwin = wp;
! 927: curbuf = wp->w_buffer;
! 928:
! 929: #ifdef AUTOCMD
! 930: apply_autocmds(EVENT_WINENTER, NULL, NULL);
! 931: if (other_buffer)
! 932: apply_autocmds(EVENT_BUFENTER, NULL, NULL);
! 933: #endif
! 934:
! 935: maketitle();
! 936: /* set window height to desired minimal value */
! 937: if (p_wh && curwin->w_height < p_wh)
! 938: win_setheight((int)p_wh);
! 939: #ifdef USE_MOUSE
! 940: setmouse(); /* in case jumped to/from help buffer */
! 941: #endif
! 942: }
! 943:
! 944: /*
! 945: * allocate a window structure and link it in the window list
! 946: */
! 947: WIN *
! 948: win_alloc(after)
! 949: WIN *after;
! 950: {
! 951: WIN *newwin;
! 952:
! 953: /*
! 954: * allocate window structure and linesizes arrays
! 955: */
! 956: newwin = (WIN *)alloc((unsigned)sizeof(WIN));
! 957: if (newwin)
! 958: {
! 959: /*
! 960: * most stucture members have to be zero
! 961: */
! 962: (void)vim_memset(newwin, 0, sizeof(WIN));
! 963: /*
! 964: * link the window in the window list
! 965: */
! 966: win_append(after, newwin);
! 967:
! 968: win_alloc_lsize(newwin);
! 969:
! 970: /* position the display and the cursor at the top of the file. */
! 971: newwin->w_topline = 1;
! 972: newwin->w_botline = 2;
! 973: newwin->w_cursor.lnum = 1;
! 974:
! 975: #ifdef USE_GUI
! 976: /* Let the GUI know this is a new scrollbar */
! 977: newwin->w_scrollbar.height = 0;
! 978: #endif /* USE_GUI */
! 979: }
! 980: return newwin;
! 981: }
! 982:
! 983: /*
! 984: * remove window 'wp' from the window list and free the structure
! 985: */
! 986: void
! 987: win_free(wp)
! 988: WIN *wp;
! 989: {
! 990: int i;
! 991:
! 992: if (prevwin == wp)
! 993: prevwin = NULL;
! 994: win_free_lsize(wp);
! 995:
! 996: for (i = 0; i < wp->w_tagstacklen; ++i)
! 997: free(wp->w_tagstack[i].tagname);
! 998:
! 999: #ifdef USE_GUI
! 1000: if (gui.in_use)
! 1001: gui_mch_destroy_scrollbar(wp);
! 1002: #endif /* USE_GUI */
! 1003:
! 1004: win_remove(wp);
! 1005: vim_free(wp);
! 1006: }
! 1007:
! 1008: static void
! 1009: win_append(after, wp)
! 1010: WIN *after, *wp;
! 1011: {
! 1012: WIN *before;
! 1013:
! 1014: if (after == NULL) /* after NULL is in front of the first */
! 1015: before = firstwin;
! 1016: else
! 1017: before = after->w_next;
! 1018:
! 1019: wp->w_next = before;
! 1020: wp->w_prev = after;
! 1021: if (after == NULL)
! 1022: firstwin = wp;
! 1023: else
! 1024: after->w_next = wp;
! 1025: if (before == NULL)
! 1026: lastwin = wp;
! 1027: else
! 1028: before->w_prev = wp;
! 1029: }
! 1030:
! 1031: /*
! 1032: * remove window from the window list
! 1033: */
! 1034: static void
! 1035: win_remove(wp)
! 1036: WIN *wp;
! 1037: {
! 1038: if (wp->w_prev)
! 1039: wp->w_prev->w_next = wp->w_next;
! 1040: else
! 1041: firstwin = wp->w_next;
! 1042: if (wp->w_next)
! 1043: wp->w_next->w_prev = wp->w_prev;
! 1044: else
! 1045: lastwin = wp->w_prev;
! 1046: }
! 1047:
! 1048: /*
! 1049: * allocate lsize arrays for a window
! 1050: * return FAIL for failure, OK for success
! 1051: */
! 1052: int
! 1053: win_alloc_lsize(wp)
! 1054: WIN *wp;
! 1055: {
! 1056: wp->w_lsize_valid = 0;
! 1057: wp->w_lsize_lnum = (linenr_t *) malloc((size_t) (Rows * sizeof(linenr_t)));
! 1058: wp->w_lsize = (char_u *)malloc((size_t) Rows);
! 1059: if (wp->w_lsize_lnum == NULL || wp->w_lsize == NULL)
! 1060: {
! 1061: win_free_lsize(wp); /* one of the two may have worked */
! 1062: wp->w_lsize_lnum = NULL;
! 1063: wp->w_lsize = NULL;
! 1064: return FAIL;
! 1065: }
! 1066: return OK;
! 1067: }
! 1068:
! 1069: /*
! 1070: * free lsize arrays for a window
! 1071: */
! 1072: void
! 1073: win_free_lsize(wp)
! 1074: WIN *wp;
! 1075: {
! 1076: vim_free(wp->w_lsize_lnum);
! 1077: vim_free(wp->w_lsize);
! 1078: }
! 1079:
! 1080: /*
! 1081: * call this fuction whenever Rows changes value
! 1082: */
! 1083: void
! 1084: screen_new_rows()
! 1085: {
! 1086: WIN *wp;
! 1087: int extra_lines;
! 1088:
! 1089: if (firstwin == NULL) /* not initialized yet */
! 1090: return;
! 1091: /*
! 1092: * the number of extra lines is the difference between the position where
! 1093: * the command line should be and where it is now
! 1094: */
! 1095: compute_cmdrow();
! 1096: extra_lines = Rows - p_ch - cmdline_row;
! 1097: if (extra_lines < 0) /* reduce windows height */
! 1098: {
! 1099: for (wp = lastwin; wp; wp = wp->w_prev)
! 1100: {
! 1101: if (wp->w_height - MIN_ROWS < -extra_lines)
! 1102: {
! 1103: extra_lines += wp->w_height - MIN_ROWS;
! 1104: win_new_height(wp, MIN_ROWS);
! 1105: }
! 1106: else
! 1107: {
! 1108: win_new_height(wp, wp->w_height + extra_lines);
! 1109: break;
! 1110: }
! 1111: }
! 1112: (void)win_comp_pos(); /* compute w_winpos */
! 1113: }
! 1114: else if (extra_lines > 0) /* increase height of last window */
! 1115: win_new_height(lastwin, lastwin->w_height + extra_lines);
! 1116:
! 1117: compute_cmdrow();
! 1118:
! 1119: if (p_ea)
! 1120: win_equal(curwin, FALSE);
! 1121: }
! 1122:
! 1123: /*
! 1124: * update the w_winpos field for all windows
! 1125: * returns the row just after the last window
! 1126: */
! 1127: static int
! 1128: win_comp_pos()
! 1129: {
! 1130: WIN *wp;
! 1131: int row;
! 1132:
! 1133: row = 0;
! 1134: for (wp = firstwin; wp != NULL; wp = wp->w_next)
! 1135: {
! 1136: if (wp->w_winpos != row) /* if position changes, redraw */
! 1137: {
! 1138: wp->w_winpos = row;
! 1139: wp->w_redr_type = NOT_VALID;
! 1140: wp->w_redr_status = TRUE;
! 1141: }
! 1142: row += wp->w_height + wp->w_status_height;
! 1143: }
! 1144: return row;
! 1145: }
! 1146:
! 1147: /*
! 1148: * set current window height
! 1149: */
! 1150: void
! 1151: win_setheight(height)
! 1152: int height;
! 1153: {
! 1154: WIN *wp;
! 1155: int room; /* total number of lines available */
! 1156: int take; /* number of lines taken from other windows */
! 1157: int room_cmdline; /* lines available from cmdline */
! 1158: int row;
! 1159: int run;
! 1160:
! 1161: if (height < MIN_ROWS) /* need at least some lines */
! 1162: height = MIN_ROWS;
! 1163: /*
! 1164: * compute the room we have from all the windows
! 1165: */
! 1166: room = MIN_ROWS; /* count the MIN_ROWS for the current window */
! 1167: for (wp = firstwin; wp != NULL; wp = wp->w_next)
! 1168: room += wp->w_height - MIN_ROWS;
! 1169: /*
! 1170: * compute the room available from the command line
! 1171: */
! 1172: room_cmdline = Rows - p_ch - cmdline_row;
! 1173: /*
! 1174: * limit new height to the room available
! 1175: */
! 1176: if (height > room + room_cmdline) /* can't make it that large */
! 1177: height = room + room_cmdline; /* use all available room */
! 1178: /*
! 1179: * compute the number of lines we will take from the windows (can be negative)
! 1180: */
! 1181: take = height - curwin->w_height;
! 1182: if (take == 0) /* no change, nothing to do */
! 1183: return;
! 1184:
! 1185: if (take > 0)
! 1186: {
! 1187: take -= room_cmdline; /* use lines from cmdline first */
! 1188: if (take < 0)
! 1189: take = 0;
! 1190: }
! 1191: /*
! 1192: * set the current window to the new height
! 1193: */
! 1194: win_new_height(curwin, height);
! 1195:
! 1196: /*
! 1197: * First take lines from the windows below the current window.
! 1198: * If that is not enough, takes lines from windows above the current window.
! 1199: */
! 1200: for (run = 0; run < 2; ++run)
! 1201: {
! 1202: if (run == 0)
! 1203: wp = curwin->w_next; /* 1st run: start with next window */
! 1204: else
! 1205: wp = curwin->w_prev; /* 2nd run: start with prev window */
! 1206: while (wp != NULL && take != 0)
! 1207: {
! 1208: if (wp->w_height - take < MIN_ROWS)
! 1209: {
! 1210: take -= wp->w_height - MIN_ROWS;
! 1211: win_new_height(wp, MIN_ROWS);
! 1212: }
! 1213: else
! 1214: {
! 1215: win_new_height(wp, wp->w_height - take);
! 1216: take = 0;
! 1217: }
! 1218: if (run == 0)
! 1219: wp = wp->w_next;
! 1220: else
! 1221: wp = wp->w_prev;
! 1222: }
! 1223: }
! 1224:
! 1225: /* recompute the window positions */
! 1226: row = win_comp_pos();
! 1227:
! 1228: /*
! 1229: * If there is extra space created between the last window and the command line,
! 1230: * clear it.
! 1231: */
! 1232: screen_fill(row, cmdline_row, 0, (int)Columns, ' ', ' ');
! 1233: cmdline_row = row;
! 1234:
! 1235: updateScreen(NOT_VALID);
! 1236: }
! 1237:
! 1238: #ifdef USE_MOUSE
! 1239: void
! 1240: win_drag_status_line(offset)
! 1241: int offset;
! 1242: {
! 1243: WIN *wp;
! 1244: int room;
! 1245: int row;
! 1246: int up; /* if TRUE, drag status line up, otherwise down */
! 1247:
! 1248: if (offset < 0)
! 1249: {
! 1250: up = TRUE;
! 1251: offset = -offset;
! 1252: }
! 1253: else
! 1254: up = FALSE;
! 1255:
! 1256: if (up) /* drag up */
! 1257: {
! 1258: room = 0;
! 1259: for (wp = curwin; wp != NULL && room < offset; wp = wp->w_prev)
! 1260: room += wp->w_height - MIN_ROWS;
! 1261: wp = curwin->w_next; /* put wp at window that grows */
! 1262: }
! 1263: else /* drag down */
! 1264: {
! 1265: /*
! 1266: * Only dragging the last status line can reduce p_ch.
! 1267: */
! 1268: room = Rows - cmdline_row;
! 1269: if (curwin->w_next == NULL)
! 1270: room -= 1;
! 1271: else
! 1272: room -= p_ch;
! 1273: for (wp = curwin->w_next; wp != NULL && room < offset; wp = wp->w_next)
! 1274: room += wp->w_height - MIN_ROWS;
! 1275: wp = curwin; /* put wp at window that grows */
! 1276: }
! 1277:
! 1278: if (room < offset) /* Not enough room */
! 1279: offset = room; /* Move as far as we can */
! 1280: if (offset <= 0)
! 1281: return;
! 1282:
! 1283: if (wp != NULL) /* grow window wp by offset lines */
! 1284: win_new_height(wp, wp->w_height + offset);
! 1285:
! 1286: if (up)
! 1287: wp = curwin; /* current window gets smaller */
! 1288: else
! 1289: wp = curwin->w_next; /* next window gets smaller */
! 1290:
! 1291: while (wp != NULL && offset > 0)
! 1292: {
! 1293: if (wp->w_height - offset < MIN_ROWS)
! 1294: {
! 1295: offset -= wp->w_height - MIN_ROWS;
! 1296: win_new_height(wp, MIN_ROWS);
! 1297: }
! 1298: else
! 1299: {
! 1300: win_new_height(wp, wp->w_height - offset);
! 1301: offset = 0;
! 1302: }
! 1303: if (up)
! 1304: wp = wp->w_prev;
! 1305: else
! 1306: wp = wp->w_next;
! 1307: }
! 1308: row = win_comp_pos();
! 1309: screen_fill(row, cmdline_row, 0, (int)Columns, ' ', ' ');
! 1310: cmdline_row = row;
! 1311: p_ch = Rows - cmdline_row;
! 1312: updateScreen(NOT_VALID);
! 1313: showmode();
! 1314: }
! 1315: #endif /* USE_MOUSE */
! 1316:
! 1317: /*
! 1318: * Set new window height.
! 1319: */
! 1320: static void
! 1321: win_new_height(wp, height)
! 1322: WIN *wp;
! 1323: int height;
! 1324: {
! 1325: /* should adjust topline to keep cursor at same relative postition */
! 1326:
! 1327: wp->w_height = height;
! 1328: win_comp_scroll(wp);
! 1329: wp->w_redr_type = NOT_VALID;
! 1330: wp->w_redr_status = TRUE;
! 1331: }
! 1332:
! 1333: void
! 1334: win_comp_scroll(wp)
! 1335: WIN *wp;
! 1336: {
! 1337: wp->w_p_scroll = (wp->w_height >> 1);
! 1338: if (wp->w_p_scroll == 0)
! 1339: wp->w_p_scroll = 1;
! 1340: }
! 1341:
! 1342: /*
! 1343: * command_height: called whenever p_ch has been changed
! 1344: */
! 1345: void
! 1346: command_height()
! 1347: {
! 1348: int current;
! 1349:
! 1350: current = Rows - cmdline_row;
! 1351: if (p_ch > current) /* p_ch got bigger */
! 1352: {
! 1353: if (lastwin->w_height - (p_ch - current) < MIN_ROWS)
! 1354: {
! 1355: emsg(e_noroom);
! 1356: p_ch = lastwin->w_height - MIN_ROWS + current;
! 1357: }
! 1358: /* clear the lines added to cmdline */
! 1359: screen_fill((int)(Rows - p_ch), (int)Rows, 0, (int)Columns, ' ', ' ');
! 1360: }
! 1361: win_new_height(lastwin, lastwin->w_height + current - (int)p_ch);
! 1362: cmdline_row = Rows - p_ch;
! 1363: redraw_cmdline = TRUE;
! 1364: }
! 1365:
! 1366: void
! 1367: last_status()
! 1368: {
! 1369: if (lastwin->w_status_height)
! 1370: {
! 1371: /* remove status line */
! 1372: if (p_ls == 0 || (p_ls == 1 && firstwin == lastwin))
! 1373: {
! 1374: win_new_height(lastwin, lastwin->w_height + 1);
! 1375: lastwin->w_status_height = 0;
! 1376: }
! 1377: }
! 1378: else
! 1379: {
! 1380: /* add status line */
! 1381: if (p_ls == 2 || (p_ls == 1 && firstwin != lastwin))
! 1382: {
! 1383: if (lastwin->w_height <= MIN_ROWS) /* can't do it */
! 1384: emsg(e_noroom);
! 1385: else
! 1386: {
! 1387: win_new_height(lastwin, lastwin->w_height - 1);
! 1388: lastwin->w_status_height = 1;
! 1389: }
! 1390: }
! 1391: }
! 1392: }
! 1393:
! 1394: /*
! 1395: * file_name_at_cursor()
! 1396: *
! 1397: * Return the name of the file under (or to the right of) the cursor. The
! 1398: * p_path variable is searched if the file name does not start with '/'.
! 1399: * The string returned has been alloc'ed and should be freed by the caller.
! 1400: * NULL is returned if the file name or file is not found.
! 1401: */
! 1402: char_u *
! 1403: file_name_at_cursor(options)
! 1404: int options;
! 1405: {
! 1406: return get_file_name_in_path(ml_get_curline(),
! 1407: curwin->w_cursor.col, options);
! 1408: }
! 1409: /* options:
! 1410: * FNAME_MESS give error messages
! 1411: * FNAME_EXP expand to path
! 1412: * FNAME_HYP check for hypertext link
! 1413: */
! 1414: char_u *
! 1415: get_file_name_in_path(ptr, col, options)
! 1416: char_u *ptr;
! 1417: int col;
! 1418: int options;
! 1419: {
! 1420: char_u *dir;
! 1421: char_u *file_name;
! 1422: char_u save_char;
! 1423: char_u *curr_path = NULL;
! 1424: int curr_path_len;
! 1425: int len;
! 1426:
! 1427: /* search forward for what could be the start of a file name */
! 1428: while (ptr[col] != NUL && !isfilechar(ptr[col]))
! 1429: ++col;
! 1430: if (ptr[col] == NUL) /* nothing found */
! 1431: {
! 1432: if (options & FNAME_MESS)
! 1433: EMSG("No file name under cursor");
! 1434: return NULL;
! 1435: }
! 1436:
! 1437: /* search backward for char that cannot be in a file name */
! 1438: while (col >= 0 && isfilechar(ptr[col]))
! 1439: --col;
! 1440: ptr += col + 1;
! 1441: col = 0;
! 1442:
! 1443: /* search forward for a char that cannot be in a file name */
! 1444: while (isfilechar(ptr[col]))
! 1445: ++col;
! 1446:
! 1447: if (options & FNAME_HYP)
! 1448: {
! 1449: /* For hypertext links, ignore the name of the machine.
! 1450: * Such a link looks like "type://machine/path". Only "/path" is used.
! 1451: * First search for the string "://", then for the extra '/'
! 1452: */
! 1453: if ((file_name = vim_strchr(ptr, ':')) != NULL &&
! 1454: STRNCMP(file_name, "://", (size_t)3) == 0 &&
! 1455: (file_name = vim_strchr(file_name + 3, '/')) != NULL &&
! 1456: file_name < ptr + col)
! 1457: {
! 1458: col -= file_name - ptr;
! 1459: ptr = file_name;
! 1460: if (ptr[1] == '~') /* skip '/' for /~user/path */
! 1461: {
! 1462: ++ptr;
! 1463: --col;
! 1464: }
! 1465: }
! 1466: }
! 1467:
! 1468: if (!(options & FNAME_EXP))
! 1469: return strnsave(ptr, col);
! 1470:
! 1471: /* copy file name into NameBuff, expanding environment variables */
! 1472: save_char = ptr[col];
! 1473: ptr[col] = NUL;
! 1474: expand_env(ptr, NameBuff, MAXPATHL);
! 1475: ptr[col] = save_char;
! 1476:
! 1477: if (isFullName(NameBuff)) /* absolute path */
! 1478: {
! 1479: if ((file_name = strsave(NameBuff)) == NULL)
! 1480: return NULL;
! 1481: if (getperm(file_name) >= 0)
! 1482: return file_name;
! 1483: if (options & FNAME_MESS)
! 1484: {
! 1485: sprintf((char *)IObuff, "Can't find file `%s'", NameBuff);
! 1486: emsg(IObuff);
! 1487: }
! 1488: }
! 1489: else /* relative path, use 'path' option */
! 1490: {
! 1491: if (curbuf->b_xfilename != NULL)
! 1492: {
! 1493: curr_path = curbuf->b_xfilename;
! 1494: ptr = gettail(curr_path);
! 1495: curr_path_len = ptr - curr_path;
! 1496: }
! 1497: else
! 1498: curr_path_len = 0;
! 1499: if ((file_name = alloc((int)(curr_path_len + STRLEN(p_path) +
! 1500: STRLEN(NameBuff) + 3))) == NULL)
! 1501: return NULL;
! 1502:
! 1503: for (dir = p_path; *dir;)
! 1504: {
! 1505: len = copy_option_part(&dir, file_name, 31000, " ,");
! 1506: /* len == 0 means: use current directory */
! 1507: if (len != 0)
! 1508: {
! 1509: /* Look for file relative to current file */
! 1510: if (file_name[0] == '.' && curr_path_len > 0)
! 1511: {
! 1512: if (len == 1) /* just a "." */
! 1513: len = 0;
! 1514: else /* "./path": move "path" */
! 1515: {
! 1516: len -= 2;
! 1517: vim_memmove(file_name + curr_path_len, file_name + 2,
! 1518: (size_t)len);
! 1519: }
! 1520: STRNCPY(file_name, curr_path, curr_path_len);
! 1521: len += curr_path_len;
! 1522: }
! 1523: if (!ispathsep(file_name[len - 1]))
! 1524: file_name[len++] = PATHSEP;
! 1525: }
! 1526: STRCPY(file_name + len, NameBuff);
! 1527: if (getperm(file_name) >= 0)
! 1528: return file_name;
! 1529: }
! 1530: if (options & FNAME_MESS)
! 1531: EMSG2("Can't find file \"%s\" in path", NameBuff);
! 1532: }
! 1533: vim_free(file_name); /* file doesn't exist */
! 1534: return NULL;
! 1535: }
! 1536:
! 1537: /*
! 1538: * Return the minimal number of rows that is needed on the screen to display
! 1539: * the current number of windows.
! 1540: */
! 1541: int
! 1542: min_rows()
! 1543: {
! 1544: WIN *wp;
! 1545: int total;
! 1546:
! 1547: if (firstwin == NULL) /* not initialized yet */
! 1548: return MIN_ROWS + 1; /* one window plus command line */
! 1549:
! 1550: total = p_ch; /* count the room for the status line */
! 1551: for (wp = firstwin; wp != NULL; wp = wp->w_next)
! 1552: total += MIN_ROWS + wp->w_status_height;
! 1553: return total;
! 1554: }
! 1555:
! 1556: /*
! 1557: * Return TRUE if there is only one window, not counting a help window, unless
! 1558: * it is the current window.
! 1559: */
! 1560: int
! 1561: only_one_window()
! 1562: {
! 1563: int count = 0;
! 1564: WIN *wp;
! 1565:
! 1566: for (wp = firstwin; wp != NULL; wp = wp->w_next)
! 1567: if (!wp->w_buffer->b_help || wp == curwin)
! 1568: ++count;
! 1569: return (count <= 1);
! 1570: }