/* vi:set ts=8 sts=4 sw=4: * * VIM - Vi IMproved by Bram Moolenaar * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. * See README.txt for an overview of the Vim source code. */ /* * buffer.c: functions for dealing with the buffer structure */ /* * The buffer list is a double linked list of all buffers. * Each buffer can be in one of these states: * never loaded: BF_NEVERLOADED is set, only the file name is valid * not loaded: b_ml.ml_mfp == NULL, no memfile allocated * hidden: b_nwindows == 0, loaded but not displayed in a window * normal: loaded and displayed in a window * * Instead of storing file names all over the place, each file name is * stored in the buffer list. It can be referenced by a number. * * The current implementation remembers all file names ever used. */ #include "vim.h" #if defined(FEAT_CMDL_COMPL) || defined(FEAT_LISTCMDS) || defined(FEAT_EVAL) || defined(FEAT_PERL)static char_u *buflist_match __ARGS((regprog_T *prog, buf_T *buf));# define HAVE_BUFLIST_MATCHstatic char_u *fname_match __ARGS((regprog_T *prog, char_u *name));#endifstatic void buflist_setfpos __ARGS((buf_T *buf, win_T *win, linenr_T lnum, colnr_T col, int copy_options));static wininfo_T *find_wininfo __ARGS((buf_T *buf));#ifdef UNIXstatic buf_T *buflist_findname_stat __ARGS((char_u *ffname, struct stat *st));static int otherfile_buf __ARGS((buf_T *buf, char_u *ffname, struct stat *stp));static int buf_same_ino __ARGS((buf_T *buf, struct stat *stp));#elsestatic int otherfile_buf __ARGS((buf_T *buf, char_u *ffname));#endif#ifdef FEAT_TITLEstatic int ti_change __ARGS((char_u *str, char_u **last));#endifstatic void free_buffer __ARGS((buf_T *));static void free_buffer_stuff __ARGS((buf_T *buf, int free_options));static void clear_wininfo __ARGS((buf_T *buf)); #ifdef UNIX# define dev_T dev_t#else# define dev_T unsigned#endif #if defined(FEAT_SIGNS)static void insert_sign __ARGS((buf_T *buf, signlist_T *prev, signlist_T *next, int id, linenr_T lnum, int typenr));static void buf_delete_signs __ARGS((buf_T *buf));#endif /* * Open current buffer, that is: open the memfile and read the file into memory * return FAIL for failure, OK otherwise */ intopen_buffer(read_stdin, eap) int read_stdin; /* read file from stdin */ exarg_T *eap; /* for forced 'ff' and 'fenc' or NULL */{ int retval = OK;#ifdef FEAT_AUTOCMD buf_T *old_curbuf;#endif /* * The 'readonly' flag is only set when BF_NEVERLOADED is being reset. * When re-entering the same buffer, it should not change, because the * user may have reset the flag by hand. */ if (readonlymode && curbuf->b_ffname != NULL && (curbuf->b_flags & BF_NEVERLOADED)) curbuf->b_p_ro = TRUE; if (ml_open(curbuf) == FAIL) { /* * There MUST be a memfile, otherwise we can't do anything * If we can't create one for the current buffer, take another buffer */ close_buffer(NULL, curbuf, 0); for (curbuf = firstbuf; curbuf != NULL; curbuf = curbuf->b_next) if (curbuf->b_ml.ml_mfp != NULL) break; /* * if there is no memfile at all, exit * This is OK, since there are no changes to loose. */ if (curbuf == NULL) { EMSG(_("E82: Cannot allocate any buffer, exiting...")); getout(2); } EMSG(_("E83: Cannot allocate buffer, using other one...")); enter_buffer(curbuf); return FAIL; } #ifdef FEAT_AUTOCMD /* The autocommands in readfile() may change the buffer, but only AFTER * reading the file. */ old_curbuf = curbuf; modified_was_set = FALSE;#endif /* mark cursor position as being invalid */ changed_line_abv_curs(); if (curbuf->b_ffname != NULL#ifdef FEAT_NETBEANS_INTG && netbeansReadFile#endif ) {#ifdef FEAT_NETBEANS_INTG int oldFire = netbeansFireChanges; netbeansFireChanges = 0;#endif retval = readfile(curbuf->b_ffname, curbuf->b_fname, (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM, eap, READ_NEW);#ifdef FEAT_NETBEANS_INTG netbeansFireChanges = oldFire;#endif /* Help buffer is filtered. */ if (curbuf->b_help) fix_help_buffer(); } else if (read_stdin) { int save_bin = curbuf->b_p_bin; linenr_T line_count; /* * First read the text in binary mode into the buffer. * Then read from that same buffer and append at the end. This makes * it possible to retry when 'fileformat' or 'fileencoding' was * guessed wrong. */ curbuf->b_p_bin = TRUE; retval = readfile(NULL, NULL, (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM, NULL, READ_NEW + READ_STDIN); curbuf->b_p_bin = save_bin; if (retval == OK) { line_count = curbuf->b_ml.ml_line_count; retval = readfile(NULL, NULL, (linenr_T)line_count, (linenr_T)0, (linenr_T)MAXLNUM, eap, READ_BUFFER); if (retval == OK) { /* Delete the binary lines. */ while (--line_count >= 0) ml_delete((linenr_T)1, FALSE); } else { /* Delete the converted lines. */ while (curbuf->b_ml.ml_line_count > line_count) ml_delete(line_count, FALSE); } /* Put the cursor on the first line. */ curwin->w_cursor.lnum = 1; curwin->w_cursor.col = 0;#ifdef FEAT_AUTOCMD# ifdef FEAT_EVAL apply_autocmds_retval(EVENT_STDINREADPOST, NULL, NULL, FALSE, curbuf, &retval);# else apply_autocmds(EVENT_STDINREADPOST, NULL, NULL, FALSE, curbuf);# endif#endif } } /* if first time loading this buffer, init b_chartab[] */ if (curbuf->b_flags & BF_NEVERLOADED) (void)buf_init_chartab(curbuf, FALSE); /* * Set/reset the Changed flag first, autocmds may change the buffer. * Apply the automatic commands, before processing the modelines. * So the modelines have priority over auto commands. */ /* When reading stdin, the buffer contents always needs writing, so set * the changed flag. Unless in readonly mode: "ls | gview -". * When interrupted and 'cpoptions' contains 'i' set changed flag. */ if ((read_stdin && !readonlymode && !bufempty())#ifdef FEAT_AUTOCMD || modified_was_set /* ":set modified" used in autocmd */# ifdef FEAT_EVAL || (aborting() && vim_strchr(p_cpo, CPO_INTMOD) != NULL)# endif#endif || (got_int && vim_strchr(p_cpo, CPO_INTMOD) != NULL)) changed(); else if (retval != FAIL) unchanged(curbuf, FALSE); save_file_ff(curbuf); /* keep this fileformat */ /* require "!" to overwrite the file, because it wasn't read completely */#ifdef FEAT_EVAL if (aborting())#else if (got_int)#endif curbuf->b_flags |= BF_READERR; #ifdef FEAT_FOLDING /* Need to update automatic folding. Do this before the autocommands, * they may use the fold info. */ foldUpdateAll(curwin);#endif #ifdef FEAT_AUTOCMD /* need to set w_topline, unless some autocommand already did that. */ if (!(curwin->w_valid & VALID_TOPLINE)) { curwin->w_topline = 1;# ifdef FEAT_DIFF curwin->w_topfill = 0;# endif }# ifdef FEAT_EVAL apply_autocmds_retval(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf, &retval);# else apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);# endif#endif if (retval != FAIL) {#ifdef FEAT_AUTOCMD /* * The autocommands may have changed the current buffer. Apply the * modelines to the correct buffer, if it still exists and is loaded. */ if (buf_valid(old_curbuf) && old_curbuf->b_ml.ml_mfp != NULL) { aco_save_T aco; /* Go to the buffer that was opened. */ aucmd_prepbuf(&aco, old_curbuf);#endif do_modelines(0); curbuf->b_flags &= ~(BF_CHECK_RO | BF_NEVERLOADED); #ifdef FEAT_AUTOCMD# ifdef FEAT_EVAL apply_autocmds_retval(EVENT_BUFWINENTER, NULL, NULL, FALSE, curbuf, &retval);# else apply_autocmds(EVENT_BUFWINENTER, NULL, NULL, FALSE, curbuf);# endif /* restore curwin/curbuf and a few other things */ aucmd_restbuf(&aco); }#endif } return retval;} /* * Return TRUE if "buf" points to a valid buffer (in the buffer list). */ intbuf_valid(buf) buf_T *buf;{ buf_T *bp; for (bp = firstbuf; bp != NULL; bp = bp->b_next) if (bp == buf) return TRUE; return FALSE;} /* * Close the link to a buffer. * "action" is used when there is no longer a window for the buffer. * It can be: * 0 buffer becomes hidden * DOBUF_UNLOAD buffer is unloaded * DOBUF_DELETE buffer is unloaded and removed from buffer list * DOBUF_WIPE buffer is unloaded and really deleted * When doing all but the first one on the current buffer, the caller should * get a new buffer very soon! * * The 'bufhidden' option can force freeing and deleting. */ voidclose_buffer(win, buf, action) win_T *win; /* if not NULL, set b_last_cursor */ buf_T *buf; int action;{#ifdef FEAT_AUTOCMD int is_curbuf; int nwindows = buf->b_nwindows;#endif int unload_buf = (action != 0); int del_buf = (action == DOBUF_DEL || action == DOBUF_WIPE); int wipe_buf = (action == DOBUF_WIPE); #ifdef FEAT_QUICKFIX /* * Force unloading or deleting when 'bufhidden' says so. * The caller must take care of NOT deleting/freeing when 'bufhidden' is * "hide" (otherwise we could never free or delete a buffer). */ if (buf->b_p_bh[0] == 'd') /* 'bufhidden' == "delete" */ { del_buf = TRUE; unload_buf = TRUE; } else if (buf->b_p_bh[0] == 'w') /* 'bufhidden' == "wipe" */ { del_buf = TRUE; unload_buf = TRUE; wipe_buf = TRUE; } else if (buf->b_p_bh[0] == 'u') /* 'bufhidden' == "unload" */ unload_buf = TRUE;#endif if (win != NULL) { /* Set b_last_cursor when closing the last window for the buffer. * Remember the last cursor position and window options of the buffer. * This used to be only for the current window, but then options like * 'foldmethod' may be lost with a ":only" command. */ if (buf->b_nwindows == 1) set_last_cursor(win); buflist_setfpos(buf, win, win->w_cursor.lnum == 1 ? 0 : win->w_cursor.lnum, win->w_cursor.col, TRUE); } #ifdef FEAT_AUTOCMD /* When the buffer is no longer in a window, trigger BufWinLeave */ if (buf->b_nwindows == 1) { apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname, FALSE, buf); if (!buf_valid(buf)) /* autocommands may delete the buffer */ return; /* When the buffer becomes hidden, but is not unloaded, trigger * BufHidden */ if (!unload_buf) { apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname, FALSE, buf); if (!buf_valid(buf)) /* autocmds may delete the buffer */ return; }# ifdef FEAT_EVAL if (aborting()) /* autocmds may abort script processing */ return;# endif } nwindows = buf->b_nwindows;#endif /* decrease the link count from windows (unless not in any window) */ if (buf->b_nwindows > 0) --buf->b_nwindows; /* Return when a window is displaying the buffer or when it's not * unloaded. */ if (buf->b_nwindows > 0 || !unload_buf) {#if 0 /* why was this here? */ if (buf == curbuf) u_sync(); /* sync undo before going to another buffer */#endif return; } /* Always remove the buffer when there is no file name. */ if (buf->b_ffname == NULL) del_buf = TRUE; /* * Free all things allocated for this buffer. * Also calls the "BufDelete" autocommands when del_buf is TRUE. */#ifdef FEAT_AUTOCMD /* Remember if we are closing the current buffer. Restore the number of * windows, so that autocommands in buf_freeall() don't get confused. */ is_curbuf = (buf == curbuf); buf->b_nwindows = nwindows;#endif buf_freeall(buf, del_buf, wipe_buf); #ifdef FEAT_AUTOCMD /* Autocommands may have deleted the buffer. */ if (!buf_valid(buf)) return;# ifdef FEAT_EVAL if (aborting()) /* autocmds may abort script processing */ return;# endif /* Autocommands may have opened or closed windows for this buffer. * Decrement the count for the close we do here. */ if (buf->b_nwindows > 0) --buf->b_nwindows; /* * It's possible that autocommands change curbuf to the one being deleted. * This might cause the previous curbuf to be deleted unexpectedly. But * in some cases it's OK to delete the curbuf, because a new one is * obtained anyway. Therefore only return if curbuf changed to the * deleted buffer. */ if (buf == curbuf && !is_curbuf) return;#endif #ifdef FEAT_NETBEANS_INTG if (usingNetbeans) netbeans_file_closed(buf);#endif /* Change directories when the 'acd' option is set. */ DO_AUTOCHDIR /* * Remove the buffer from the list. */ if (wipe_buf) {#ifdef FEAT_SUN_WORKSHOP if (usingSunWorkShop) workshop_file_closed_lineno((char *)buf->b_ffname, (int)buf->b_last_cursor.lnum);#endif vim_free(buf->b_ffname); vim_free(buf->b_sfname); if (buf->b_prev == NULL) firstbuf = buf->b_next; else buf->b_prev->b_next = buf->b_next; if (buf->b_next == NULL) lastbuf = buf->b_prev; else buf->b_next->b_prev = buf->b_prev; free_buffer(buf); } else { if (del_buf) { /* Free all internal variables and reset option values, to make * ":bdel" compatible with Vim 5.7. */ free_buffer_stuff(buf, TRUE); /* Make it look like a new buffer. */ buf->b_flags = BF_CHECK_RO | BF_NEVERLOADED; /* Init the options when loaded again. */ buf->b_p_initialized = FALSE; } buf_clear_file(buf); if (del_buf) buf->b_p_bl = FALSE; }} /* * Make buffer not contain a file. */ voidbuf_clear_file(buf) buf_T *buf;{ buf->b_ml.ml_line_count = 1; unchanged(buf, TRUE);#ifndef SHORT_FNAME buf->b_shortname = FALSE;#endif buf->b_p_eol = TRUE; buf->b_start_eol = TRUE;#ifdef FEAT_MBYTE buf->b_p_bomb = FALSE;#endif buf->b_ml.ml_mfp = NULL; buf->b_ml.ml_flags = ML_EMPTY; /* empty buffer */Lines 1–500 of 5517. Load more
/* vi:set ts=8 sts=4 sw=4: * * VIM - Vi IMproved by Bram Moolenaar * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. * See README.txt for an overview of the Vim source code. */ /* * buffer.c: functions for dealing with the buffer structure */ /* * The buffer list is a double linked list of all buffers. * Each buffer can be in one of these states: * never loaded: BF_NEVERLOADED is set, only the file name is valid * not loaded: b_ml.ml_mfp == NULL, no memfile allocated * hidden: b_nwindows == 0, loaded but not displayed in a window * normal: loaded and displayed in a window * * Instead of storing file names all over the place, each file name is * stored in the buffer list. It can be referenced by a number. * * The current implementation remembers all file names ever used. */ #include "vim.h" #if defined(FEAT_CMDL_COMPL) || defined(FEAT_LISTCMDS) || defined(FEAT_EVAL) || defined(FEAT_PERL) static char_u *buflist_match __ARGS((regprog_T *prog, buf_T *buf)); # define HAVE_BUFLIST_MATCH static char_u *fname_match __ARGS((regprog_T *prog, char_u *name)); #endif static void buflist_setfpos __ARGS((buf_T *buf, win_T *win, linenr_T lnum, colnr_T col, int copy_options)); static wininfo_T *find_wininfo __ARGS((buf_T *buf)); #ifdef UNIX static buf_T *buflist_findname_stat __ARGS((char_u *ffname, struct stat *st)); static int otherfile_buf __ARGS((buf_T *buf, char_u *ffname, struct stat *stp)); static int buf_same_ino __ARGS((buf_T *buf, struct stat *stp)); #else static int otherfile_buf __ARGS((buf_T *buf, char_u *ffname)); #endif #ifdef FEAT_TITLE static int ti_change __ARGS((char_u *str, char_u **last)); #endif static void free_buffer __ARGS((buf_T *)); static void free_buffer_stuff __ARGS((buf_T *buf, int free_options)); static void clear_wininfo __ARGS((buf_T *buf)); #ifdef UNIX # define dev_T dev_t #else # define dev_T unsigned #endif #if defined(FEAT_SIGNS) static void insert_sign __ARGS((buf_T *buf, signlist_T *prev, signlist_T *next, int id, linenr_T lnum, int typenr)); static void buf_delete_signs __ARGS((buf_T *buf)); #endif /* * Open current buffer, that is: open the memfile and read the file into memory * return FAIL for failure, OK otherwise */ int open_buffer(read_stdin, eap) int read_stdin; /* read file from stdin */ exarg_T *eap; /* for forced 'ff' and 'fenc' or NULL */ { int retval = OK; #ifdef FEAT_AUTOCMD buf_T *old_curbuf; #endif /* * The 'readonly' flag is only set when BF_NEVERLOADED is being reset. * When re-entering the same buffer, it should not change, because the * user may have reset the flag by hand. */ if (readonlymode && curbuf->b_ffname != NULL && (curbuf->b_flags & BF_NEVERLOADED)) curbuf->b_p_ro = TRUE; if (ml_open(curbuf) == FAIL) { /* * There MUST be a memfile, otherwise we can't do anything * If we can't create one for the current buffer, take another buffer */ close_buffer(NULL, curbuf, 0); for (curbuf = firstbuf; curbuf != NULL; curbuf = curbuf->b_next) if (curbuf->b_ml.ml_mfp != NULL) break; /* * if there is no memfile at all, exit * This is OK, since there are no changes to loose. */ if (curbuf == NULL) { EMSG(_("E82: Cannot allocate any buffer, exiting...")); getout(2); } EMSG(_("E83: Cannot allocate buffer, using other one...")); enter_buffer(curbuf); return FAIL; } #ifdef FEAT_AUTOCMD /* The autocommands in readfile() may change the buffer, but only AFTER * reading the file. */ old_curbuf = curbuf; modified_was_set = FALSE; #endif /* mark cursor position as being invalid */ changed_line_abv_curs(); if (curbuf->b_ffname != NULL #ifdef FEAT_NETBEANS_INTG && netbeansReadFile #endif ) { #ifdef FEAT_NETBEANS_INTG int oldFire = netbeansFireChanges; netbeansFireChanges = 0; #endif retval = readfile(curbuf->b_ffname, curbuf->b_fname, (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM, eap, READ_NEW); #ifdef FEAT_NETBEANS_INTG netbeansFireChanges = oldFire; #endif /* Help buffer is filtered. */ if (curbuf->b_help) fix_help_buffer(); } else if (read_stdin) { int save_bin = curbuf->b_p_bin; linenr_T line_count; /* * First read the text in binary mode into the buffer. * Then read from that same buffer and append at the end. This makes * it possible to retry when 'fileformat' or 'fileencoding' was * guessed wrong. */ curbuf->b_p_bin = TRUE; retval = readfile(NULL, NULL, (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM, NULL, READ_NEW + READ_STDIN); curbuf->b_p_bin = save_bin; if (retval == OK) { line_count = curbuf->b_ml.ml_line_count; retval = readfile(NULL, NULL, (linenr_T)line_count, (linenr_T)0, (linenr_T)MAXLNUM, eap, READ_BUFFER); if (retval == OK) { /* Delete the binary lines. */ while (--line_count >= 0) ml_delete((linenr_T)1, FALSE); } else { /* Delete the converted lines. */ while (curbuf->b_ml.ml_line_count > line_count) ml_delete(line_count, FALSE); } /* Put the cursor on the first line. */ curwin->w_cursor.lnum = 1; curwin->w_cursor.col = 0; #ifdef FEAT_AUTOCMD # ifdef FEAT_EVAL apply_autocmds_retval(EVENT_STDINREADPOST, NULL, NULL, FALSE, curbuf, &retval); # else apply_autocmds(EVENT_STDINREADPOST, NULL, NULL, FALSE, curbuf); # endif #endif } } /* if first time loading this buffer, init b_chartab[] */ if (curbuf->b_flags & BF_NEVERLOADED) (void)buf_init_chartab(curbuf, FALSE); /* * Set/reset the Changed flag first, autocmds may change the buffer. * Apply the automatic commands, before processing the modelines. * So the modelines have priority over auto commands. */ /* When reading stdin, the buffer contents always needs writing, so set * the changed flag. Unless in readonly mode: "ls | gview -". * When interrupted and 'cpoptions' contains 'i' set changed flag. */ if ((read_stdin && !readonlymode && !bufempty()) #ifdef FEAT_AUTOCMD || modified_was_set /* ":set modified" used in autocmd */ # ifdef FEAT_EVAL || (aborting() && vim_strchr(p_cpo, CPO_INTMOD) != NULL) # endif #endif || (got_int && vim_strchr(p_cpo, CPO_INTMOD) != NULL)) changed(); else if (retval != FAIL) unchanged(curbuf, FALSE); save_file_ff(curbuf); /* keep this fileformat */ /* require "!" to overwrite the file, because it wasn't read completely */ #ifdef FEAT_EVAL if (aborting()) #else if (got_int) #endif curbuf->b_flags |= BF_READERR; #ifdef FEAT_FOLDING /* Need to update automatic folding. Do this before the autocommands, * they may use the fold info. */ foldUpdateAll(curwin); #endif #ifdef FEAT_AUTOCMD /* need to set w_topline, unless some autocommand already did that. */ if (!(curwin->w_valid & VALID_TOPLINE)) { curwin->w_topline = 1; # ifdef FEAT_DIFF curwin->w_topfill = 0; # endif } # ifdef FEAT_EVAL apply_autocmds_retval(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf, &retval); # else apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf); # endif #endif if (retval != FAIL) { #ifdef FEAT_AUTOCMD /* * The autocommands may have changed the current buffer. Apply the * modelines to the correct buffer, if it still exists and is loaded. */ if (buf_valid(old_curbuf) && old_curbuf->b_ml.ml_mfp != NULL) { aco_save_T aco; /* Go to the buffer that was opened. */ aucmd_prepbuf(&aco, old_curbuf); #endif do_modelines(0); curbuf->b_flags &= ~(BF_CHECK_RO | BF_NEVERLOADED); #ifdef FEAT_AUTOCMD # ifdef FEAT_EVAL apply_autocmds_retval(EVENT_BUFWINENTER, NULL, NULL, FALSE, curbuf, &retval); # else apply_autocmds(EVENT_BUFWINENTER, NULL, NULL, FALSE, curbuf); # endif /* restore curwin/curbuf and a few other things */ aucmd_restbuf(&aco); } #endif } return retval; } /* * Return TRUE if "buf" points to a valid buffer (in the buffer list). */ int buf_valid(buf) buf_T *buf; { buf_T *bp; for (bp = firstbuf; bp != NULL; bp = bp->b_next) if (bp == buf) return TRUE; return FALSE; } /* * Close the link to a buffer. * "action" is used when there is no longer a window for the buffer. * It can be: * 0 buffer becomes hidden * DOBUF_UNLOAD buffer is unloaded * DOBUF_DELETE buffer is unloaded and removed from buffer list * DOBUF_WIPE buffer is unloaded and really deleted * When doing all but the first one on the current buffer, the caller should * get a new buffer very soon! * * The 'bufhidden' option can force freeing and deleting. */ void close_buffer(win, buf, action) win_T *win; /* if not NULL, set b_last_cursor */ buf_T *buf; int action; { #ifdef FEAT_AUTOCMD int is_curbuf; int nwindows = buf->b_nwindows; #endif int unload_buf = (action != 0); int del_buf = (action == DOBUF_DEL || action == DOBUF_WIPE); int wipe_buf = (action == DOBUF_WIPE); #ifdef FEAT_QUICKFIX /* * Force unloading or deleting when 'bufhidden' says so. * The caller must take care of NOT deleting/freeing when 'bufhidden' is * "hide" (otherwise we could never free or delete a buffer). */ if (buf->b_p_bh[0] == 'd') /* 'bufhidden' == "delete" */ { del_buf = TRUE; unload_buf = TRUE; } else if (buf->b_p_bh[0] == 'w') /* 'bufhidden' == "wipe" */ { del_buf = TRUE; unload_buf = TRUE; wipe_buf = TRUE; } else if (buf->b_p_bh[0] == 'u') /* 'bufhidden' == "unload" */ unload_buf = TRUE; #endif if (win != NULL) { /* Set b_last_cursor when closing the last window for the buffer. * Remember the last cursor position and window options of the buffer. * This used to be only for the current window, but then options like * 'foldmethod' may be lost with a ":only" command. */ if (buf->b_nwindows == 1) set_last_cursor(win); buflist_setfpos(buf, win, win->w_cursor.lnum == 1 ? 0 : win->w_cursor.lnum, win->w_cursor.col, TRUE); } #ifdef FEAT_AUTOCMD /* When the buffer is no longer in a window, trigger BufWinLeave */ if (buf->b_nwindows == 1) { apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname, FALSE, buf); if (!buf_valid(buf)) /* autocommands may delete the buffer */ return; /* When the buffer becomes hidden, but is not unloaded, trigger * BufHidden */ if (!unload_buf) { apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname, FALSE, buf); if (!buf_valid(buf)) /* autocmds may delete the buffer */ return; } # ifdef FEAT_EVAL if (aborting()) /* autocmds may abort script processing */ return; # endif } nwindows = buf->b_nwindows; #endif /* decrease the link count from windows (unless not in any window) */ if (buf->b_nwindows > 0) --buf->b_nwindows; /* Return when a window is displaying the buffer or when it's not * unloaded. */ if (buf->b_nwindows > 0 || !unload_buf) { #if 0 /* why was this here? */ if (buf == curbuf) u_sync(); /* sync undo before going to another buffer */ #endif return; } /* Always remove the buffer when there is no file name. */ if (buf->b_ffname == NULL) del_buf = TRUE; /* * Free all things allocated for this buffer. * Also calls the "BufDelete" autocommands when del_buf is TRUE. */ #ifdef FEAT_AUTOCMD /* Remember if we are closing the current buffer. Restore the number of * windows, so that autocommands in buf_freeall() don't get confused. */ is_curbuf = (buf == curbuf); buf->b_nwindows = nwindows; #endif buf_freeall(buf, del_buf, wipe_buf); #ifdef FEAT_AUTOCMD /* Autocommands may have deleted the buffer. */ if (!buf_valid(buf)) return; # ifdef FEAT_EVAL if (aborting()) /* autocmds may abort script processing */ return; # endif /* Autocommands may have opened or closed windows for this buffer. * Decrement the count for the close we do here. */ if (buf->b_nwindows > 0) --buf->b_nwindows; /* * It's possible that autocommands change curbuf to the one being deleted. * This might cause the previous curbuf to be deleted unexpectedly. But * in some cases it's OK to delete the curbuf, because a new one is * obtained anyway. Therefore only return if curbuf changed to the * deleted buffer. */ if (buf == curbuf && !is_curbuf) return; #endif #ifdef FEAT_NETBEANS_INTG if (usingNetbeans) netbeans_file_closed(buf); #endif /* Change directories when the 'acd' option is set. */ DO_AUTOCHDIR /* * Remove the buffer from the list. */ if (wipe_buf) { #ifdef FEAT_SUN_WORKSHOP if (usingSunWorkShop) workshop_file_closed_lineno((char *)buf->b_ffname, (int)buf->b_last_cursor.lnum); #endif vim_free(buf->b_ffname); vim_free(buf->b_sfname); if (buf->b_prev == NULL) firstbuf = buf->b_next; else buf->b_prev->b_next = buf->b_next; if (buf->b_next == NULL) lastbuf = buf->b_prev; else buf->b_next->b_prev = buf->b_prev; free_buffer(buf); } else { if (del_buf) { /* Free all internal variables and reset option values, to make * ":bdel" compatible with Vim 5.7. */ free_buffer_stuff(buf, TRUE); /* Make it look like a new buffer. */ buf->b_flags = BF_CHECK_RO | BF_NEVERLOADED; /* Init the options when loaded again. */ buf->b_p_initialized = FALSE; } buf_clear_file(buf); if (del_buf) buf->b_p_bl = FALSE; } } /* * Make buffer not contain a file. */ void buf_clear_file(buf) buf_T *buf; { buf->b_ml.ml_line_count = 1; unchanged(buf, TRUE); #ifndef SHORT_FNAME buf->b_shortname = FALSE; #endif buf->b_p_eol = TRUE; buf->b_start_eol = TRUE; #ifdef FEAT_MBYTE buf->b_p_bomb = FALSE; #endif buf->b_ml.ml_mfp = NULL; buf->b_ml.ml_flags = ML_EMPTY; /* empty buffer */