mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
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)
0a7984af56
In Nvim Test_checktime_fast() is also flaky. Add a delay to avoid that.
This commit is contained in:
parent
6f5fae08a3
commit
03348e5b9d
@ -587,7 +587,9 @@ struct file_buffer {
|
|||||||
// where invoked
|
// where invoked
|
||||||
|
|
||||||
long b_mtime; // last change time of original file
|
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; // 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
|
uint64_t b_orig_size; // size of original file in bytes
|
||||||
int b_orig_mode; // mode of original file
|
int b_orig_mode; // mode of original file
|
||||||
time_t b_last_used; // time when the buffer was last used; used
|
time_t b_last_used; // time when the buffer was last used; used
|
||||||
|
@ -4539,6 +4539,7 @@ static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||||||
"mouse",
|
"mouse",
|
||||||
"multi_byte",
|
"multi_byte",
|
||||||
"multi_lang",
|
"multi_lang",
|
||||||
|
"nanotime",
|
||||||
"num64",
|
"num64",
|
||||||
"packages",
|
"packages",
|
||||||
"path_extra",
|
"path_extra",
|
||||||
|
@ -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)) {
|
if (os_fileinfo((char *)fname, &file_info)) {
|
||||||
buf_store_file_info(curbuf, &file_info);
|
buf_store_file_info(curbuf, &file_info);
|
||||||
curbuf->b_mtime_read = curbuf->b_mtime;
|
curbuf->b_mtime_read = curbuf->b_mtime;
|
||||||
|
curbuf->b_mtime_read_ns = curbuf->b_mtime_ns;
|
||||||
#ifdef UNIX
|
#ifdef UNIX
|
||||||
/*
|
/*
|
||||||
* Use the protection bits of the original file for the swap file.
|
* 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
|
#endif
|
||||||
} else {
|
} else {
|
||||||
curbuf->b_mtime = 0;
|
curbuf->b_mtime = 0;
|
||||||
|
curbuf->b_mtime_ns = 0;
|
||||||
curbuf->b_mtime_read = 0;
|
curbuf->b_mtime_read = 0;
|
||||||
|
curbuf->b_mtime_read_ns = 0;
|
||||||
curbuf->b_orig_size = 0;
|
curbuf->b_orig_size = 0;
|
||||||
curbuf->b_orig_mode = 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!"),
|
msg_puts_attr(_("don't quit the editor until the file is successfully written!"),
|
||||||
attr | MSG_HIST);
|
attr | MSG_HIST);
|
||||||
|
|
||||||
/* Update the timestamp to avoid an "overwrite changed file"
|
// Update the timestamp to avoid an "overwrite changed file"
|
||||||
* prompt when writing again. */
|
// prompt when writing again.
|
||||||
if (os_fileinfo((char *)fname, &file_info_old)) {
|
if (os_fileinfo((char *)fname, &file_info_old)) {
|
||||||
buf_store_file_info(buf, &file_info_old);
|
buf_store_file_info(buf, &file_info_old);
|
||||||
buf->b_mtime_read = buf->b_mtime;
|
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)
|
static int check_mtime(buf_T *buf, FileInfo *file_info)
|
||||||
{
|
{
|
||||||
if (buf->b_mtime_read != 0
|
if (buf->b_mtime_read != 0
|
||||||
&& time_differs(file_info->stat.st_mtim.tv_sec,
|
&& time_differs(file_info, buf->b_mtime_read, buf->b_mtime_read_ns)) {
|
||||||
buf->b_mtime_read)) {
|
|
||||||
msg_scroll = true; // Don't overwrite messages here.
|
msg_scroll = true; // Don't overwrite messages here.
|
||||||
msg_silent = 0; // Must give this prompt.
|
msg_silent = 0; // Must give this prompt.
|
||||||
// Don't use emsg() here, don't want to flush the buffers.
|
// 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 OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return true if the times differ
|
static bool time_differs(const FileInfo *file_info, long mtime, long mtime_ns) FUNC_ATTR_CONST
|
||||||
///
|
|
||||||
/// @param t1 first time
|
|
||||||
/// @param t2 second time
|
|
||||||
static bool time_differs(long t1, long t2) FUNC_ATTR_CONST
|
|
||||||
{
|
{
|
||||||
#if defined(__linux__) || defined(MSWIN)
|
#if defined(__linux__) || defined(MSWIN)
|
||||||
// On a FAT filesystem, esp. under Linux, there are only 5 bits to store
|
// 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
|
// the seconds. Since the roundoff is done when flushing the inode, the
|
||||||
// time may change unexpectedly by one second!!!
|
// 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
|
#else
|
||||||
return t1 != t2;
|
return (long)file_info->stat.st_mtim.tv_sec != mtime;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4943,7 +4944,7 @@ int buf_check_timestamp(buf_T *buf)
|
|||||||
if (!(buf->b_flags & BF_NOTEDITED)
|
if (!(buf->b_flags & BF_NOTEDITED)
|
||||||
&& buf->b_mtime != 0
|
&& buf->b_mtime != 0
|
||||||
&& (!(file_info_ok = os_fileinfo((char *)buf->b_ffname, &file_info))
|
&& (!(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)) {
|
|| (int)file_info.stat.st_mode != buf->b_orig_mode)) {
|
||||||
const long prev_b_mtime = buf->b_mtime;
|
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
|
// Only timestamp changed, store it to avoid a warning
|
||||||
// in check_mtime() later.
|
// in check_mtime() later.
|
||||||
buf->b_mtime_read = buf->b_mtime;
|
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
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
buf->b_mtime = file_info->stat.st_mtim.tv_sec;
|
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_size = os_fileinfo_size(file_info);
|
||||||
buf->b_orig_mode = (int)file_info->stat.st_mode;
|
buf->b_orig_mode = (int)file_info->stat.st_mode;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
long_to_char((long)os_fileinfo_inode(&file_info), b0p->b0_ino);
|
||||||
buf_store_file_info(buf, &file_info);
|
buf_store_file_info(buf, &file_info);
|
||||||
buf->b_mtime_read = buf->b_mtime;
|
buf->b_mtime_read = buf->b_mtime;
|
||||||
|
buf->b_mtime_read_ns = buf->b_mtime_ns;
|
||||||
} else {
|
} else {
|
||||||
long_to_char(0L, b0p->b0_mtime);
|
long_to_char(0L, b0p->b0_mtime);
|
||||||
long_to_char(0L, b0p->b0_ino);
|
long_to_char(0L, b0p->b0_ino);
|
||||||
buf->b_mtime = 0;
|
buf->b_mtime = 0;
|
||||||
|
buf->b_mtime_ns = 0;
|
||||||
buf->b_mtime_read = 0;
|
buf->b_mtime_read = 0;
|
||||||
|
buf->b_mtime_read_ns = 0;
|
||||||
buf->b_orig_size = 0;
|
buf->b_orig_size = 0;
|
||||||
buf->b_orig_mode = 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;
|
FileInfo file_info;
|
||||||
if (!os_fileinfo((char *)buf->b_ffname, &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_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) {
|
|| os_fileinfo_size(&file_info) != buf->b_orig_size) {
|
||||||
ml_preserve(buf, false, do_fsync);
|
ml_preserve(buf, false, do_fsync);
|
||||||
did_check_timestamps = false;
|
did_check_timestamps = false;
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
" Tests for stat functions and checktime
|
" Tests for stat functions and checktime
|
||||||
|
|
||||||
|
source check.vim
|
||||||
|
|
||||||
func CheckFileTime(doSleep)
|
func CheckFileTime(doSleep)
|
||||||
let fnames = ['Xtest1.tmp', 'Xtest2.tmp', 'Xtest3.tmp']
|
let fnames = ['Xtest1.tmp', 'Xtest2.tmp', 'Xtest3.tmp']
|
||||||
let times = []
|
let times = []
|
||||||
@ -74,6 +76,40 @@ func Test_checktime()
|
|||||||
call delete(fname)
|
call delete(fname)
|
||||||
endfunc
|
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()
|
func Test_autoread_file_deleted()
|
||||||
new Xautoread
|
new Xautoread
|
||||||
set autoread
|
set autoread
|
||||||
|
Loading…
Reference in New Issue
Block a user