diff options
Diffstat (limited to 'src/nvim/fileio.c')
-rw-r--r-- | src/nvim/fileio.c | 169 |
1 files changed, 115 insertions, 54 deletions
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 4cf42b41e9..20f0cdccc3 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -20,7 +20,7 @@ #include "nvim/cursor.h" #include "nvim/diff.h" #include "nvim/edit.h" -#include "nvim/eval.h" +#include "nvim/eval/userfunc.h" #include "nvim/ex_cmds.h" #include "nvim/ex_docmd.h" #include "nvim/ex_eval.h" @@ -62,6 +62,11 @@ #define BUFSIZE 8192 /* size of normal write buffer */ #define SMBUFSIZE 256 /* size of emergency write buffer */ +// For compatibility with libuv < 1.20.0 (tested on 1.18.0) +#ifndef UV_FS_COPYFILE_FICLONE +#define UV_FS_COPYFILE_FICLONE 0 +#endif + // // The autocommands are stored in a list for each event. // Autocommands for the same pattern, that are consecutive, are joined @@ -407,11 +412,27 @@ readfile( if (newfile) { if (apply_autocmds_exarg(EVENT_BUFREADCMD, NULL, sfname, - FALSE, curbuf, eap)) - return aborting() ? FAIL : OK; + false, curbuf, eap)) { + int status = OK; + + if (aborting()) { + status = FAIL; + } + + // The BufReadCmd code usually uses ":read" to get the text and + // perhaps ":file" to change the buffer name. But we should + // consider this to work like ":edit", thus reset the + // BF_NOTEDITED flag. Then ":write" will work to overwrite the + // same file. + if (status == OK) { + curbuf->b_flags &= ~BF_NOTEDITED; + } + return status; + } } else if (apply_autocmds_exarg(EVENT_FILEREADCMD, sfname, sfname, - FALSE, NULL, eap)) + false, NULL, eap)) { return aborting() ? FAIL : OK; + } curbuf->b_op_start = pos; } @@ -548,20 +569,21 @@ readfile( return FAIL; } } - if (dir_of_file_exists(fname)) - filemess(curbuf, sfname, (char_u *)_("[New File]"), 0); - else - filemess(curbuf, sfname, - (char_u *)_("[New DIRECTORY]"), 0); - /* Even though this is a new file, it might have been - * edited before and deleted. Get the old marks. */ + if (dir_of_file_exists(fname)) { + filemess(curbuf, sfname, (char_u *)new_file_message(), 0); + } else { + filemess(curbuf, sfname, (char_u *)_("[New DIRECTORY]"), 0); + } + // Even though this is a new file, it might have been + // edited before and deleted. Get the old marks. check_marks_read(); - /* Set forced 'fileencoding'. */ - if (eap != NULL) + // Set forced 'fileencoding'. + if (eap != NULL) { set_forced_fenc(eap); + } apply_autocmds_exarg(EVENT_BUFNEWFILE, sfname, sfname, - FALSE, curbuf, eap); - /* remember the current fileformat */ + false, curbuf, eap); + // remember the current fileformat save_file_ff(curbuf); if (aborting()) /* autocmds may abort script processing */ @@ -2032,14 +2054,16 @@ readfile_linenr( * Fill "*eap" to force the 'fileencoding', 'fileformat' and 'binary to be * equal to the buffer "buf". Used for calling readfile(). */ -void prep_exarg(exarg_T *eap, buf_T *buf) +void prep_exarg(exarg_T *eap, const buf_T *buf) + FUNC_ATTR_NONNULL_ALL { - eap->cmd = xmalloc(STRLEN(buf->b_p_ff) + STRLEN(buf->b_p_fenc) + 15); + const size_t cmd_len = 15 + STRLEN(buf->b_p_fenc); + eap->cmd = xmalloc(cmd_len); - sprintf((char *)eap->cmd, "e ++ff=%s ++enc=%s", buf->b_p_ff, buf->b_p_fenc); - eap->force_enc = 14 + (int)STRLEN(buf->b_p_ff); + snprintf((char *)eap->cmd, cmd_len, "e ++enc=%s", buf->b_p_fenc); + eap->force_enc = 8; eap->bad_char = buf->b_bad_char; - eap->force_ff = 7; + eap->force_ff = *buf->b_p_ff; eap->force_bin = buf->b_p_bin ? FORCE_BIN : FORCE_NOBIN; eap->read_edit = FALSE; @@ -2180,6 +2204,11 @@ static void check_marks_read(void) curbuf->b_marks_read = true; } +char *new_file_message(void) +{ + return shortmess(SHM_NEW) ? _("[New]") : _("[New File]"); +} + /* * buf_write() - write to file "fname" lines "start" through "end" * @@ -2650,6 +2679,7 @@ buf_write( */ if (!(append && *p_pm == NUL) && !filtering && perm >= 0 && dobackup) { FileInfo file_info; + const bool no_prepend_dot = false; if ((bkc & BKC_YES) || append) { /* "yes" */ backup_copy = TRUE; @@ -2737,6 +2767,7 @@ buf_write( int some_error = false; char_u *dirp; char_u *rootname; + char_u *p; /* * Try to make the backup in each directory in the 'bdir' option. @@ -2756,6 +2787,17 @@ buf_write( * Isolate one directory name, using an entry in 'bdir'. */ (void)copy_option_part(&dirp, IObuff, IOSIZE, ","); + p = IObuff + STRLEN(IObuff); + if (after_pathsep((char *)IObuff, (char *)p) && p[-1] == p[-2]) { + // Ends with '//', Use Full path + if ((p = (char_u *)make_percent_swname((char *)IObuff, (char *)fname)) + != NULL) { + backup = (char_u *)modname((char *)p, (char *)backup_ext, + no_prepend_dot); + xfree(p); + } + } + rootname = get_file_in_dir(fname, IObuff); if (rootname == NULL) { some_error = TRUE; /* out of memory */ @@ -2764,10 +2806,14 @@ buf_write( FileInfo file_info_new; { - /* - * Make backup file name. - */ - backup = (char_u *)modname((char *)rootname, (char *)backup_ext, FALSE); + // + // Make the backup file name. + // + if (backup == NULL) { + backup = (char_u *)modname((char *)rootname, (char *)backup_ext, + no_prepend_dot); + } + if (backup == NULL) { xfree(rootname); some_error = TRUE; /* out of memory */ @@ -2893,12 +2939,26 @@ nobackup: * Isolate one directory name and make the backup file name. */ (void)copy_option_part(&dirp, IObuff, IOSIZE, ","); - rootname = get_file_in_dir(fname, IObuff); - if (rootname == NULL) - backup = NULL; - else { - backup = (char_u *)modname((char *)rootname, (char *)backup_ext, FALSE); - xfree(rootname); + p = IObuff + STRLEN(IObuff); + if (after_pathsep((char *)IObuff, (char *)p) && p[-1] == p[-2]) { + // path ends with '//', use full path + if ((p = (char_u *)make_percent_swname((char *)IObuff, (char *)fname)) + != NULL) { + backup = (char_u *)modname((char *)p, (char *)backup_ext, + no_prepend_dot); + xfree(p); + } + } + + if (backup == NULL) { + rootname = get_file_in_dir(fname, IObuff); + if (rootname == NULL) { + backup = NULL; + } else { + backup = (char_u *)modname((char *)rootname, (char *)backup_ext, + no_prepend_dot); + xfree(rootname); + } } if (backup != NULL) { @@ -3459,8 +3519,8 @@ restore_backup: STRCAT(IObuff, _("[Device]")); c = TRUE; } else if (newfile) { - STRCAT(IObuff, shortmess(SHM_NEW) ? _("[New]") : _("[New File]")); - c = TRUE; + STRCAT(IObuff, new_file_message()); + c = true; } if (no_eol) { msg_add_eol(); @@ -3700,8 +3760,9 @@ static int set_rw_fname(char_u *fname, char_u *sfname) return FAIL; } - if (setfname(curbuf, fname, sfname, FALSE) == OK) + if (setfname(curbuf, fname, sfname, false) == OK) { curbuf->b_flags |= BF_NOTEDITED; + } /* ....and a new named one is created */ apply_autocmds(EVENT_BUFNEW, NULL, NULL, FALSE, curbuf); @@ -4834,7 +4895,7 @@ buf_check_timestamp( if (buf->terminal || buf->b_ffname == NULL || buf->b_ml.ml_mfp == NULL - || *buf->b_p_bt != NUL + || !bt_normal(buf) || buf->b_saving || busy ) @@ -5328,7 +5389,7 @@ static bool vim_settempdir(char *tempdir) char_u *vim_tempname(void) { // Temp filename counter. - static uint32_t temp_count; + static uint64_t temp_count; char_u *tempdir = vim_gettempdir(); if (!tempdir) { @@ -5339,7 +5400,7 @@ char_u *vim_tempname(void) // and nobody else creates a file in it. char_u template[TEMP_FILE_PATH_MAXLEN]; snprintf((char *)template, TEMP_FILE_PATH_MAXLEN, - "%s%" PRIu32, tempdir, temp_count++); + "%s%" PRIu64, tempdir, temp_count++); return vim_strsave(template); } @@ -6555,7 +6616,7 @@ static int autocmd_nested = FALSE; /// Execute autocommands for "event" and file name "fname". /// -/// @param event event that occured +/// @param event event that occurred /// @param fname filename, NULL or empty means use actual file name /// @param fname_io filename to use for <afile> on cmdline /// @param force When true, ignore autocmd_busy @@ -6572,7 +6633,7 @@ bool apply_autocmds(event_T event, char_u *fname, char_u *fname_io, bool force, /// Like apply_autocmds(), but with extra "eap" argument. This takes care of /// setting v:filearg. /// -/// @param event event that occured +/// @param event event that occurred /// @param fname NULL or empty means use actual file name /// @param fname_io fname to use for <afile> on cmdline /// @param force When true, ignore autocmd_busy @@ -6592,7 +6653,7 @@ static bool apply_autocmds_exarg(event_T event, char_u *fname, char_u *fname_io, /// conditional, no autocommands are executed. If otherwise the autocommands /// cause the script to be aborted, retval is set to FAIL. /// -/// @param event event that occured +/// @param event event that occurred /// @param fname NULL or empty means use actual file name /// @param fname_io fname to use for <afile> on cmdline /// @param force When true, ignore autocmd_busy @@ -6652,7 +6713,7 @@ bool has_event(event_T event) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT /// Execute autocommands for "event" and file name "fname". /// -/// @param event event that occured +/// @param event event that occurred /// @param fname filename, NULL or empty means use actual file name /// @param fname_io filename to use for <afile> on cmdline, /// NULL means use `fname`. @@ -6681,7 +6742,6 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io, static int nesting = 0; AutoPatCmd patcmd; AutoPat *ap; - void *save_funccalp; char_u *save_cmdarg; long save_cmdbang; static int filechangeshell_busy = FALSE; @@ -6830,7 +6890,8 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io, || event == EVENT_SPELLFILEMISSING || event == EVENT_SYNTAX || event == EVENT_SIGNAL - || event == EVENT_TABCLOSED) { + || event == EVENT_TABCLOSED + || event == EVENT_WINCLOSED) { fname = vim_strsave(fname); } else { fname = (char_u *)FullName_save((char *)fname, false); @@ -6870,8 +6931,9 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io, if (do_profiling == PROF_YES) prof_child_enter(&wait_time); /* doesn't count for the caller itself */ - /* Don't use local function variables, if called from a function */ - save_funccalp = save_funccal(); + // Don't use local function variables, if called from a function. + funccal_entry_T funccal_entry; + save_funccal(&funccal_entry); /* * When starting to execute autocommands, save the search patterns. @@ -6960,9 +7022,10 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io, autocmd_bufnr = save_autocmd_bufnr; autocmd_match = save_autocmd_match; current_sctx = save_current_sctx; - restore_funccal(save_funccalp); - if (do_profiling == PROF_YES) + restore_funccal(); + if (do_profiling == PROF_YES) { prof_child_exit(&wait_time); + } KeyTyped = save_KeyTyped; xfree(fname); xfree(sfname); @@ -7100,12 +7163,10 @@ auto_next_pat( } } -/* - * Get next autocommand command. - * Called by do_cmdline() to get the next line for ":if". - * Returns allocated string, or NULL for end of autocommands. - */ -char_u *getnextac(int c, void *cookie, int indent) +/// Get next autocommand command. +/// Called by do_cmdline() to get the next line for ":if". +/// @return allocated string, or NULL for end of autocommands. +char_u *getnextac(int c, void *cookie, int indent, bool do_concat) { AutoPatCmd *acp = (AutoPatCmd *)cookie; char_u *retval; @@ -7166,8 +7227,8 @@ char_u *getnextac(int c, void *cookie, int indent) /// To account for buffer-local autocommands, function needs to know /// in which buffer the file will be opened. /// -/// @param event event that occured. -/// @param sfname filename the event occured in. +/// @param event event that occurred. +/// @param sfname filename the event occurred in. /// @param buf buffer the file is open in bool has_autocmd(event_T event, char_u *sfname, buf_T *buf) FUNC_ATTR_WARN_UNUSED_RESULT |