diff options
author | Lewis Russell <lewis6991@gmail.com> | 2023-01-30 13:39:15 +0000 |
---|---|---|
committer | Lewis Russell <lewis6991@gmail.com> | 2023-01-31 11:20:35 +0000 |
commit | b001f25204042ada6459d13f21ff29dfa0ba494c (patch) | |
tree | d7b4d8b840233551030e6a2522f23f00d9679459 | |
parent | f4b1f0d042a910f069cde9f336bb4d2a8443713c (diff) | |
download | rneovim-b001f25204042ada6459d13f21ff29dfa0ba494c.tar.gz rneovim-b001f25204042ada6459d13f21ff29dfa0ba494c.tar.bz2 rneovim-b001f25204042ada6459d13f21ff29dfa0ba494c.zip |
refactor(fileio.c): factor out autocmd handling from buf_write()
-rw-r--r-- | src/nvim/fileio.c | 363 |
1 files changed, 190 insertions, 173 deletions
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 826b25cd3e..e81d5f614f 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -2076,6 +2076,188 @@ char *new_file_message(void) return shortmess(SHM_NEW) ? _("[New]") : _("[New File]"); } +static int buf_write_do_autocmds(buf_T *buf, char **fnamep, char **sfnamep, char **ffnamep, + linenr_T start, linenr_T *endp, exarg_T *eap, bool append, + bool filtering, bool reset_changed, bool overwriting, bool whole, + const pos_T orig_start, const pos_T orig_end) +{ + linenr_T old_line_count = buf->b_ml.ml_line_count; + int msg_save = msg_scroll; + + aco_save_T aco; + int buf_ffname = false; + int buf_sfname = false; + int buf_fname_f = false; + int buf_fname_s = false; + int did_cmd = false; + int nofile_err = false; + int empty_memline = (buf->b_ml.ml_mfp == NULL); + bufref_T bufref; + + char *sfname = *sfnamep; + + // Apply PRE autocommands. + // Set curbuf to the buffer to be written. + // Careful: The autocommands may call buf_write() recursively! + if (*ffnamep == buf->b_ffname) { + buf_ffname = true; + } + if (sfname == buf->b_sfname) { + buf_sfname = true; + } + if (*fnamep == buf->b_ffname) { + buf_fname_f = true; + } + if (*fnamep == buf->b_sfname) { + buf_fname_s = true; + } + + // Set curwin/curbuf to buf and save a few things. + aucmd_prepbuf(&aco, buf); + set_bufref(&bufref, buf); + + if (append) { + if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEAPPENDCMD, + sfname, sfname, false, curbuf, eap))) { + if (overwriting && bt_nofilename(curbuf)) { + nofile_err = true; + } else { + apply_autocmds_exarg(EVENT_FILEAPPENDPRE, + sfname, sfname, false, curbuf, eap); + } + } + } else if (filtering) { + apply_autocmds_exarg(EVENT_FILTERWRITEPRE, + NULL, sfname, false, curbuf, eap); + } else if (reset_changed && whole) { + int was_changed = curbufIsChanged(); + + did_cmd = apply_autocmds_exarg(EVENT_BUFWRITECMD, + sfname, sfname, false, curbuf, eap); + if (did_cmd) { + if (was_changed && !curbufIsChanged()) { + // Written everything correctly and BufWriteCmd has reset + // 'modified': Correct the undo information so that an + // undo now sets 'modified'. + u_unchanged(curbuf); + u_update_save_nr(curbuf); + } + } else { + if (overwriting && bt_nofilename(curbuf)) { + nofile_err = true; + } else { + apply_autocmds_exarg(EVENT_BUFWRITEPRE, + sfname, sfname, false, curbuf, eap); + } + } + } else { + if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEWRITECMD, + sfname, sfname, false, curbuf, eap))) { + if (overwriting && bt_nofilename(curbuf)) { + nofile_err = true; + } else { + apply_autocmds_exarg(EVENT_FILEWRITEPRE, + sfname, sfname, false, curbuf, eap); + } + } + } + + // restore curwin/curbuf and a few other things + aucmd_restbuf(&aco); + + // In three situations we return here and don't write the file: + // 1. the autocommands deleted or unloaded the buffer. + // 2. The autocommands abort script processing. + // 3. If one of the "Cmd" autocommands was executed. + if (!bufref_valid(&bufref)) { + buf = NULL; + } + if (buf == NULL || (buf->b_ml.ml_mfp == NULL && !empty_memline) + || did_cmd || nofile_err + || aborting()) { + if (buf != NULL && (cmdmod.cmod_flags & CMOD_LOCKMARKS)) { + // restore the original '[ and '] positions + buf->b_op_start = orig_start; + buf->b_op_end = orig_end; + } + + no_wait_return--; + msg_scroll = msg_save; + if (nofile_err) { + semsg(_(e_no_matching_autocommands_for_buftype_str_buffer), curbuf->b_p_bt); + } + + if (nofile_err + || aborting()) { + // An aborting error, interrupt or exception in the + // autocommands. + return FAIL; + } + if (did_cmd) { + if (buf == NULL) { + // The buffer was deleted. We assume it was written + // (can't retry anyway). + return OK; + } + if (overwriting) { + // Assume the buffer was written, update the timestamp. + ml_timestamp(buf); + if (append) { + buf->b_flags &= ~BF_NEW; + } else { + buf->b_flags &= ~BF_WRITE_MASK; + } + } + if (reset_changed && buf->b_changed && !append + && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL)) { + // Buffer still changed, the autocommands didn't work properly. + return FAIL; + } + return OK; + } + if (!aborting()) { + emsg(_("E203: Autocommands deleted or unloaded buffer to be written")); + } + return FAIL; + } + + // The autocommands may have changed the number of lines in the file. + // When writing the whole file, adjust the end. + // When writing part of the file, assume that the autocommands only + // changed the number of lines that are to be written (tricky!). + if (buf->b_ml.ml_line_count != old_line_count) { + if (whole) { // write all + *endp = buf->b_ml.ml_line_count; + } else if (buf->b_ml.ml_line_count > old_line_count) { // more lines + *endp += buf->b_ml.ml_line_count - old_line_count; + } else { // less lines + *endp -= old_line_count - buf->b_ml.ml_line_count; + if (*endp < start) { + no_wait_return--; + msg_scroll = msg_save; + emsg(_("E204: Autocommand changed number of lines in unexpected way")); + return FAIL; + } + } + } + + // The autocommands may have changed the name of the buffer, which may + // be kept in fname, ffname and sfname. + if (buf_ffname) { + *ffnamep = buf->b_ffname; + } + if (buf_sfname) { + *sfnamep = buf->b_sfname; + } + if (buf_fname_f) { + *fnamep = buf->b_ffname; + } + if (buf_fname_s) { + *fnamep = buf->b_sfname; + } + return NOTDONE; +} + /// buf_write() - write to file "fname" lines "start" through "end" /// /// We do our own buffering here because fwrite() is so slow. @@ -2139,7 +2321,6 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en #endif // writing everything int whole = (start == 1 && end == buf->b_ml.ml_line_count); - linenr_T old_line_count = buf->b_ml.ml_line_count; int fileformat; int write_bin; struct bw_info write_info; // info for buf_write_bytes() @@ -2155,8 +2336,6 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en int write_undo_file = false; context_sha256_T sha_ctx; unsigned int bkc = get_bkc_value(buf); - const pos_T orig_start = buf->b_op_start; - const pos_T orig_end = buf->b_op_end; if (fname == NULL || *fname == NUL) { // safety check return FAIL; @@ -2230,182 +2409,20 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en no_wait_return++; // don't wait for return yet + const pos_T orig_start = buf->b_op_start; + const pos_T orig_end = buf->b_op_end; + // Set '[ and '] marks to the lines to be written. buf->b_op_start.lnum = start; buf->b_op_start.col = 0; buf->b_op_end.lnum = end; buf->b_op_end.col = 0; - { - aco_save_T aco; - int buf_ffname = false; - int buf_sfname = false; - int buf_fname_f = false; - int buf_fname_s = false; - int did_cmd = false; - int nofile_err = false; - int empty_memline = (buf->b_ml.ml_mfp == NULL); - bufref_T bufref; - - // Apply PRE autocommands. - // Set curbuf to the buffer to be written. - // Careful: The autocommands may call buf_write() recursively! - if (ffname == buf->b_ffname) { - buf_ffname = true; - } - if (sfname == buf->b_sfname) { - buf_sfname = true; - } - if (fname == buf->b_ffname) { - buf_fname_f = true; - } - if (fname == buf->b_sfname) { - buf_fname_s = true; - } - - // Set curwin/curbuf to buf and save a few things. - aucmd_prepbuf(&aco, buf); - set_bufref(&bufref, buf); - - if (append) { - if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEAPPENDCMD, - sfname, sfname, false, curbuf, eap))) { - if (overwriting && bt_nofilename(curbuf)) { - nofile_err = true; - } else { - apply_autocmds_exarg(EVENT_FILEAPPENDPRE, - sfname, sfname, false, curbuf, eap); - } - } - } else if (filtering) { - apply_autocmds_exarg(EVENT_FILTERWRITEPRE, - NULL, sfname, false, curbuf, eap); - } else if (reset_changed && whole) { - int was_changed = curbufIsChanged(); - - did_cmd = apply_autocmds_exarg(EVENT_BUFWRITECMD, - sfname, sfname, false, curbuf, eap); - if (did_cmd) { - if (was_changed && !curbufIsChanged()) { - // Written everything correctly and BufWriteCmd has reset - // 'modified': Correct the undo information so that an - // undo now sets 'modified'. - u_unchanged(curbuf); - u_update_save_nr(curbuf); - } - } else { - if (overwriting && bt_nofilename(curbuf)) { - nofile_err = true; - } else { - apply_autocmds_exarg(EVENT_BUFWRITEPRE, - sfname, sfname, false, curbuf, eap); - } - } - } else { - if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEWRITECMD, - sfname, sfname, false, curbuf, eap))) { - if (overwriting && bt_nofilename(curbuf)) { - nofile_err = true; - } else { - apply_autocmds_exarg(EVENT_FILEWRITEPRE, - sfname, sfname, false, curbuf, eap); - } - } - } - - // restore curwin/curbuf and a few other things - aucmd_restbuf(&aco); - - // In three situations we return here and don't write the file: - // 1. the autocommands deleted or unloaded the buffer. - // 2. The autocommands abort script processing. - // 3. If one of the "Cmd" autocommands was executed. - if (!bufref_valid(&bufref)) { - buf = NULL; - } - if (buf == NULL || (buf->b_ml.ml_mfp == NULL && !empty_memline) - || did_cmd || nofile_err - || aborting()) { - if (buf != NULL && (cmdmod.cmod_flags & CMOD_LOCKMARKS)) { - // restore the original '[ and '] positions - buf->b_op_start = orig_start; - buf->b_op_end = orig_end; - } - - no_wait_return--; - msg_scroll = msg_save; - if (nofile_err) { - semsg(_(e_no_matching_autocommands_for_buftype_str_buffer), curbuf->b_p_bt); - } - - if (nofile_err - || aborting()) { - // An aborting error, interrupt or exception in the - // autocommands. - return FAIL; - } - if (did_cmd) { - if (buf == NULL) { - // The buffer was deleted. We assume it was written - // (can't retry anyway). - return OK; - } - if (overwriting) { - // Assume the buffer was written, update the timestamp. - ml_timestamp(buf); - if (append) { - buf->b_flags &= ~BF_NEW; - } else { - buf->b_flags &= ~BF_WRITE_MASK; - } - } - if (reset_changed && buf->b_changed && !append - && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL)) { - // Buffer still changed, the autocommands didn't work properly. - return FAIL; - } - return OK; - } - if (!aborting()) { - emsg(_("E203: Autocommands deleted or unloaded buffer to be written")); - } - return FAIL; - } - - // The autocommands may have changed the number of lines in the file. - // When writing the whole file, adjust the end. - // When writing part of the file, assume that the autocommands only - // changed the number of lines that are to be written (tricky!). - if (buf->b_ml.ml_line_count != old_line_count) { - if (whole) { // write all - end = buf->b_ml.ml_line_count; - } else if (buf->b_ml.ml_line_count > old_line_count) { // more lines - end += buf->b_ml.ml_line_count - old_line_count; - } else { // less lines - end -= old_line_count - buf->b_ml.ml_line_count; - if (end < start) { - no_wait_return--; - msg_scroll = msg_save; - emsg(_("E204: Autocommand changed number of lines in unexpected way")); - return FAIL; - } - } - } - - // The autocommands may have changed the name of the buffer, which may - // be kept in fname, ffname and sfname. - if (buf_ffname) { - ffname = buf->b_ffname; - } - if (buf_sfname) { - sfname = buf->b_sfname; - } - if (buf_fname_f) { - fname = buf->b_ffname; - } - if (buf_fname_s) { - fname = buf->b_sfname; - } + int res = buf_write_do_autocmds(buf, &fname, &sfname, &ffname, start, &end, eap, append, + filtering, reset_changed, overwriting, whole, orig_start, + orig_end); + if (res != NOTDONE) { + return res; } if (cmdmod.cmod_flags & CMOD_LOCKMARKS) { |