aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2022-02-13 21:33:28 +0800
committerzeertzjq <zeertzjq@outlook.com>2022-02-13 21:33:28 +0800
commit03348e5b9db3f057057a70581ef71180c3cb6527 (patch)
treee7a169e48a0a2a06e4cdd0ee0470aeaebbb6ecca
parent6f5fae08a302bce6de453425a6b1c1d851112914 (diff)
downloadrneovim-03348e5b9db3f057057a70581ef71180c3cb6527.tar.gz
rneovim-03348e5b9db3f057057a70581ef71180c3cb6527.tar.bz2
rneovim-03348e5b9db3f057057a70581ef71180c3cb6527.zip
vim-patch:8.2.3510: changes are only detected with one second accuracy
Problem: Changes are only detected with one second accuracy. Solution: Use the nanosecond time if possible. (Leah Neukirchen, closes vim/vim#8873, closes vim/vim#8875) https://github.com/vim/vim/commit/0a7984af5601323fae7b3398f05a48087db7b767 In Nvim Test_checktime_fast() is also flaky. Add a delay to avoid that.
-rw-r--r--src/nvim/buffer_defs.h2
-rw-r--r--src/nvim/eval/funcs.c1
-rw-r--r--src/nvim/fileio.c27
-rw-r--r--src/nvim/memline.c4
-rw-r--r--src/nvim/testdir/test_stat.vim36
5 files changed, 58 insertions, 12 deletions
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 7b17c5b506..7ae5df164f 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -587,7 +587,9 @@ struct file_buffer {
// where invoked
long b_mtime; // last change time of original file
+ long b_mtime_ns; // nanoseconds of last change time
long b_mtime_read; // last change time when reading
+ long b_mtime_read_ns; // nanoseconds of last read time
uint64_t b_orig_size; // size of original file in bytes
int b_orig_mode; // mode of original file
time_t b_last_used; // time when the buffer was last used; used
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 7772d9ffc2..c6baa105b0 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -4539,6 +4539,7 @@ static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr)
"mouse",
"multi_byte",
"multi_lang",
+ "nanotime",
"num64",
"packages",
"path_extra",
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 8e1be3bbf7..475b44bc49 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -405,6 +405,7 @@ int readfile(char_u *fname, char_u *sfname, linenr_T from, linenr_T lines_to_ski
if (os_fileinfo((char *)fname, &file_info)) {
buf_store_file_info(curbuf, &file_info);
curbuf->b_mtime_read = curbuf->b_mtime;
+ curbuf->b_mtime_read_ns = curbuf->b_mtime_ns;
#ifdef UNIX
/*
* Use the protection bits of the original file for the swap file.
@@ -421,7 +422,9 @@ int readfile(char_u *fname, char_u *sfname, linenr_T from, linenr_T lines_to_ski
#endif
} else {
curbuf->b_mtime = 0;
+ curbuf->b_mtime_ns = 0;
curbuf->b_mtime_read = 0;
+ curbuf->b_mtime_read_ns = 0;
curbuf->b_orig_size = 0;
curbuf->b_orig_mode = 0;
}
@@ -3695,11 +3698,12 @@ nofail:
msg_puts_attr(_("don't quit the editor until the file is successfully written!"),
attr | MSG_HIST);
- /* Update the timestamp to avoid an "overwrite changed file"
- * prompt when writing again. */
+ // Update the timestamp to avoid an "overwrite changed file"
+ // prompt when writing again.
if (os_fileinfo((char *)fname, &file_info_old)) {
buf_store_file_info(buf, &file_info_old);
buf->b_mtime_read = buf->b_mtime;
+ buf->b_mtime_read_ns = buf->b_mtime_ns;
}
}
}
@@ -3893,8 +3897,7 @@ static void msg_add_eol(void)
static int check_mtime(buf_T *buf, FileInfo *file_info)
{
if (buf->b_mtime_read != 0
- && time_differs(file_info->stat.st_mtim.tv_sec,
- buf->b_mtime_read)) {
+ && time_differs(file_info, buf->b_mtime_read, buf->b_mtime_read_ns)) {
msg_scroll = true; // Don't overwrite messages here.
msg_silent = 0; // Must give this prompt.
// Don't use emsg() here, don't want to flush the buffers.
@@ -3908,19 +3911,17 @@ static int check_mtime(buf_T *buf, FileInfo *file_info)
return OK;
}
-/// Return true if the times differ
-///
-/// @param t1 first time
-/// @param t2 second time
-static bool time_differs(long t1, long t2) FUNC_ATTR_CONST
+static bool time_differs(const FileInfo *file_info, long mtime, long mtime_ns) FUNC_ATTR_CONST
{
#if defined(__linux__) || defined(MSWIN)
// On a FAT filesystem, esp. under Linux, there are only 5 bits to store
// the seconds. Since the roundoff is done when flushing the inode, the
// time may change unexpectedly by one second!!!
- return t1 - t2 > 1 || t2 - t1 > 1;
+ return (long)file_info->stat.st_mtim.tv_sec - mtime > 1
+ || mtime - (long)file_info->stat.st_mtim.tv_sec > 1
+ || (long)file_info->stat.st_mtim.tv_nsec != mtime_ns;
#else
- return t1 != t2;
+ return (long)file_info->stat.st_mtim.tv_sec != mtime;
#endif
}
@@ -4943,7 +4944,7 @@ int buf_check_timestamp(buf_T *buf)
if (!(buf->b_flags & BF_NOTEDITED)
&& buf->b_mtime != 0
&& (!(file_info_ok = os_fileinfo((char *)buf->b_ffname, &file_info))
- || time_differs(file_info.stat.st_mtim.tv_sec, buf->b_mtime)
+ || time_differs(&file_info, buf->b_mtime, buf->b_mtime_ns)
|| (int)file_info.stat.st_mode != buf->b_orig_mode)) {
const long prev_b_mtime = buf->b_mtime;
@@ -5034,6 +5035,7 @@ int buf_check_timestamp(buf_T *buf)
// Only timestamp changed, store it to avoid a warning
// in check_mtime() later.
buf->b_mtime_read = buf->b_mtime;
+ buf->b_mtime_read_ns = buf->b_mtime_ns;
}
}
}
@@ -5262,6 +5264,7 @@ void buf_store_file_info(buf_T *buf, FileInfo *file_info)
FUNC_ATTR_NONNULL_ALL
{
buf->b_mtime = file_info->stat.st_mtim.tv_sec;
+ buf->b_mtime_ns = file_info->stat.st_mtim.tv_nsec;
buf->b_orig_size = os_fileinfo_size(file_info);
buf->b_orig_mode = (int)file_info->stat.st_mode;
}
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index 9925971783..004ef36b36 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -704,11 +704,14 @@ static void set_b0_fname(ZERO_BL *b0p, buf_T *buf)
long_to_char((long)os_fileinfo_inode(&file_info), b0p->b0_ino);
buf_store_file_info(buf, &file_info);
buf->b_mtime_read = buf->b_mtime;
+ buf->b_mtime_read_ns = buf->b_mtime_ns;
} else {
long_to_char(0L, b0p->b0_mtime);
long_to_char(0L, b0p->b0_ino);
buf->b_mtime = 0;
+ buf->b_mtime_ns = 0;
buf->b_mtime_read = 0;
+ buf->b_mtime_read_ns = 0;
buf->b_orig_size = 0;
buf->b_orig_mode = 0;
}
@@ -1720,6 +1723,7 @@ void ml_sync_all(int check_file, int check_char, bool do_fsync)
FileInfo file_info;
if (!os_fileinfo((char *)buf->b_ffname, &file_info)
|| file_info.stat.st_mtim.tv_sec != buf->b_mtime_read
+ || file_info.stat.st_mtim.tv_nsec != buf->b_mtime_read_ns
|| os_fileinfo_size(&file_info) != buf->b_orig_size) {
ml_preserve(buf, false, do_fsync);
did_check_timestamps = false;
diff --git a/src/nvim/testdir/test_stat.vim b/src/nvim/testdir/test_stat.vim
index 170358e023..a6fe31b85a 100644
--- a/src/nvim/testdir/test_stat.vim
+++ b/src/nvim/testdir/test_stat.vim
@@ -1,5 +1,7 @@
" Tests for stat functions and checktime
+source check.vim
+
func CheckFileTime(doSleep)
let fnames = ['Xtest1.tmp', 'Xtest2.tmp', 'Xtest3.tmp']
let times = []
@@ -74,6 +76,40 @@ func Test_checktime()
call delete(fname)
endfunc
+func Test_checktime_fast()
+ CheckFeature nanotime
+
+ let fname = 'Xtest.tmp'
+
+ let fl = ['Hello World!']
+ call writefile(fl, fname)
+ set autoread
+ exec 'e' fname
+ let fl = readfile(fname)
+ let fl[0] .= ' - checktime'
+ sleep 10m " make test less flaky in Nvim
+ call writefile(fl, fname)
+ checktime
+ call assert_equal(fl[0], getline(1))
+
+ call delete(fname)
+endfunc
+
+func Test_autoread_fast()
+ CheckFeature nanotime
+
+ new Xautoread
+ set autoread
+ call setline(1, 'foo')
+
+ w!
+ silent !echo bar > Xautoread
+ checktime
+
+ call assert_equal('bar', trim(getline(1)))
+ call delete('Xautoread')
+endfunc
+
func Test_autoread_file_deleted()
new Xautoread
set autoread