diff options
Diffstat (limited to 'usr.bin/vim/buffer.c')
-rw-r--r-- | usr.bin/vim/buffer.c | 290 |
1 files changed, 224 insertions, 66 deletions
diff --git a/usr.bin/vim/buffer.c b/usr.bin/vim/buffer.c index a1e8124ce94..9940a1588cb 100644 --- a/usr.bin/vim/buffer.c +++ b/usr.bin/vim/buffer.c @@ -1,4 +1,4 @@ -/* $OpenBSD: buffer.c,v 1.1 1996/09/07 21:40:27 downsj Exp $ */ +/* $OpenBSD: buffer.c,v 1.2 1996/09/21 06:22:51 downsj Exp $ */ /* vi:set ts=4 sw=4: * * VIM - Vi IMproved by Bram Moolenaar @@ -31,11 +31,10 @@ #include "option.h" static void enter_buffer __ARGS((BUF *)); -static void free_buf_options __ARGS((BUF *)); static char_u *buflist_match __ARGS((regexp *prog, BUF *buf)); static void buflist_setlnum __ARGS((BUF *, linenr_t)); static linenr_t buflist_findlnum __ARGS((BUF *)); -static void append_arg_number __ARGS((char_u *, int)); +static int append_arg_number __ARGS((char_u *, int, int)); /* * Open current buffer, that is: open the memfile and read the file into memory @@ -45,6 +44,10 @@ static void append_arg_number __ARGS((char_u *, int)); open_buffer() { int retval = OK; +#ifdef AUTOCMD + BUF *old_curbuf; + BUF *new_curbuf; +#endif /* * The 'readonly' flag is only set when b_neverloaded is being reset. @@ -77,6 +80,11 @@ open_buffer() enter_buffer(curbuf); return FAIL; } +#ifdef AUTOCMD + /* The autocommands in readfile() may change the buffer, but only AFTER + * reading the file. */ + old_curbuf = curbuf; +#endif if (curbuf->b_filename != NULL) retval = readfile(curbuf->b_filename, curbuf->b_sfilename, (linenr_t)0, TRUE, (linenr_t)0, MAXLNUM, FALSE); @@ -105,14 +113,45 @@ open_buffer() if (retval != FAIL) { - do_modelines(); - curbuf->b_neverloaded = FALSE; +#ifdef AUTOCMD + /* + * The autocommands may have changed the current buffer. Apply the + * modelines to the correct buffer, if it still exists. + */ + if (buf_valid(old_curbuf)) + { + new_curbuf = curbuf; + curbuf = old_curbuf; + curwin->w_buffer = old_curbuf; +#endif + do_modelines(); + curbuf->b_neverloaded = FALSE; +#ifdef AUTOCMD + curbuf = new_curbuf; + curwin->w_buffer = new_curbuf; + } +#endif } return retval; } /* + * Return TRUE if "buf" points to a valid buffer (in the buffer list). + */ + int +buf_valid(buf) + BUF *buf; +{ + BUF *bp; + + for (bp = firstbuf; bp != NULL; bp = bp->b_next) + if (bp == buf) + return TRUE; + return FALSE; +} + +/* * Close the link to a buffer. If "free_buf" is TRUE free the buffer if it * becomes unreferenced. The caller should get a new buffer very soon! * if 'del_buf' is TRUE, remove the buffer from the buffer list. @@ -152,6 +191,7 @@ close_buffer(win, buf, free_buf, del_buf) else buf->b_next->b_prev = buf->b_prev; free_buf_options(buf); + vim_free(buf); } else buf_clear(buf); @@ -238,7 +278,7 @@ do_bufdel(command, arg, addr_count, start_bnr, end_bnr, forceit) if (bnr == curbuf->b_fnum) do_current = bnr; else if (do_buffer(command, DOBUF_FIRST, FORWARD, (int)bnr, - forceit) == OK) + forceit) == OK) ++deleted; /* @@ -267,7 +307,7 @@ do_bufdel(command, arg, addr_count, start_bnr, end_bnr, forceit) } } if (!got_int && do_current && do_buffer(command, DOBUF_FIRST, - FORWARD, do_current, forceit) == OK) + FORWARD, do_current, forceit) == OK) ++deleted; if (deleted == 0) @@ -398,18 +438,20 @@ do_buffer(action, start, dir, count, forceit) EMSG("Cannot unload last buffer"); return FAIL; } - /* Close any other windows on this buffer */ + + /* Close any other windows on this buffer, then make it empty. */ close_others(FALSE); buf = curbuf; setpcmark(); - retval = do_ecmd(0, NULL, NULL, NULL, FALSE, (linenr_t)1, FALSE); + retval = do_ecmd(0, NULL, NULL, NULL, (linenr_t)1, + forceit ? ECMD_FORCEIT : 0); + /* - * The do_ecmd() may create a new buffer, then we have to delete + * do_ecmd() may create a new buffer, then we have to delete * the old one. But do_ecmd() may have done that already, check - * if the buffer still exists (it will be the first or second in - * the buffer list). + * if the buffer still exists. */ - if (buf != curbuf && (buf == firstbuf || buf == firstbuf->b_next)) + if (buf != curbuf && buf_valid(buf)) close_buffer(NULL, buf, TRUE, TRUE); return retval; } @@ -427,41 +469,63 @@ do_buffer(action, start, dir, count, forceit) if (buf != curbuf) { close_windows(buf); - close_buffer(NULL, buf, TRUE, action == DOBUF_DEL); + if (buf_valid(buf)) + close_buffer(NULL, buf, TRUE, action == DOBUF_DEL); return OK; } /* * Deleting the current buffer: Need to find another buffer to go to. * There must be another, otherwise it would have been handled above. + * First try to find one that is loaded. */ - if (curbuf->b_next != NULL) - buf = curbuf->b_next; - else - buf = curbuf->b_prev; + for (buf = firstbuf; buf != NULL; buf = buf->b_next) + if (buf != curbuf && buf->b_ml.ml_mfp != NULL) + break; + if (buf == NULL) /* No loaded buffers, just take anyone */ + { + if (curbuf->b_next != NULL) + buf = curbuf->b_next; + else + buf = curbuf->b_prev; + } } /* * make buf current buffer */ - setpcmark(); if (action == DOBUF_SPLIT) /* split window first */ { if (win_split(0, FALSE) == FAIL) return FAIL; } + + /* go to current buffer - nothing to do */ + if (buf == curbuf) + return OK; + + setpcmark(); curwin->w_alt_fnum = curbuf->b_fnum; /* remember alternate file */ buflist_altlnum(); /* remember curpos.lnum */ + /* close_windows() or apply_autocmds() may change curbuf */ + delbuf = curbuf; + #ifdef AUTOCMD apply_autocmds(EVENT_BUFLEAVE, NULL, NULL); + if (buf_valid(delbuf)) #endif - delbuf = curbuf; /* close_windows() may change curbuf */ - if (action == DOBUF_UNLOAD || action == DOBUF_DEL) - close_windows(curbuf); - close_buffer(NULL, delbuf, action == DOBUF_UNLOAD || action == DOBUF_DEL, - action == DOBUF_DEL); - enter_buffer(buf); + { + if (action == DOBUF_UNLOAD || action == DOBUF_DEL) + close_windows(delbuf); + if (buf_valid(delbuf)) + close_buffer(NULL, delbuf, action == DOBUF_UNLOAD || + action == DOBUF_DEL, action == DOBUF_DEL); + } +#ifdef AUTOCMD + if (buf_valid(buf)) /* an autocommand may have deleted buf! */ +#endif + enter_buffer(buf); return OK; } @@ -473,7 +537,7 @@ do_buffer(action, start, dir, count, forceit) enter_buffer(buf) BUF *buf; { - buf_copy_options(curbuf, buf, TRUE); + buf_copy_options(curbuf, buf, TRUE, FALSE); curwin->w_buffer = buf; curbuf = buf; ++curbuf->b_nwindows; @@ -526,7 +590,7 @@ buflist_new(fname, sfname, lnum, use_curbuf) buflist_setlnum(buf, lnum); /* copy the options now, if 'cpo' doesn't have 's' and not done * already */ - buf_copy_options(curbuf, buf, FALSE); + buf_copy_options(curbuf, buf, FALSE, FALSE); return buf; } @@ -566,6 +630,7 @@ buflist_new(fname, sfname, lnum, use_curbuf) { vim_free(buf->b_winlnum); free_buf_options(buf); + vim_free(buf); } return NULL; } @@ -578,11 +643,6 @@ buflist_new(fname, sfname, lnum, use_curbuf) else { /* - * Copy the options from the current buffer. - */ - buf_copy_options(curbuf, buf, FALSE); - - /* * put new buffer at the end of the buffer list */ buf->b_next = NULL; @@ -610,6 +670,11 @@ buflist_new(fname, sfname, lnum, use_curbuf) buf->b_winlnum->wl_next = NULL; buf->b_winlnum->wl_prev = NULL; buf->b_winlnum->wl_win = curwin; + + /* + * Always copy the options from the current buffer. + */ + buf_copy_options(curbuf, buf, FALSE, TRUE); } if (did_cd) @@ -626,9 +691,9 @@ buflist_new(fname, sfname, lnum, use_curbuf) } /* - * Free the memory for a BUF structure and its options + * Free the memory for the options of a buffer. */ - static void + void free_buf_options(buf) BUF *buf; { @@ -642,7 +707,6 @@ free_buf_options(buf) #if defined(CINDENT) || defined(SMARTINDENT) free_string_option(buf->b_p_cinw); #endif - vim_free(buf); } /* @@ -654,10 +718,11 @@ free_buf_options(buf) * return FAIL for failure, OK for success */ int -buflist_getfile(n, lnum, options) +buflist_getfile(n, lnum, options, forceit) int n; linenr_t lnum; int options; + int forceit; { BUF *buf; @@ -679,7 +744,8 @@ buflist_getfile(n, lnum, options) if (lnum == 0) lnum = buflist_findlnum(buf); ++RedrawingDisabled; - if (getfile(buf->b_fnum, NULL, NULL, (options & GETF_SETMARK), lnum) <= 0) + if (getfile(buf->b_fnum, NULL, NULL, (options & GETF_SETMARK), + lnum, forceit) <= 0) { --RedrawingDisabled; return OK; @@ -1290,7 +1356,7 @@ fileinfo(fullname, shorthelp, dont_truncate) (int)curwin->w_cursor.col + 1, (int)curwin->w_virtcol + 1); } - append_arg_number(buffer, !shortmess(SHM_FILE)); + (void)append_arg_number(buffer, !shortmess(SHM_FILE), IOSIZE); if (dont_truncate) msg(buffer); @@ -1372,24 +1438,40 @@ maketitle() { char_u *t_name; char_u *i_name; + int maxlen; + int len; if (curbuf->b_filename == NULL) { - t_name = (char_u *)""; + t_name = (char_u *)"VIM -"; i_name = (char_u *)"No File"; } else { - home_replace(curbuf, curbuf->b_filename, IObuff, IOSIZE); - append_arg_number(IObuff, FALSE); + STRCPY(IObuff, "VIM - "); + home_replace(curbuf, curbuf->b_filename, IObuff + 6, IOSIZE - 6); + append_arg_number(IObuff, FALSE, IOSIZE); + if (p_titlelen > 0) + { + maxlen = p_titlelen * Columns / 100; + if (maxlen < 10) + maxlen = 10; + len = STRLEN(IObuff); + if (len > maxlen) + { + vim_memmove(IObuff + 6, IObuff + 6 + len - maxlen, + (size_t)maxlen - 5); + IObuff[5] = '<'; + } + } t_name = IObuff; i_name = gettail(curbuf->b_filename); /* use filename only for icon */ } vim_free(lasttitle); - if (p_title && (lasttitle = alloc((unsigned)(strsize(t_name) + 7))) != NULL) + if (p_title && (lasttitle = alloc((unsigned)(strsize(t_name) + 1))) != NULL) { - STRCPY(lasttitle, "VIM - "); + *lasttitle = NUL; while (*t_name) STRCAT(lasttitle, transchar(*t_name++)); } @@ -1410,26 +1492,33 @@ maketitle() } /* - * Append (file 2 of 8) to 'buf'. + * Append (file 2 of 8) to 'buf', if editing more than one file. + * Return TRUE if it was appended. */ - static void -append_arg_number(buf, add_file) + static int +append_arg_number(buf, add_file, maxlen) char_u *buf; - int add_file; /* Add "file" before the arg number */ + int add_file; /* Add "file" before the arg number */ + int maxlen; /* maximum nr of chars in buf */ { - if (arg_count <= 1) /* nothing to do */ - return; + char_u *p; + + if (arg_count <= 1) /* nothing to do */ + return FALSE; - buf += STRLEN(buf); /* go to the end of the buffer */ - *buf++ = ' '; - *buf++ = '('; + p = buf + STRLEN(buf); /* go to the end of the buffer */ + if (p - buf + 35 >= maxlen) /* getting too long */ + return FALSE; + *p++ = ' '; + *p++ = '('; if (add_file) { - STRCPY(buf, "file "); - buf += 5; + STRCPY(p, "file "); + p += 5; } - sprintf((char *)buf, curwin->w_arg_idx_invalid ? "(%d) of %d)" : - "%d of %d)", curwin->w_arg_idx + 1, arg_count); + sprintf((char *)p, curwin->w_arg_idx_invalid ? "(%d) of %d)" : + "%d of %d)", curwin->w_arg_idx + 1, arg_count); + return TRUE; } /* @@ -1501,10 +1590,12 @@ do_arg_all(count) /* EMSG("Argument list contains less than 2 files"); */ return; } + /* * 1. close all but first window * 2. make the desired number of windows - * 3. start editing in the windows + * 3. start editing one file in each window + * arg_count may change while doing this, because of autocommands. */ setpcmark(); close_others(FALSE); @@ -1512,22 +1603,46 @@ do_arg_all(count) if (count > arg_count || count <= 0) count = arg_count; count = make_windows(count); - for (i = 0; i < count; ++i) + +#ifdef AUTOCMD + /* + * Don't execute Win/Buf Enter/Leave autocommands here + */ + ++autocmd_no_enter; + ++autocmd_no_leave; +#endif + for (i = 0; i < count && i < arg_count && !got_int; ++i) { - /* edit file i */ - (void)do_ecmd(0, arg_files[i], NULL, NULL, TRUE, (linenr_t)1, FALSE); - curwin->w_arg_idx = i; if (i == arg_count - 1) arg_had_last = TRUE; + curwin->w_arg_idx = i; +#ifdef AUTOCMD + if (i == 0) /* first window: do autocmd for leaving this buffer */ + --autocmd_no_leave; +#endif + /* edit file i */ + (void)do_ecmd(0, arg_files[i], NULL, NULL, (linenr_t)1, + ECMD_HIDE + ECMD_OLDBUF); +#ifdef AUTOCMD + if (i == 0) + ++autocmd_no_leave; +#endif if (curwin->w_next == NULL) /* just checking */ break; win_enter(curwin->w_next, FALSE); + mch_breakcheck(); } +#ifdef AUTOCMD + --autocmd_no_enter; +#endif win_enter(firstwin, FALSE); /* back to first window */ +#ifdef AUTOCMD + --autocmd_no_leave; +#endif } /* - * do_arg_all: open a window for each buffer + * do_buffer_all: open a window for each buffer * * 'count' is the maximum number of windows to open. * when 'all' is TRUE, also load inactive buffers @@ -1559,27 +1674,70 @@ do_buffer_all(count, all) * 1. close all but first window * 2. make the desired number of windows * 3. stuff commands to fill the windows + * Watch out for autocommands that delete buffers or windows. */ close_others(FALSE); curwin->w_arg_idx = 0; if (buf_count > count) buf_count = count; buf_count = make_windows(buf_count); + +#ifdef AUTOCMD + /* + * Don't execute Win/Buf Enter/Leave autocommands here + */ + ++autocmd_no_enter; + ++autocmd_no_leave; +#endif buf = firstbuf; for (i = 0; i < buf_count; ++i) { + /* find buffer number to put in this window */ for ( ; buf != NULL; buf = buf->b_next) if (all || buf->b_ml.ml_mfp != NULL) break; if (buf == NULL) /* Cannot happen? */ break; + + /* advance to next window */ if (i != 0) - stuffReadbuff((char_u *)"\n\027\027:"); /* CTRL-W CTRL-W */ - stuffReadbuff((char_u *)":buf "); /* edit Nth buffer */ - stuffnumReadbuff((long)buf->b_fnum); + { + if (curwin->w_next == NULL) /* just checking */ + break; + win_enter(curwin->w_next, FALSE); + } + +#ifdef AUTOCMD + if (i == 0) /* first window: do autocmd for leaving this buffer */ + --autocmd_no_leave; +#endif + + /* get buffer for this window */ + (void)do_buffer(DOBUF_GOTO, DOBUF_FIRST, FORWARD, (int)buf->b_fnum, 0); +#ifdef AUTOCMD + if (i == 0) + ++autocmd_no_leave; + if (!buf_valid(buf)) /* autocommands deleted the buffer!!! */ + break; +#endif + + mch_breakcheck(); + if (got_int) + { + (void)vgetc(); /* only break the file loading, not the rest */ + break; + } buf = buf->b_next; } - stuffReadbuff((char_u *)"\n100\027k"); /* back to first window */ +#ifdef AUTOCMD + --autocmd_no_enter; +#endif + win_enter(firstwin, FALSE); /* back to first window */ +#ifdef AUTOCMD + --autocmd_no_leave; +#endif + if (buf_count > 1) + win_equal(curwin, FALSE); /* adjust heights */ } /* |