comparison src/buffer.c @ 5586:505cf1943dc2 v7.4.140

updated for version 7.4.140 Problem: Crash when wiping out buffer triggers autocommand that wipes out only other buffer. Solution: Do not delete the last buffer, make it empty. (Hirohito Higashi)
author Bram Moolenaar <bram@vim.org>
date Fri, 10 Jan 2014 16:43:14 +0100
parents d0595545e98a
children 06e5f65c34d8
comparison
equal deleted inserted replaced
5585:8ce54730f806 5586:505cf1943dc2
992 #endif /* FEAT_LISTCMDS */ 992 #endif /* FEAT_LISTCMDS */
993 993
994 #if defined(FEAT_LISTCMDS) || defined(FEAT_PYTHON) \ 994 #if defined(FEAT_LISTCMDS) || defined(FEAT_PYTHON) \
995 || defined(FEAT_PYTHON3) || defined(PROTO) 995 || defined(FEAT_PYTHON3) || defined(PROTO)
996 996
997 static int empty_curbuf __ARGS((int close_others, int forceit, int action));
998
999 /*
1000 * Make the current buffer empty.
1001 * Used when it is wiped out and it's the last buffer.
1002 */
1003 static int
1004 empty_curbuf(close_others, forceit, action)
1005 int close_others;
1006 int forceit;
1007 int action;
1008 {
1009 int retval;
1010 buf_T *buf = curbuf;
1011
1012 if (action == DOBUF_UNLOAD)
1013 {
1014 EMSG(_("E90: Cannot unload last buffer"));
1015 return FAIL;
1016 }
1017
1018 if (close_others)
1019 {
1020 /* Close any other windows on this buffer, then make it empty. */
1021 #ifdef FEAT_WINDOWS
1022 close_windows(buf, TRUE);
1023 #endif
1024 }
1025
1026 setpcmark();
1027 retval = do_ecmd(0, NULL, NULL, NULL, ECMD_ONE,
1028 forceit ? ECMD_FORCEIT : 0, curwin);
1029
1030 /*
1031 * do_ecmd() may create a new buffer, then we have to delete
1032 * the old one. But do_ecmd() may have done that already, check
1033 * if the buffer still exists.
1034 */
1035 if (buf != curbuf && buf_valid(buf) && buf->b_nwindows == 0)
1036 close_buffer(NULL, buf, action, FALSE);
1037 if (!close_others)
1038 need_fileinfo = FALSE;
1039 return retval;
1040 }
997 /* 1041 /*
998 * Implementation of the commands for the buffer list. 1042 * Implementation of the commands for the buffer list.
999 * 1043 *
1000 * action == DOBUF_GOTO go to specified buffer 1044 * action == DOBUF_GOTO go to specified buffer
1001 * action == DOBUF_SPLIT split window and go to specified buffer 1045 * action == DOBUF_SPLIT split window and go to specified buffer
1112 * delete buffer buf from memory and/or the list 1156 * delete buffer buf from memory and/or the list
1113 */ 1157 */
1114 if (unload) 1158 if (unload)
1115 { 1159 {
1116 int forward; 1160 int forward;
1117 int retval;
1118 1161
1119 /* When unloading or deleting a buffer that's already unloaded and 1162 /* When unloading or deleting a buffer that's already unloaded and
1120 * unlisted: fail silently. */ 1163 * unlisted: fail silently. */
1121 if (action != DOBUF_WIPE && buf->b_ml.ml_mfp == NULL && !buf->b_p_bl) 1164 if (action != DOBUF_WIPE && buf->b_ml.ml_mfp == NULL && !buf->b_p_bl)
1122 return FAIL; 1165 return FAIL;
1153 */ 1196 */
1154 for (bp = firstbuf; bp != NULL; bp = bp->b_next) 1197 for (bp = firstbuf; bp != NULL; bp = bp->b_next)
1155 if (bp->b_p_bl && bp != buf) 1198 if (bp->b_p_bl && bp != buf)
1156 break; 1199 break;
1157 if (bp == NULL && buf == curbuf) 1200 if (bp == NULL && buf == curbuf)
1158 { 1201 return empty_curbuf(TRUE, forceit, action);
1159 if (action == DOBUF_UNLOAD)
1160 {
1161 EMSG(_("E90: Cannot unload last buffer"));
1162 return FAIL;
1163 }
1164
1165 /* Close any other windows on this buffer, then make it empty. */
1166 #ifdef FEAT_WINDOWS
1167 close_windows(buf, TRUE);
1168 #endif
1169 setpcmark();
1170 retval = do_ecmd(0, NULL, NULL, NULL, ECMD_ONE,
1171 forceit ? ECMD_FORCEIT : 0, curwin);
1172
1173 /*
1174 * do_ecmd() may create a new buffer, then we have to delete
1175 * the old one. But do_ecmd() may have done that already, check
1176 * if the buffer still exists.
1177 */
1178 if (buf != curbuf && buf_valid(buf) && buf->b_nwindows == 0)
1179 close_buffer(NULL, buf, action, FALSE);
1180 return retval;
1181 }
1182 1202
1183 #ifdef FEAT_WINDOWS 1203 #ifdef FEAT_WINDOWS
1184 /* 1204 /*
1185 * If the deleted buffer is the current one, close the current window 1205 * If the deleted buffer is the current one, close the current window
1186 * (unless it's the only window). Repeat this so long as we end up in 1206 * (unless it's the only window). Repeat this so long as we end up in
1210 return OK; 1230 return OK;
1211 } 1231 }
1212 1232
1213 /* 1233 /*
1214 * Deleting the current buffer: Need to find another buffer to go to. 1234 * Deleting the current buffer: Need to find another buffer to go to.
1215 * There must be another, otherwise it would have been handled above. 1235 * There should be another, otherwise it would have been handled
1236 * above. However, autocommands may have deleted all buffers.
1216 * First use au_new_curbuf, if it is valid. 1237 * First use au_new_curbuf, if it is valid.
1217 * Then prefer the buffer we most recently visited. 1238 * Then prefer the buffer we most recently visited.
1218 * Else try to find one that is loaded, after the current buffer, 1239 * Else try to find one that is loaded, after the current buffer,
1219 * then before the current buffer. 1240 * then before the current buffer.
1220 * Finally use any buffer. 1241 * Finally use any buffer.
1309 else 1330 else
1310 buf = curbuf->b_prev; 1331 buf = curbuf->b_prev;
1311 } 1332 }
1312 } 1333 }
1313 1334
1335 if (buf == NULL)
1336 {
1337 /* Autocommands must have wiped out all other buffers. Only option
1338 * now is to make the current buffer empty. */
1339 return empty_curbuf(FALSE, forceit, action);
1340 }
1341
1314 /* 1342 /*
1315 * make buf current buffer 1343 * make buf current buffer
1316 */ 1344 */
1317 if (action == DOBUF_SPLIT) /* split window first */ 1345 if (action == DOBUF_SPLIT) /* split window first */
1318 { 1346 {