mirror of
https://github.com/vim/vim.git
synced 2025-09-26 04:04:07 -04:00
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 #8873, closes #8875)
This commit is contained in:
committed by
Bram Moolenaar
parent
340dd0fbe4
commit
0a7984af56
@@ -12236,6 +12236,7 @@ multi_byte_encoding 'encoding' is set to a multibyte encoding.
|
|||||||
multi_byte_ime Compiled with support for IME input method.
|
multi_byte_ime Compiled with support for IME input method.
|
||||||
multi_lang Compiled with support for multiple languages.
|
multi_lang Compiled with support for multiple languages.
|
||||||
mzscheme Compiled with MzScheme interface |mzscheme|.
|
mzscheme Compiled with MzScheme interface |mzscheme|.
|
||||||
|
nanotime Compiled with sub-second time stamp checks.
|
||||||
netbeans_enabled Compiled with support for |netbeans| and connected.
|
netbeans_enabled Compiled with support for |netbeans| and connected.
|
||||||
netbeans_intg Compiled with support for |netbeans|.
|
netbeans_intg Compiled with support for |netbeans|.
|
||||||
num64 Compiled with 64-bit |Number| support.
|
num64 Compiled with 64-bit |Number| support.
|
||||||
|
46
src/auto/configure
vendored
46
src/auto/configure
vendored
@@ -13149,6 +13149,52 @@ if test "x$vim_cv_stat_ignores_slash" = "xyes" ; then
|
|||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for nanoseconds field of struct stat" >&5
|
||||||
|
$as_echo_n "checking for nanoseconds field of struct stat... " >&6; }
|
||||||
|
if ${ac_cv_struct_st_mtim_nsec+:} false; then :
|
||||||
|
$as_echo_n "(cached) " >&6
|
||||||
|
else
|
||||||
|
ac_save_CPPFLAGS="$CPPFLAGS"
|
||||||
|
ac_cv_struct_st_mtim_nsec=no
|
||||||
|
# st_mtim.tv_nsec -- the usual case
|
||||||
|
# st_mtim._tv_nsec -- Solaris 2.6, if
|
||||||
|
# (defined _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED == 1
|
||||||
|
# && !defined __EXTENSIONS__)
|
||||||
|
# st_mtim.st__tim.tv_nsec -- UnixWare 2.1.2
|
||||||
|
# st_mtime_n -- AIX 5.2 and above
|
||||||
|
# st_mtimespec.tv_nsec -- Darwin (Mac OSX)
|
||||||
|
for ac_val in st_mtim.tv_nsec st_mtim._tv_nsec st_mtim.st__tim.tv_nsec st_mtime_n st_mtimespec.tv_nsec; do
|
||||||
|
CPPFLAGS="$ac_save_CPPFLAGS -DST_MTIM_NSEC=$ac_val"
|
||||||
|
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||||
|
/* end confdefs.h. */
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
int
|
||||||
|
main ()
|
||||||
|
{
|
||||||
|
struct stat s; s.ST_MTIM_NSEC;
|
||||||
|
;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
_ACEOF
|
||||||
|
if ac_fn_c_try_compile "$LINENO"; then :
|
||||||
|
ac_cv_struct_st_mtim_nsec=$ac_val; break
|
||||||
|
fi
|
||||||
|
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||||
|
done
|
||||||
|
CPPFLAGS="$ac_save_CPPFLAGS"
|
||||||
|
|
||||||
|
fi
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_st_mtim_nsec" >&5
|
||||||
|
$as_echo "$ac_cv_struct_st_mtim_nsec" >&6; }
|
||||||
|
if test $ac_cv_struct_st_mtim_nsec != no; then
|
||||||
|
|
||||||
|
cat >>confdefs.h <<_ACEOF
|
||||||
|
#define ST_MTIM_NSEC $ac_cv_struct_st_mtim_nsec
|
||||||
|
_ACEOF
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv_open()" >&5
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv_open()" >&5
|
||||||
$as_echo_n "checking for iconv_open()... " >&6; }
|
$as_echo_n "checking for iconv_open()... " >&6; }
|
||||||
save_LIBS="$LIBS"
|
save_LIBS="$LIBS"
|
||||||
|
@@ -527,7 +527,7 @@ buf_write_bytes(struct bw_info *ip)
|
|||||||
check_mtime(buf_T *buf, stat_T *st)
|
check_mtime(buf_T *buf, stat_T *st)
|
||||||
{
|
{
|
||||||
if (buf->b_mtime_read != 0
|
if (buf->b_mtime_read != 0
|
||||||
&& time_differs((long)st->st_mtime, buf->b_mtime_read))
|
&& time_differs(st, buf->b_mtime_read, buf->b_mtime_read_ns))
|
||||||
{
|
{
|
||||||
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
|
||||||
@@ -2558,6 +2558,7 @@ nofail:
|
|||||||
{
|
{
|
||||||
buf_store_time(buf, &st_old, fname);
|
buf_store_time(buf, &st_old, fname);
|
||||||
buf->b_mtime_read = buf->b_mtime;
|
buf->b_mtime_read = buf->b_mtime;
|
||||||
|
buf->b_mtime_read_ns = buf->b_mtime_ns;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -144,6 +144,9 @@
|
|||||||
/* Define if stat() ignores a trailing slash */
|
/* Define if stat() ignores a trailing slash */
|
||||||
#undef STAT_IGNORES_SLASH
|
#undef STAT_IGNORES_SLASH
|
||||||
|
|
||||||
|
/* Define to nanoseconds field of struct stat */
|
||||||
|
#undef ST_MTIM_NSEC
|
||||||
|
|
||||||
/* Define if tgetstr() has a second argument that is (char *) */
|
/* Define if tgetstr() has a second argument that is (char *) */
|
||||||
#undef TGETSTR_CHAR_P
|
#undef TGETSTR_CHAR_P
|
||||||
|
|
||||||
|
@@ -3843,6 +3843,31 @@ main() {struct stat st; exit(stat("configure/", &st) != 0); }
|
|||||||
if test "x$vim_cv_stat_ignores_slash" = "xyes" ; then
|
if test "x$vim_cv_stat_ignores_slash" = "xyes" ; then
|
||||||
AC_DEFINE(STAT_IGNORES_SLASH)
|
AC_DEFINE(STAT_IGNORES_SLASH)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
dnl nanoseconds field of struct stat
|
||||||
|
AC_CACHE_CHECK([for nanoseconds field of struct stat],
|
||||||
|
ac_cv_struct_st_mtim_nsec,
|
||||||
|
[ac_save_CPPFLAGS="$CPPFLAGS"
|
||||||
|
ac_cv_struct_st_mtim_nsec=no
|
||||||
|
# st_mtim.tv_nsec -- the usual case
|
||||||
|
# st_mtim._tv_nsec -- Solaris 2.6, if
|
||||||
|
# (defined _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED == 1
|
||||||
|
# && !defined __EXTENSIONS__)
|
||||||
|
# st_mtim.st__tim.tv_nsec -- UnixWare 2.1.2
|
||||||
|
# st_mtime_n -- AIX 5.2 and above
|
||||||
|
# st_mtimespec.tv_nsec -- Darwin (Mac OSX)
|
||||||
|
for ac_val in st_mtim.tv_nsec st_mtim._tv_nsec st_mtim.st__tim.tv_nsec st_mtime_n st_mtimespec.tv_nsec; do
|
||||||
|
CPPFLAGS="$ac_save_CPPFLAGS -DST_MTIM_NSEC=$ac_val"
|
||||||
|
AC_TRY_COMPILE([#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>], [struct stat s; s.ST_MTIM_NSEC;],
|
||||||
|
[ac_cv_struct_st_mtim_nsec=$ac_val; break])
|
||||||
|
done
|
||||||
|
CPPFLAGS="$ac_save_CPPFLAGS"
|
||||||
|
])
|
||||||
|
if test $ac_cv_struct_st_mtim_nsec != no; then
|
||||||
|
AC_DEFINE_UNQUOTED([ST_MTIM_NSEC], [$ac_cv_struct_st_mtim_nsec],
|
||||||
|
[Define if struct stat contains a nanoseconds field])
|
||||||
|
fi
|
||||||
|
|
||||||
dnl Link with iconv for charset translation, if not found without library.
|
dnl Link with iconv for charset translation, if not found without library.
|
||||||
dnl check for iconv() requires including iconv.h
|
dnl check for iconv() requires including iconv.h
|
||||||
|
@@ -5479,6 +5479,13 @@ f_has(typval_T *argvars, typval_T *rettv)
|
|||||||
0
|
0
|
||||||
#endif
|
#endif
|
||||||
},
|
},
|
||||||
|
{"nanotime",
|
||||||
|
#ifdef ST_MTIM_NSEC
|
||||||
|
1
|
||||||
|
#else
|
||||||
|
0
|
||||||
|
#endif
|
||||||
|
},
|
||||||
{"num64", 1},
|
{"num64", 1},
|
||||||
{"ole",
|
{"ole",
|
||||||
#ifdef FEAT_OLE
|
#ifdef FEAT_OLE
|
||||||
|
24
src/fileio.c
24
src/fileio.c
@@ -408,6 +408,7 @@ readfile(
|
|||||||
{
|
{
|
||||||
buf_store_time(curbuf, &st, fname);
|
buf_store_time(curbuf, &st, fname);
|
||||||
curbuf->b_mtime_read = curbuf->b_mtime;
|
curbuf->b_mtime_read = curbuf->b_mtime;
|
||||||
|
curbuf->b_mtime_read_ns = curbuf->b_mtime_ns;
|
||||||
filesize_disk = st.st_size;
|
filesize_disk = st.st_size;
|
||||||
#ifdef UNIX
|
#ifdef UNIX
|
||||||
/*
|
/*
|
||||||
@@ -432,7 +433,9 @@ readfile(
|
|||||||
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;
|
||||||
}
|
}
|
||||||
@@ -2569,6 +2572,7 @@ failed:
|
|||||||
{
|
{
|
||||||
buf_store_time(curbuf, &st, fname);
|
buf_store_time(curbuf, &st, fname);
|
||||||
curbuf->b_mtime_read = curbuf->b_mtime;
|
curbuf->b_mtime_read = curbuf->b_mtime;
|
||||||
|
curbuf->b_mtime_read_ns = curbuf->b_mtime_ns;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -3115,15 +3119,19 @@ msg_add_eol(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
time_differs(long t1, long t2)
|
time_differs(stat_T *st, long mtime, long mtime_ns UNUSED)
|
||||||
{
|
{
|
||||||
#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)st->st_mtime - mtime > 1 || mtime - (long)st->st_mtime > 1
|
||||||
|
# ifdef ST_MTIM_NSEC
|
||||||
|
|| (long)st->ST_MTIM_NSEC != mtime_ns
|
||||||
|
# endif
|
||||||
|
;
|
||||||
#else
|
#else
|
||||||
return (t1 != t2);
|
return (long)st->st_mtime != mtime;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4072,7 +4080,7 @@ buf_check_timestamp(
|
|||||||
if ( !(buf->b_flags & BF_NOTEDITED)
|
if ( !(buf->b_flags & BF_NOTEDITED)
|
||||||
&& buf->b_mtime != 0
|
&& buf->b_mtime != 0
|
||||||
&& ((stat_res = mch_stat((char *)buf->b_ffname, &st)) < 0
|
&& ((stat_res = mch_stat((char *)buf->b_ffname, &st)) < 0
|
||||||
|| time_differs((long)st.st_mtime, buf->b_mtime)
|
|| time_differs(&st, buf->b_mtime, buf->b_mtime_ns)
|
||||||
|| st.st_size != buf->b_orig_size
|
|| st.st_size != buf->b_orig_size
|
||||||
#ifdef HAVE_ST_MODE
|
#ifdef HAVE_ST_MODE
|
||||||
|| (int)st.st_mode != buf->b_orig_mode
|
|| (int)st.st_mode != buf->b_orig_mode
|
||||||
@@ -4187,9 +4195,12 @@ buf_check_timestamp(
|
|||||||
mesg2 = _("See \":help W16\" for more info.");
|
mesg2 = _("See \":help W16\" for more info.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
// 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4468,6 +4479,11 @@ buf_reload(buf_T *buf, int orig_mode)
|
|||||||
buf_store_time(buf_T *buf, stat_T *st, char_u *fname UNUSED)
|
buf_store_time(buf_T *buf, stat_T *st, char_u *fname UNUSED)
|
||||||
{
|
{
|
||||||
buf->b_mtime = (long)st->st_mtime;
|
buf->b_mtime = (long)st->st_mtime;
|
||||||
|
#ifdef ST_MTIM_NSEC
|
||||||
|
buf->b_mtime_ns = (long)st->ST_MTIM_NSEC;
|
||||||
|
#else
|
||||||
|
buf->b_mtime_ns = 0;
|
||||||
|
#endif
|
||||||
buf->b_orig_size = st->st_size;
|
buf->b_orig_size = st->st_size;
|
||||||
#ifdef HAVE_ST_MODE
|
#ifdef HAVE_ST_MODE
|
||||||
buf->b_orig_mode = (int)st->st_mode;
|
buf->b_orig_mode = (int)st->st_mode;
|
||||||
|
@@ -1032,6 +1032,7 @@ set_b0_fname(ZERO_BL *b0p, buf_T *buf)
|
|||||||
#endif
|
#endif
|
||||||
buf_store_time(buf, &st, buf->b_ffname);
|
buf_store_time(buf, &st, buf->b_ffname);
|
||||||
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
|
||||||
{
|
{
|
||||||
@@ -1040,7 +1041,9 @@ set_b0_fname(ZERO_BL *b0p, buf_T *buf)
|
|||||||
long_to_char(0L, b0p->b0_ino);
|
long_to_char(0L, b0p->b0_ino);
|
||||||
#endif
|
#endif
|
||||||
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;
|
||||||
}
|
}
|
||||||
@@ -2436,6 +2439,9 @@ ml_sync_all(int check_file, int check_char)
|
|||||||
*/
|
*/
|
||||||
if (mch_stat((char *)buf->b_ffname, &st) == -1
|
if (mch_stat((char *)buf->b_ffname, &st) == -1
|
||||||
|| st.st_mtime != buf->b_mtime_read
|
|| st.st_mtime != buf->b_mtime_read
|
||||||
|
#ifdef ST_MTIM_NSEC
|
||||||
|
|| st.ST_MTIM_NSEC != buf->b_mtime_read_ns
|
||||||
|
#endif
|
||||||
|| st.st_size != buf->b_orig_size)
|
|| st.st_size != buf->b_orig_size)
|
||||||
{
|
{
|
||||||
ml_preserve(buf, FALSE);
|
ml_preserve(buf, FALSE);
|
||||||
|
@@ -1760,7 +1760,10 @@ nb_do_cmd(
|
|||||||
if (buf == NULL || buf->bufp == NULL)
|
if (buf == NULL || buf->bufp == NULL)
|
||||||
nbdebug((" invalid buffer identifier in setModtime\n"));
|
nbdebug((" invalid buffer identifier in setModtime\n"));
|
||||||
else
|
else
|
||||||
|
{
|
||||||
buf->bufp->b_mtime = atoi((char *)args);
|
buf->bufp->b_mtime = atoi((char *)args);
|
||||||
|
buf->bufp->b_mtime_ns = 0;
|
||||||
|
}
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
}
|
}
|
||||||
else if (streq((char *)cmd, "setReadOnly"))
|
else if (streq((char *)cmd, "setReadOnly"))
|
||||||
|
@@ -12,7 +12,7 @@ void msg_add_fname(buf_T *buf, char_u *fname);
|
|||||||
int msg_add_fileformat(int eol_type);
|
int msg_add_fileformat(int eol_type);
|
||||||
void msg_add_lines(int insert_space, long lnum, off_T nchars);
|
void msg_add_lines(int insert_space, long lnum, off_T nchars);
|
||||||
void msg_add_eol(void);
|
void msg_add_eol(void);
|
||||||
int time_differs(long t1, long t2);
|
int time_differs(stat_T *st, long mtime, long mtime_ns);
|
||||||
int need_conversion(char_u *fenc);
|
int need_conversion(char_u *fenc);
|
||||||
int get_fio_flags(char_u *ptr);
|
int get_fio_flags(char_u *ptr);
|
||||||
int get_win_fio_flags(char_u *ptr);
|
int get_win_fio_flags(char_u *ptr);
|
||||||
|
@@ -2724,7 +2724,9 @@ struct file_buffer
|
|||||||
wininfo_T *b_wininfo; // list of last used info for each window
|
wininfo_T *b_wininfo; // list of last used info for each window
|
||||||
|
|
||||||
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
|
||||||
off_T b_orig_size; // size of original file in bytes
|
off_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
|
||||||
#ifdef FEAT_VIMINFO
|
#ifdef FEAT_VIMINFO
|
||||||
|
@@ -76,6 +76,39 @@ 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'
|
||||||
|
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
|
||||||
|
@@ -757,6 +757,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
3510,
|
||||||
/**/
|
/**/
|
||||||
3509,
|
3509,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user