To: vim_dev@googlegroups.com Subject: Patch 8.2.5057 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.5057 Problem: Using gettimeofday() for timeout is very inefficient. Solution: Set a platform dependent timer. (Paul Ollis, closes #10505) Files: src/auto/configure, src/config.h.in, src/configure.ac, src/drawscreen.c, src/errors.h, src/evalfunc.c, src/ex_cmds.c, src/ex_getln.c, src/match.c, src/os_mac.h, src/os_macosx.m, src/os_unix.c, src/os_win32.c, src/proto/os_unix.pro, src/proto/os_win32.pro, src/proto/regexp.pro, src/quickfix.c, src/regexp.c, src/regexp.h, src/regexp_bt.c, src/regexp_nfa.c, src/screen.c, src/search.c, src/structs.h, src/syntax.c, src/testdir/test_hlsearch.vim, src/testdir/test_search.vim, src/testdir/test_syntax.vim *** ../vim-8.2.5056/src/auto/configure 2022-04-04 17:19:57.139569576 +0100 --- src/auto/configure 2022-06-05 16:45:10.470696162 +0100 *************** *** 762,768 **** docdir oldincludedir includedir - runstatedir localstatedir sharedstatedir sysconfdir --- 762,767 ---- *************** *** 898,904 **** sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' - runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE}' --- 897,902 ---- *************** *** 1151,1165 **** | -silent | --silent | --silen | --sile | --sil) silent=yes ;; - -runstatedir | --runstatedir | --runstatedi | --runstated \ - | --runstate | --runstat | --runsta | --runst | --runs \ - | --run | --ru | --r) - ac_prev=runstatedir ;; - -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ - | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ - | --run=* | --ru=* | --r=*) - runstatedir=$ac_optarg ;; - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ --- 1149,1154 ---- *************** *** 1297,1303 **** for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ ! libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. --- 1286,1292 ---- for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ ! libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. *************** *** 1450,1456 **** --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --- 1439,1444 ---- *************** *** 12737,12743 **** We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ ! #define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; --- 12725,12731 ---- We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ ! #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; *************** *** 12783,12789 **** We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ ! #define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; --- 12771,12777 ---- We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ ! #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; *************** *** 12807,12813 **** We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ ! #define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; --- 12795,12801 ---- We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ ! #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; *************** *** 12852,12858 **** We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ ! #define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; --- 12840,12846 ---- We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ ! #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; *************** *** 12876,12882 **** We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ ! #define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; --- 12864,12870 ---- We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ ! #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; *************** *** 13080,13085 **** --- 13068,13143 ---- fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for timer_create" >&5 + $as_echo_n "checking for timer_create... " >&6; } + save_LIBS="$LIBS" + LIBS="$LIBS -lrt" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include + #include + static void set_flag(union sigval) {} + + int + main () + { + + struct timespec ts; + struct sigevent action = {0}; + timer_t timer_id; + + action.sigev_notify = SIGEV_THREAD; + action.sigev_notify_function = set_flag; + timer_create(CLOCK_REALTIME, &action, &timer_id); + + ; + return 0; + } + _ACEOF + if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes; with -lrt" >&5 + $as_echo "yes; with -lrt" >&6; }; $as_echo "#define HAVE_TIMER_CREATE 1" >>confdefs.h + + else + LIBS="$save_LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include + #include + static void set_flag(union sigval) {} + + int + main () + { + + struct timespec ts; + struct sigevent action = {0}; + timer_t timer_id; + + action.sigev_notify = SIGEV_THREAD; + action.sigev_notify_function = set_flag; + timer_create(CLOCK_REALTIME, &action, &timer_id); + + ; + return 0; + } + _ACEOF + if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 + $as_echo "yes" >&6; }; $as_echo "#define HAVE_TIMER_CREATE 1" >>confdefs.h + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 + $as_echo "no" >&6; } + fi + rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + fi + rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stat() ignores a trailing slash" >&5 $as_echo_n "checking whether stat() ignores a trailing slash... " >&6; } if ${vim_cv_stat_ignores_slash+:} false; then : *** ../vim-8.2.5056/src/config.h.in 2022-02-23 18:07:34.361914993 +0000 --- src/config.h.in 2022-06-05 16:55:18.730774478 +0100 *************** *** 231,236 **** --- 231,237 ---- #undef HAVE_UTIME #undef HAVE_BIND_TEXTDOMAIN_CODESET #undef HAVE_MBLEN + #undef HAVE_TIMER_CREATE /* Define, if needed, for accessing large files. */ #undef _LARGE_FILES *** ../vim-8.2.5056/src/configure.ac 2022-04-04 17:19:57.135569573 +0100 --- src/configure.ac 2022-06-05 16:48:36.646745138 +0100 *************** *** 1,7 **** dnl configure.ac: autoconf script for Vim ! dnl Process this file with autoconf 2.12 or 2.13 to produce "configure". ! dnl Should also work with autoconf 2.54 and later. AC_INIT(vim.h) AC_CONFIG_HEADER(auto/config.h:config.h.in) --- 1,8 ---- dnl configure.ac: autoconf script for Vim ! dnl Process this file with autoconf 2.69 to produce "configure". ! dnl This should also work with other versions of autoconf, but 2.70 and later ! dnl generate lots of hard to fix "obsolete" warnings. AC_INIT(vim.h) AC_CONFIG_HEADER(auto/config.h:config.h.in) *************** *** 3812,3817 **** --- 3813,3853 ---- AC_MSG_RESULT(yes); AC_DEFINE(HAVE_ST_BLKSIZE), AC_MSG_RESULT(no)) + dnl Check for timer_create. It probably requires the 'rt' library. + AC_MSG_CHECKING([for timer_create]) + save_LIBS="$LIBS" + LIBS="$LIBS -lrt" + AC_TRY_LINK([ + #include + #include + static void set_flag(union sigval) {} + ], [ + struct timespec ts; + struct sigevent action = {0}; + timer_t timer_id; + + action.sigev_notify = SIGEV_THREAD; + action.sigev_notify_function = set_flag; + timer_create(CLOCK_REALTIME, &action, &timer_id); + ], + AC_MSG_RESULT(yes; with -lrt); AC_DEFINE(HAVE_TIMER_CREATE), + LIBS="$save_LIBS" + AC_TRY_LINK([ + #include + #include + static void set_flag(union sigval) {} + ], [ + struct timespec ts; + struct sigevent action = {0}; + timer_t timer_id; + + action.sigev_notify = SIGEV_THREAD; + action.sigev_notify_function = set_flag; + timer_create(CLOCK_REALTIME, &action, &timer_id); + ], + AC_MSG_RESULT(yes); AC_DEFINE(HAVE_TIMER_CREATE), + AC_MSG_RESULT(no))) + AC_CACHE_CHECK([whether stat() ignores a trailing slash], [vim_cv_stat_ignores_slash], [ AC_RUN_IFELSE([AC_LANG_SOURCE([[ *** ../vim-8.2.5056/src/drawscreen.c 2022-05-31 13:42:54.830788849 +0100 --- src/drawscreen.c 2022-06-05 13:46:55.624445077 +0100 *************** *** 1474,1482 **** #if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA) int save_got_int; #endif - #ifdef SYN_TIME_LIMIT - proftime_T syntax_tm; - #endif #if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD) // This needs to be done only for the first window when update_screen() is --- 1474,1479 ---- *************** *** 2182,2189 **** #endif #ifdef SYN_TIME_LIMIT // Set the time limit to 'redrawtime'. ! profile_setlimit(p_rdt, &syntax_tm); ! syn_set_timeout(&syntax_tm); #endif #ifdef FEAT_FOLDING win_foldinfo.fi_level = 0; --- 2179,2185 ---- #endif #ifdef SYN_TIME_LIMIT // Set the time limit to 'redrawtime'. ! init_regexp_timeout(p_rdt); #endif #ifdef FEAT_FOLDING win_foldinfo.fi_level = 0; *************** *** 2695,2701 **** } #ifdef SYN_TIME_LIMIT ! syn_set_timeout(NULL); #endif // Reset the type of redrawing required, the window has been updated. --- 2691,2697 ---- } #ifdef SYN_TIME_LIMIT ! disable_regexp_timeout(); #endif // Reset the type of redrawing required, the window has been updated. *** ../vim-8.2.5056/src/errors.h 2022-05-29 17:13:15.779819248 +0100 --- src/errors.h 2022-06-05 14:10:19.863972241 +0100 *************** *** 3288,3290 **** --- 3288,3302 ---- EXTERN char e_argument_1_list_item_nr_dictionary_required[] INIT(= N_("E1284: Argument 1, list item %d: Dictionary required")); #endif + #ifdef FEAT_RELTIME + EXTERN char e_could_not_clear_timeout_str[] + INIT(= N_("E1285: Could not clear timeout: %s")); + EXTERN char e_could_not_set_timeout_str[] + INIT(= N_("E1286: Could not set timeout: %s")); + EXTERN char e_could_not_set_handler_for_timeout_str[] + INIT(= N_("E1287: Could not set handler for timeout: %s")); + EXTERN char e_could_not_reset_handler_for_timeout_str[] + INIT(= N_("E1288: Could not reset handler for timeout: %s")); + EXTERN char e_could_not_check_for_pending_sigalrm_str[] + INIT(= N_("E1289: Could not check for pending SIGALRM: %s")); + #endif *** ../vim-8.2.5056/src/evalfunc.c 2022-05-27 21:57:51.943739826 +0100 --- src/evalfunc.c 2022-06-05 13:46:55.624445077 +0100 *************** *** 8439,8445 **** int retval = 0; // default: FAIL long lnum_stop = 0; #ifdef FEAT_RELTIME - proftime_T tm; long time_limit = 0; #endif int options = SEARCH_KEEP; --- 8439,8444 ---- *************** *** 8486,8496 **** } } - #ifdef FEAT_RELTIME - // Set the time limit, if there is one. - profile_setlimit(time_limit, &tm); - #endif - /* * This function does not accept SP_REPEAT and SP_RETCOUNT flags. * Check to make sure only those flags are set. --- 8485,8490 ---- *************** *** 8509,8515 **** CLEAR_FIELD(sia); sia.sa_stop_lnum = (linenr_T)lnum_stop; #ifdef FEAT_RELTIME ! sia.sa_tm = &tm; #endif // Repeat until {skip} returns FALSE. --- 8503,8509 ---- CLEAR_FIELD(sia); sia.sa_stop_lnum = (linenr_T)lnum_stop; #ifdef FEAT_RELTIME ! sia.sa_tm = time_limit; #endif // Repeat until {skip} returns FALSE. *************** *** 8955,8973 **** int use_skip = FALSE; int err; int options = SEARCH_KEEP; - #ifdef FEAT_RELTIME - proftime_T tm; - #endif // Make 'cpoptions' empty, the 'l' flag should not be used here. save_cpo = p_cpo; p_cpo = empty_option; - #ifdef FEAT_RELTIME - // Set the time limit, if there is one. - profile_setlimit(time_limit, &tm); - #endif - // Make two search patterns: start/end (pat2, for in nested pairs) and // start/middle/end (pat3, for the top pair). pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17); --- 8949,8959 ---- *************** *** 8998,9004 **** CLEAR_FIELD(sia); sia.sa_stop_lnum = lnum_stop; #ifdef FEAT_RELTIME ! sia.sa_tm = &tm; #endif n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L, options, RE_SEARCH, &sia); --- 8984,8990 ---- CLEAR_FIELD(sia); sia.sa_stop_lnum = lnum_stop; #ifdef FEAT_RELTIME ! sia.sa_tm = time_limit; #endif n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L, options, RE_SEARCH, &sia); *** ../vim-8.2.5056/src/ex_cmds.c 2022-05-30 20:58:48.914049575 +0100 --- src/ex_cmds.c 2022-06-05 13:46:55.624445077 +0100 *************** *** 4006,4012 **** ); ++lnum) { nmatch = vim_regexec_multi(®match, curwin, curbuf, lnum, ! (colnr_T)0, NULL, NULL); if (nmatch) { colnr_T copycol; --- 4006,4012 ---- ); ++lnum) { nmatch = vim_regexec_multi(®match, curwin, curbuf, lnum, ! (colnr_T)0, NULL); if (nmatch) { colnr_T copycol; *************** *** 4663,4669 **** || nmatch_tl > 0 || (nmatch = vim_regexec_multi(®match, curwin, curbuf, sub_firstlnum, ! matchcol, NULL, NULL)) == 0 || regmatch.startpos[0].lnum > 0) { if (new_start != NULL) --- 4663,4669 ---- || nmatch_tl > 0 || (nmatch = vim_regexec_multi(®match, curwin, curbuf, sub_firstlnum, ! matchcol, NULL)) == 0 || regmatch.startpos[0].lnum > 0) { if (new_start != NULL) *************** *** 4728,4734 **** } if (nmatch == -1 && !lastone) nmatch = vim_regexec_multi(®match, curwin, curbuf, ! sub_firstlnum, matchcol, NULL, NULL); /* * 5. break if there isn't another match in this line --- 4728,4734 ---- } if (nmatch == -1 && !lastone) nmatch = vim_regexec_multi(®match, curwin, curbuf, ! sub_firstlnum, matchcol, NULL); /* * 5. break if there isn't another match in this line *************** *** 4992,4998 **** { lnum = curwin->w_cursor.lnum; match = vim_regexec_multi(®match, curwin, curbuf, lnum, ! (colnr_T)0, NULL, NULL); if ((type == 'g' && match) || (type == 'v' && !match)) global_exe_one(cmd, lnum); } --- 4992,4998 ---- { lnum = curwin->w_cursor.lnum; match = vim_regexec_multi(®match, curwin, curbuf, lnum, ! (colnr_T)0, NULL); if ((type == 'g' && match) || (type == 'v' && !match)) global_exe_one(cmd, lnum); } *************** *** 5005,5011 **** { // a match on this line? match = vim_regexec_multi(®match, curwin, curbuf, lnum, ! (colnr_T)0, NULL, NULL); if (regmatch.regprog == NULL) break; // re-compiling regprog failed if ((type == 'g' && match) || (type == 'v' && !match)) --- 5005,5011 ---- { // a match on this line? match = vim_regexec_multi(®match, curwin, curbuf, lnum, ! (colnr_T)0, NULL); if (regmatch.regprog == NULL) break; // re-compiling regprog failed if ((type == 'g' && match) || (type == 'v' && !match)) *** ../vim-8.2.5056/src/ex_getln.c 2022-05-30 16:01:38.999629604 +0100 --- src/ex_getln.c 2022-06-05 13:46:55.624445077 +0100 *************** *** 417,423 **** int found; // do_search() result pos_T end_pos; #ifdef FEAT_RELTIME - proftime_T tm; searchit_arg_T sia; #endif int next_char; --- 417,422 ---- *************** *** 484,493 **** cursor_off(); // so the user knows we're busy out_flush(); ++emsg_off; // so it doesn't beep if bad expr - #ifdef FEAT_RELTIME - // Set the time limit to half a second. - profile_setlimit(500L, &tm); - #endif if (!p_hls) search_flags += SEARCH_KEEP; if (search_first_line != 0) --- 483,488 ---- *************** *** 495,501 **** ccline.cmdbuff[skiplen + patlen] = NUL; #ifdef FEAT_RELTIME CLEAR_FIELD(sia); ! sia.sa_tm = &tm; #endif found = do_search(NULL, firstc == ':' ? '/' : firstc, search_delim, ccline.cmdbuff + skiplen, count, search_flags, --- 490,497 ---- ccline.cmdbuff[skiplen + patlen] = NUL; #ifdef FEAT_RELTIME CLEAR_FIELD(sia); ! // Set the time limit to half a second. ! sia.sa_tm = 500; #endif found = do_search(NULL, firstc == ':' ? '/' : firstc, search_delim, ccline.cmdbuff + skiplen, count, search_flags, *** ../vim-8.2.5056/src/match.c 2022-05-31 13:42:54.830788849 +0100 --- src/match.c 2022-06-05 14:24:09.667674692 +0100 *************** *** 330,339 **** cur->hl.buf = wp->w_buffer; cur->hl.lnum = 0; cur->hl.first_lnum = 0; - # ifdef FEAT_RELTIME - // Set the time limit to 'redrawtime'. - profile_setlimit(p_rdt, &(cur->hl.tm)); - # endif cur = cur->next; } search_hl->buf = wp->w_buffer; --- 330,335 ---- *************** *** 424,429 **** --- 420,426 ---- colnr_T matchcol; long nmatched; int called_emsg_before = called_emsg; + int timed_out = FALSE; // for :{range}s/pat only highlight inside the range if ((lnum < search_first_line || lnum > search_last_line) && cur == NULL) *************** *** 451,457 **** { # ifdef FEAT_RELTIME // Stop searching after passing the time limit. ! if (profile_passed_limit(&(shl->tm))) { shl->lnum = 0; // no match found in time break; --- 448,454 ---- { # ifdef FEAT_RELTIME // Stop searching after passing the time limit. ! if (timed_out) { shl->lnum = 0; // no match found in time break; *************** *** 494,509 **** int regprog_is_copy = (shl != search_hl && cur != NULL && shl == &cur->hl && cur->match.regprog == cur->hl.rm.regprog); - int timed_out = FALSE; nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum, ! matchcol, ! #ifdef FEAT_RELTIME ! &(shl->tm), &timed_out ! #else ! NULL, NULL ! #endif ! ); // Copy the regprog, in case it got freed and recompiled. if (regprog_is_copy) cur->match.regprog = cur->hl.rm.regprog; --- 491,499 ---- int regprog_is_copy = (shl != search_hl && cur != NULL && shl == &cur->hl && cur->match.regprog == cur->hl.rm.regprog); nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum, ! matchcol, &timed_out); // Copy the regprog, in case it got freed and recompiled. if (regprog_is_copy) cur->match.regprog = cur->hl.rm.regprog; *** ../vim-8.2.5056/src/os_mac.h 2021-12-27 17:21:38.016449116 +0000 --- src/os_mac.h 2022-06-05 14:26:39.915661365 +0100 *************** *** 6,11 **** --- 6,14 ---- * Do ":help credits" in Vim to see a list of people who contributed. */ + #ifndef OS_MAC__H + #define OS_MAC__H + // Before Including the MacOS specific files, // let's set the OPAQUE_TOOLBOX_STRUCTS to 0 so we // can access the internal structures. *************** *** 266,268 **** --- 269,320 ---- // A Mac constant causing big problem to syntax highlighting #define UNKNOWN_CREATOR '\?\?\?\?' + + #ifdef FEAT_RELTIME + + # include + + # if !defined(MAC_OS_X_VERSION_10_12) || \ + (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_12) + typedef int clockid_t; + # endif + # ifndef CLOCK_REALTIME + # define CLOCK_REALTIME 0 + # endif + # ifndef CLOCK_MONOTONIC + # define CLOCK_MONOTONIC 1 + # endif + + struct itimerspec + { + struct timespec it_interval; // timer period + struct timespec it_value; // initial expiration + }; + + struct sigevent; + + struct macos_timer + { + dispatch_queue_t tim_queue; + dispatch_source_t tim_timer; + void (*tim_func)(union sigval); + void *tim_arg; + }; + + typedef struct macos_timer *timer_t; + + extern int timer_create( + clockid_t clockid, + struct sigevent *sevp, + timer_t *timerid); + + extern int timer_delete(timer_t timerid); + + extern int timer_settime( + timer_t timerid, int flags, + const struct itimerspec *new_value, + struct itimerspec *unused); + + #endif // FEAT_RELTIME + + #endif // OS_MAC__H *** ../vim-8.2.5056/src/os_macosx.m 2020-08-13 20:05:31.785361610 +0100 --- src/os_macosx.m 2022-06-05 13:46:55.624445077 +0100 *************** *** 23,28 **** --- 23,35 ---- * X11 header files. */ #define NO_X11_INCLUDES + #include + #include + #include + #include + + #include + #include "vim.h" #import *************** *** 208,213 **** --- 215,389 ---- #endif /* FEAT_CLIPBOARD */ + #ifdef FEAT_RELTIME + /* + * The following timer code is based on a Gist by Jorgen Lundman: + * + * https://gist.github.com/lundman + */ + + typedef struct macos_timer macos_timer_T; + + static void + _timer_cancel(void *arg UNUSED) + { + // This is not currently used, but it might be useful in the future and + // it is non-trivial enough to provide as usable implementation. + # if 0 + macos_timer_T *timerid = (macos_timer_T *)arg; + + dispatch_release(timerid->tim_timer); + dispatch_release(timerid->tim_queue); + timerid->tim_timer = NULL; + timerid->tim_queue = NULL; + free(timerid); + # endif + } + + static void + _timer_handler(void *arg) + { + macos_timer_T *timerid = (macos_timer_T *)arg; + union sigval sv; + + sv.sival_ptr = timerid->tim_arg; + + if (timerid->tim_func != NULL) + timerid->tim_func(sv); + } + + static uint64_t + itime_to_ns(const struct timespec *it) + { + time_t sec = it->tv_sec; + long nsec = it->tv_nsec; + uint64_t ns = NSEC_PER_SEC * sec + nsec; + + return ns == 0 ? DISPATCH_TIME_FOREVER : ns; + } + + /* + * A partial emulation of the POSIX timer_create function. + * + * The limitations and differences include: + * + * - Only CLOCK_REALTIME and CLOCK_MONOTONIC are supported as clockid + * values. + * - Even if CLOCK_REALTIME is specified, internally the mach_absolute_time + * source is used internally. + * - The only notification method supported is SIGEV_THREAD. + */ + inline int + timer_create(clockid_t clockid, struct sigevent *sevp, timer_t *timerid) + { + macos_timer_T *timer = NULL; + + // We only support real time and monotonic clocks; and SIGEV_THREAD + // notification. In practice, there is no difference between the two + // types of clocks on MacOS - we always use the mach_machine_time + // source. + if ( (clockid != CLOCK_REALTIME && clockid != CLOCK_MONOTONIC) + || sevp->sigev_notify != SIGEV_THREAD) + { + semsg("clockid: %d %d", clockid, CLOCK_REALTIME); + semsg("notify: %d %d", sevp->sigev_notify, SIGEV_THREAD); + errno = ENOTSUP; + return -1; + } + + timer = (macos_timer_T *)malloc(sizeof(macos_timer_T)); + if (timer == NULL) + { + errno = ENOMEM; + return -1; + } + *timerid = timer; + + timer->tim_queue = dispatch_queue_create( + "org.vim.timerqueue", NULL); + if (timer->tim_queue == NULL) + { + errno = ENOMEM; + return -1; + } + + timer->tim_timer = dispatch_source_create( + DISPATCH_SOURCE_TYPE_TIMER, 0, 0, timer->tim_queue); + if (timer->tim_timer == NULL) + { + errno = ENOMEM; + return -1; + } + + timer->tim_func = sevp->sigev_notify_function; + timer->tim_arg = sevp->sigev_value.sival_ptr; + + dispatch_set_context(timer->tim_timer, timer); + dispatch_source_set_event_handler_f(timer->tim_timer, _timer_handler); + dispatch_source_set_cancel_handler_f(timer->tim_timer, _timer_cancel); + + dispatch_resume(timer->tim_timer); + + return 0; + } + + /* + * A partial emulation of the POSIX timer_settime function. + * + * The limitations and differences include: + * + * - The flags argument is ignored. The supplied new_value is therfore + * always treated as a relative time. + * - The old_value argument is ignored. + */ + int + timer_settime( + timer_t timerid, + int unused_flags UNUSED, + const struct itimerspec *new_value, + struct itimerspec *old_value UNUSED) + { + uint64_t first_shot = itime_to_ns(&new_value->it_value); + + if (timerid == NULL) + return 0; + + if (first_shot == DISPATCH_TIME_FOREVER) + { + dispatch_source_set_timer( + timerid->tim_timer, first_shot, first_shot, 0); + } + else + { + uint64_t interval = itime_to_ns(&new_value->it_interval); + + dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, first_shot); + dispatch_source_set_timer(timerid->tim_timer, start, interval, 0); + } + + return 0; + } + + /* + * An emulation of the POSIX timer_delete function. + * + * Disabled because it is not currently used, but an implemented provided + * for completeness and possible future use. + */ + #if 0 + int + timer_delete(timer_t timerid) + { + /* Calls _timer_cancel() */ + if (timerid != NULL) + dispatch_source_cancel(timerid->tim_timer); + + return 0; + } + #endif + + #endif /* FEAT_RELTIME */ + /* Lift the compiler warning suppression. */ #if defined(__clang__) && defined(__STRICT_ANSI__) # pragma clang diagnostic pop *** ../vim-8.2.5056/src/os_unix.c 2022-05-09 20:09:19.298641424 +0100 --- src/os_unix.c 2022-06-05 14:31:49.187705964 +0100 *************** *** 8256,8258 **** --- 8256,8472 ---- } } #endif // USE_XSMP + + #if defined(FEAT_RELTIME) || defined(PROTO) + # if defined(HAVE_TIMER_CREATE) || defined(MACOS_X) + /* + * Implement timeout with timer_create() and timer_settime(). + */ + static int timeout_flag = FALSE; + static timer_t timer_id; + static int timer_created = FALSE; + + /* + * Callback for when the timer expires. + */ + static void + set_flag(union sigval _unused UNUSED) + { + timeout_flag = TRUE; + } + + /* + * Stop any active timeout. + */ + void + stop_timeout(void) + { + static struct itimerspec disarm = {{0, 0}, {0, 0}}; + + if (timer_created) + { + int ret = timer_settime(timer_id, 0, &disarm, NULL); + + if (ret < 0) + semsg(_(e_could_not_clear_timeout_str), strerror(errno)); + } + + // Clear the current timeout flag; any previous timeout should be + // considered _not_ triggered. + timeout_flag = FALSE; + } + + /* + * Start the timeout timer. + * + * The return value is a pointer to a flag that is initialised to FALSE. If the + * timeout expires, the flag is set to TRUE. This will only return pointers to + * static memory; i.e. any pointer returned by this function may always be + * safely dereferenced. + * + * This function is not expected to fail, but if it does it will still return a + * valid flag pointer; the flag will remain stuck as FALSE . + */ + const int * + start_timeout(long msec) + { + struct itimerspec interval = { + {0, 0}, // Do not repeat. + {msec / 1000, (msec % 1000) * 1000000}}; // Timeout interval + int ret; + + // This is really the caller's responsibility, but let's make sure the + // previous timer has been stopped. + stop_timeout(); + timeout_flag = FALSE; + + if (!timer_created) + { + struct sigevent action = {0}; + + action.sigev_notify = SIGEV_THREAD; + action.sigev_notify_function = set_flag; + ret = timer_create(CLOCK_MONOTONIC, &action, &timer_id); + if (ret < 0) + { + semsg(_(e_could_not_set_timeout_str), strerror(errno)); + return &timeout_flag; + } + timer_created = TRUE; + } + + ret = timer_settime(timer_id, 0, &interval, NULL); + if (ret < 0) + semsg(_(e_could_not_set_timeout_str), strerror(errno)); + + return &timeout_flag; + } + + # else + + /* + * Implement timeout with setitimer() + */ + static struct itimerval prev_interval; + static struct sigaction prev_sigaction; + static int timeout_flag = FALSE; + static int timer_active = FALSE; + static int timer_handler_active = FALSE; + static int alarm_pending = FALSE; + + /* + * Handle SIGALRM for a timeout. + */ + static RETSIGTYPE + set_flag SIGDEFARG(sigarg) + { + if (alarm_pending) + alarm_pending = FALSE; + else + timeout_flag = TRUE; + } + + /* + * Stop any active timeout. + */ + void + stop_timeout(void) + { + static struct itimerval disarm = {{0, 0}, {0, 0}}; + int ret; + + if (timer_active) + { + timer_active = FALSE; + ret = setitimer(ITIMER_REAL, &disarm, &prev_interval); + if (ret < 0) + // Should only get here as a result of coding errors. + semsg(_(e_could_not_clear_timeout_str), strerror(errno)); + } + + if (timer_handler_active) + { + timer_handler_active = FALSE; + ret = sigaction(SIGALRM, &prev_sigaction, NULL); + if (ret < 0) + // Should only get here as a result of coding errors. + semsg(_(e_could_not_reset_handler_for_timeout_str), + strerror(errno)); + } + timeout_flag = 0; + } + + /* + * Start the timeout timer. + * + * The return value is a pointer to a flag that is initialised to FALSE. If the + * timeout expires, the flag is set to TRUE. This will only return pointers to + * static memory; i.e. any pointer returned by this function may always be + * safely dereferenced. + * + * This function is not expected to fail, but if it does it will still return a + * valid flag pointer; the flag will remain stuck as FALSE . + */ + const int * + start_timeout(long msec) + { + struct itimerval interval = { + {0, 0}, // Do not repeat. + {msec / 1000, (msec % 1000) * 1000}}; // Timeout interval + struct sigaction handle_alarm; + int ret; + sigset_t sigs; + sigset_t saved_sigs; + + // This is really the caller's responsibility, but let's make sure the + // previous timer has been stopped. + stop_timeout(); + + // There is a small chance that SIGALRM is pending and so the handler must + // ignore it on the first call. + alarm_pending = FALSE; + ret = sigemptyset(&sigs); + ret = ret == 0 ? sigaddset(&sigs, SIGALRM) : ret; + ret = ret == 0 ? sigprocmask(SIG_BLOCK, &sigs, &saved_sigs) : ret; + timeout_flag = FALSE; + ret = ret == 0 ? sigpending(&sigs) : ret; + if (ret == 0) + { + alarm_pending = sigismember(&sigs, SIGALRM); + ret = ret == 0 ? sigprocmask(SIG_SETMASK, &saved_sigs, NULL) : ret; + } + if (unlikely(ret != 0 || alarm_pending < 0)) + { + // Just catching coding errors. Write an error message, but carry on. + semsg(_(e_could_not_check_for_pending_sigalrm_str), strerror(errno)); + alarm_pending = FALSE; + } + + // Set up the alarm handler first. + ret = sigemptyset(&handle_alarm.sa_mask); + handle_alarm.sa_handler = set_flag; + handle_alarm.sa_flags = 0; + ret = ret == 0 ? sigaction(SIGALRM, &handle_alarm, &prev_sigaction) : ret; + if (ret < 0) + { + // Should only get here as a result of coding errors. + semsg(_(e_could_not_set_handler_for_timeout_str), strerror(errno)); + return &timeout_flag; + } + timer_handler_active = TRUE; + + // Set up the interval timer once the alarm handler is in place. + ret = setitimer(ITIMER_REAL, &interval, &prev_interval); + if (ret < 0) + { + // Should only get here as a result of coding errors. + semsg(_(e_could_not_set_timeout_str), strerror(errno)); + stop_timeout(); + return &timeout_flag; + } + + timer_active = TRUE; + return &timeout_flag; + } + # endif // HAVE_TIMER_CREATE + #endif // FEAT_RELTIME *** ../vim-8.2.5056/src/os_win32.c 2022-05-12 20:35:32.327574779 +0100 --- src/os_win32.c 2022-06-05 14:31:32.163705399 +0100 *************** *** 100,105 **** --- 100,107 ---- typedef char * LPWSTR; typedef int ACCESS_MASK; typedef int BOOL; + typedef int BOOLEAN; + typedef int CALLBACK; typedef int COLORREF; typedef int CONSOLE_CURSOR_INFO; typedef int COORD; *************** *** 7327,7332 **** --- 7329,7335 ---- ULONG EaSize; } FILE_EA_INFORMATION_, *PFILE_EA_INFORMATION_; + #ifndef PROTO typedef NTSTATUS (NTAPI *PfnNtOpenFile)( PHANDLE FileHandle, ACCESS_MASK DesiredAccess, *************** *** 7367,7372 **** --- 7370,7376 ---- PfnNtQueryEaFile pNtQueryEaFile = NULL; PfnNtQueryInformationFile pNtQueryInformationFile = NULL; PfnRtlInitUnicodeString pRtlInitUnicodeString = NULL; + #endif /* * Load ntdll.dll functions. *************** *** 8315,8317 **** --- 8319,8403 ---- } return msg; } + + #if defined(FEAT_RELTIME) || defined(PROTO) + static HANDLE timer_handle; + static int timer_active = FALSE; + + /* + * Calls to start_timeout alternate the return value pointer between the two + * entries in timeout_flags. If the previously active timeout is very close to + * expiring when start_timeout() is called then a race condition means that the + * set_flag() function may still be invoked after the previous timer is + * deleted. Ping-ponging between the two flags prevents this causing 'fake' + * timeouts. + */ + static int timeout_flags[2]; + static int flag_idx = 0; + static int *timeout_flag = &timeout_flags[0]; + + + static void CALLBACK + set_flag(void *param, BOOLEAN unused2) + { + int *timeout_flag = (int *)param; + + *timeout_flag = TRUE; + } + + /* + * Stop any active timeout. + */ + void + stop_timeout(void) + { + if (timer_active) + { + BOOL ret = DeleteTimerQueueTimer(NULL, timer_handle, NULL); + timer_active = FALSE; + if (!ret && GetLastError() != ERROR_IO_PENDING) + { + semsg(_(e_could_not_clear_timeout_str), GetWin32Error()); + } + } + *timeout_flag = FALSE; + } + + /* + * Start the timeout timer. + * + * The period is defined in milliseconds. + * + * The return value is a pointer to a flag that is initialised to 0. If the + * timeout expires, the flag is set to 1. This will only return pointers to + * static memory; i.e. any pointer returned by this function may always be + * safely dereferenced. + * + * This function is not expected to fail, but if it does it still returns a + * valid flag pointer; the flag will remain stuck at zero. + */ + const int * + start_timeout(long msec) + { + UINT interval = (UINT)msec; + BOOL ret; + + timeout_flag = &timeout_flags[flag_idx]; + + stop_timeout(); + ret = CreateTimerQueueTimer( + &timer_handle, NULL, set_flag, timeout_flag, + (DWORD)msec, 0, WT_EXECUTEDEFAULT); + if (!ret) + { + semsg(_(e_could_not_set_timeout_str), GetWin32Error()); + } + else + { + flag_idx = (flag_idx + 1) % 2; + timer_active = TRUE; + *timeout_flag = FALSE; + } + return timeout_flag; + } + #endif *** ../vim-8.2.5056/src/proto/os_unix.pro 2022-02-23 18:07:34.365914989 +0000 --- src/proto/os_unix.pro 2022-06-05 14:31:56.243706148 +0100 *************** *** 72,77 **** --- 72,78 ---- int mch_has_exp_wildcard(char_u *p); int mch_has_wildcard(char_u *p); int mch_rename(const char *src, const char *dest); + int gpm_available(void); int gpm_enabled(void); int mch_libcall(char_u *libname, char_u *funcname, char_u *argstring, int argint, char_u **string_result, int *number_result); void setup_term_clip(void); *************** *** 85,89 **** int xsmp_handle_requests(void); void xsmp_init(void); void xsmp_close(void); ! int gpm_available(void); /* vim: set ft=c : */ --- 86,91 ---- int xsmp_handle_requests(void); void xsmp_init(void); void xsmp_close(void); ! void stop_timeout(void); ! const int *start_timeout(long msec); /* vim: set ft=c : */ *** ../vim-8.2.5056/src/proto/os_win32.pro 2022-02-12 11:18:32.318462415 +0000 --- src/proto/os_win32.pro 2022-06-05 14:30:36.131702212 +0100 *************** *** 83,87 **** int is_conpty_stable(void); int get_conpty_fix_type(void); void resize_console_buf(void); ! char * GetWin32Error(void); /* vim: set ft=c : */ --- 83,89 ---- int is_conpty_stable(void); int get_conpty_fix_type(void); void resize_console_buf(void); ! char *GetWin32Error(void); ! void stop_timeout(void); ! const int *start_timeout(long msec); /* vim: set ft=c : */ *** ../vim-8.2.5056/src/proto/regexp.pro 2022-05-30 20:58:48.914049575 +0100 --- src/proto/regexp.pro 2022-06-05 14:22:48.399703980 +0100 *************** *** 1,4 **** --- 1,6 ---- /* regexp.c */ + void init_regexp_timeout(long msec); + void disable_regexp_timeout(void); int re_multiline(regprog_T *prog); char_u *skip_regexp(char_u *startp, int delim, int magic); char_u *skip_regexp_err(char_u *startp, int delim, int magic); *************** *** 18,22 **** int vim_regexec_prog(regprog_T **prog, int ignore_case, char_u *line, colnr_T col); int vim_regexec(regmatch_T *rmp, char_u *line, colnr_T col); int vim_regexec_nl(regmatch_T *rmp, char_u *line, colnr_T col); ! long vim_regexec_multi(regmmatch_T *rmp, win_T *win, buf_T *buf, linenr_T lnum, colnr_T col, proftime_T *tm, int *timed_out); /* vim: set ft=c : */ --- 20,24 ---- int vim_regexec_prog(regprog_T **prog, int ignore_case, char_u *line, colnr_T col); int vim_regexec(regmatch_T *rmp, char_u *line, colnr_T col); int vim_regexec_nl(regmatch_T *rmp, char_u *line, colnr_T col); ! long vim_regexec_multi(regmmatch_T *rmp, win_T *win, buf_T *buf, linenr_T lnum, colnr_T col, int *timed_out); /* vim: set ft=c : */ *** ../vim-8.2.5056/src/quickfix.c 2022-05-15 13:59:08.704167482 +0100 --- src/quickfix.c 2022-06-05 13:46:55.628445075 +0100 *************** *** 5990,5996 **** { // Regular expression match while (vim_regexec_multi(regmatch, curwin, buf, lnum, ! col, NULL, NULL) > 0) { // Pass the buffer number so that it gets used even for a // dummy buffer, unless duplicate_name is set, then the --- 5990,5996 ---- { // Regular expression match while (vim_regexec_multi(regmatch, curwin, buf, lnum, ! col, NULL) > 0) { // Pass the buffer number so that it gets used even for a // dummy buffer, unless duplicate_name is set, then the *** ../vim-8.2.5056/src/regexp.c 2022-05-30 20:58:48.914049575 +0100 --- src/regexp.c 2022-06-05 13:46:55.628445075 +0100 *************** *** 20,25 **** --- 20,30 ---- # define BT_REGEXP_DEBUG_LOG_NAME "bt_regexp_debug.log" #endif + #ifdef FEAT_RELTIME + static int dummy_timeout_flag = 0; + static const int *timeout_flag = &dummy_timeout_flag; + #endif + /* * Magic characters have a special meaning, they don't match literally. * Magic characters are negative. This separates them from literal characters *************** *** 45,50 **** --- 50,69 ---- return Magic(x); } + #ifdef FEAT_RELTIME + void + init_regexp_timeout(long msec) + { + timeout_flag = start_timeout(msec); + } + + void + disable_regexp_timeout(void) + { + stop_timeout(); + } + #endif + /* * The first byte of the BT regexp internal "program" is actually this magic * number; the start node begins in the second byte. It's used to catch the *************** *** 1944,1951 **** #ifdef FEAT_EVAL // To make sure that the length doesn't change between checking the // length and copying the string, and to speed up things, the ! // resulting string is saved from the call with "flags & REGSUB_COPY" ! // == 0 to the // call with "flags & REGSUB_COPY" != 0. if (copy) { if (eval_result != NULL) --- 1963,1971 ---- #ifdef FEAT_EVAL // To make sure that the length doesn't change between checking the // length and copying the string, and to speed up things, the ! // resulting string is saved from the call with ! // "flags & REGSUB_COPY" == 0 to the call with ! // "flags & REGSUB_COPY" != 0. if (copy) { if (eval_result != NULL) *************** *** 1960,1966 **** int prev_can_f_submatch = can_f_submatch; regsubmatch_T rsm_save; ! vim_free(eval_result); // The expression may contain substitute(), which calls us // recursively. Make sure submatch() gets the text from the first --- 1980,1986 ---- int prev_can_f_submatch = can_f_submatch; regsubmatch_T rsm_save; ! VIM_CLEAR(eval_result); // The expression may contain substitute(), which calls us // recursively. Make sure submatch() gets the text from the first *************** *** 2905,2911 **** buf_T *buf, // buffer in which to search linenr_T lnum, // nr of line to start looking for match colnr_T col, // column to start looking for match - proftime_T *tm, // timeout limit or NULL int *timed_out) // flag is set when timeout limit reached { int result; --- 2925,2930 ---- *************** *** 2926,2932 **** rex_in_use = TRUE; result = rmp->regprog->engine->regexec_multi( ! rmp, win, buf, lnum, col, tm, timed_out); rmp->regprog->re_in_use = FALSE; // NFA engine aborted because it's very slow. --- 2945,2951 ---- rex_in_use = TRUE; result = rmp->regprog->engine->regexec_multi( ! rmp, win, buf, lnum, col, timed_out); rmp->regprog->re_in_use = FALSE; // NFA engine aborted because it's very slow. *************** *** 2966,2972 **** rmp->regprog->re_in_use = TRUE; result = rmp->regprog->engine->regexec_multi( ! rmp, win, buf, lnum, col, tm, timed_out); rmp->regprog->re_in_use = FALSE; } vim_free(pat); --- 2985,2991 ---- rmp->regprog->re_in_use = TRUE; result = rmp->regprog->engine->regexec_multi( ! rmp, win, buf, lnum, col, timed_out); rmp->regprog->re_in_use = FALSE; } vim_free(pat); *** ../vim-8.2.5056/src/regexp.h 2022-05-30 20:58:48.910049580 +0100 --- src/regexp.h 2022-06-05 13:46:55.628445075 +0100 *************** *** 173,179 **** // bt_regexec_nl or nfa_regexec_nl int (*regexec_nl)(regmatch_T *, char_u *, colnr_T, int); // bt_regexec_mult or nfa_regexec_mult ! long (*regexec_multi)(regmmatch_T *, win_T *, buf_T *, linenr_T, colnr_T, proftime_T *, int *); //char_u *expr; }; --- 173,179 ---- // bt_regexec_nl or nfa_regexec_nl int (*regexec_nl)(regmatch_T *, char_u *, colnr_T, int); // bt_regexec_mult or nfa_regexec_mult ! long (*regexec_multi)(regmmatch_T *, win_T *, buf_T *, linenr_T, colnr_T, int *); //char_u *expr; }; *** ../vim-8.2.5056/src/regexp_bt.c 2022-05-27 15:35:23.846892913 +0100 --- src/regexp_bt.c 2022-06-05 13:46:55.628445075 +0100 *************** *** 3228,3234 **** static int regmatch( char_u *scan, // Current node. - proftime_T *tm UNUSED, // timeout limit or NULL int *timed_out UNUSED) // flag set on timeout or NULL { char_u *next; // Next node. --- 3228,3233 ---- *************** *** 3237,3245 **** regitem_T *rp; int no; int status; // one of the RA_ values: - #ifdef FEAT_RELTIME - int tm_count = 0; - #endif // Make "regstack" and "backpos" empty. They are allocated and freed in // bt_regexec_both() to reduce malloc()/free() calls. --- 3236,3241 ---- *************** *** 3271,3289 **** break; } #ifdef FEAT_RELTIME ! // Check for timeout once in 250 times to avoid excessive overhead from ! // reading the clock. The value has been picked to check about once ! // per msec on a modern CPU. ! if (tm != NULL && ++tm_count == 250) { ! tm_count = 0; ! if (profile_passed_limit(tm)) ! { ! if (timed_out != NULL) ! *timed_out = TRUE; ! status = RA_FAIL; ! break; ! } } #endif status = RA_CONT; --- 3267,3278 ---- break; } #ifdef FEAT_RELTIME ! if (*timeout_flag) { ! if (timed_out != NULL) ! *timed_out = TRUE; ! status = RA_FAIL; ! break; } #endif status = RA_CONT; *************** *** 3315,3321 **** op = OP(scan); // Check for character class with NL added. if (!rex.reg_line_lbr && WITH_NL(op) && REG_MULTI ! && *rex.input == NUL && rex.lnum <= rex.reg_maxline) { reg_nextline(); } --- 3304,3310 ---- op = OP(scan); // Check for character class with NL added. if (!rex.reg_line_lbr && WITH_NL(op) && REG_MULTI ! && *rex.input == NUL && rex.lnum <= rex.reg_maxline) { reg_nextline(); } *************** *** 4732,4738 **** regtry( bt_regprog_T *prog, colnr_T col, - proftime_T *tm, // timeout limit or NULL int *timed_out) // flag set on timeout or NULL { rex.input = rex.line + col; --- 4721,4726 ---- *************** *** 4742,4748 **** rex.need_clear_zsubexpr = (prog->reghasz == REX_SET); #endif ! if (regmatch(prog->program + 1, tm, timed_out) == 0) return 0; cleanup_subexpr(); --- 4730,4736 ---- rex.need_clear_zsubexpr = (prog->reghasz == REX_SET); #endif ! if (regmatch(prog->program + 1, timed_out) == 0) return 0; cleanup_subexpr(); *************** *** 4817,4823 **** bt_regexec_both( char_u *line, colnr_T col, // column to start looking for match - proftime_T *tm, // timeout limit or NULL int *timed_out) // flag set on timeout or NULL { bt_regprog_T *prog; --- 4805,4810 ---- *************** *** 4940,4954 **** && (((enc_utf8 && utf_fold(prog->regstart) == utf_fold(c))) || (c < 255 && prog->regstart < 255 && MB_TOLOWER(prog->regstart) == MB_TOLOWER(c))))) ! retval = regtry(prog, col, tm, timed_out); else retval = 0; } else { - #ifdef FEAT_RELTIME - int tm_count = 0; - #endif // Messy cases: unanchored match. while (!got_int) { --- 4927,4938 ---- && (((enc_utf8 && utf_fold(prog->regstart) == utf_fold(c))) || (c < 255 && prog->regstart < 255 && MB_TOLOWER(prog->regstart) == MB_TOLOWER(c))))) ! retval = regtry(prog, col, timed_out); else retval = 0; } else { // Messy cases: unanchored match. while (!got_int) { *************** *** 4975,4981 **** break; } ! retval = regtry(prog, col, tm, timed_out); if (retval > 0) break; --- 4959,4965 ---- break; } ! retval = regtry(prog, col, timed_out); if (retval > 0) break; *************** *** 4992,5009 **** else ++col; #ifdef FEAT_RELTIME ! // Check for timeout once in 500 times to avoid excessive overhead ! // from reading the clock. The value has been picked to check ! // about once per msec on a modern CPU. ! if (tm != NULL && ++tm_count == 500) { ! tm_count = 0; ! if (profile_passed_limit(tm)) ! { ! if (timed_out != NULL) ! *timed_out = TRUE; ! break; ! } } #endif } --- 4976,4986 ---- else ++col; #ifdef FEAT_RELTIME ! if (*timeout_flag) { ! if (timed_out != NULL) ! *timed_out = TRUE; ! break; } #endif } *************** *** 5067,5073 **** rex.reg_icombine = FALSE; rex.reg_maxcol = 0; ! return bt_regexec_both(line, col, NULL, NULL); } /* --- 5044,5050 ---- rex.reg_icombine = FALSE; rex.reg_maxcol = 0; ! return bt_regexec_both(line, col, NULL); } /* *************** *** 5085,5095 **** buf_T *buf, // buffer in which to search linenr_T lnum, // nr of line to start looking for match colnr_T col, // column to start looking for match - proftime_T *tm, // timeout limit or NULL int *timed_out) // flag set on timeout or NULL { init_regexec_multi(rmp, win, buf, lnum); ! return bt_regexec_both(NULL, col, tm, timed_out); } /* --- 5062,5071 ---- buf_T *buf, // buffer in which to search linenr_T lnum, // nr of line to start looking for match colnr_T col, // column to start looking for match int *timed_out) // flag set on timeout or NULL { init_regexec_multi(rmp, win, buf, lnum); ! return bt_regexec_both(NULL, col, timed_out); } /* *** ../vim-8.2.5056/src/regexp_nfa.c 2022-05-28 11:08:36.341330145 +0100 --- src/regexp_nfa.c 2022-06-05 13:46:55.628445075 +0100 *************** *** 4051,4057 **** // Used during execution: whether a match has been found. static int nfa_match; #ifdef FEAT_RELTIME - static proftime_T *nfa_time_limit; static int *nfa_timed_out; #endif --- 4051,4056 ---- *************** *** 5650,5678 **** * To reduce overhead, only check one in "count" times. */ static int ! nfa_did_time_out(int count) { ! static int tm_count = 0; ! ! // Check for timeout once in "count" times to avoid excessive overhead from ! // reading the clock. ! if (nfa_time_limit != NULL) { ! if (tm_count >= count) ! { ! if (profile_passed_limit(nfa_time_limit)) ! { ! if (nfa_timed_out != NULL) ! *nfa_timed_out = TRUE; ! tm_count = 99999; ! return TRUE; ! } ! // Only reset the count when not timed out, so that when it did ! // timeout it keeps timing out until the time limit is changed. ! tm_count = 0; ! } ! else ! ++tm_count; } return FALSE; } --- 5649,5661 ---- * To reduce overhead, only check one in "count" times. */ static int ! nfa_did_time_out(void) { ! if (*timeout_flag) { ! if (nfa_timed_out != NULL) ! *nfa_timed_out = TRUE; ! return TRUE; } return FALSE; } *************** *** 5726,5732 **** return FALSE; #ifdef FEAT_RELTIME // Check relatively often here, since this is the toplevel matching. ! if (nfa_did_time_out(100)) return FALSE; #endif --- 5709,5715 ---- return FALSE; #ifdef FEAT_RELTIME // Check relatively often here, since this is the toplevel matching. ! if (nfa_did_time_out()) return FALSE; #endif *************** *** 5880,5887 **** if (got_int) break; #ifdef FEAT_RELTIME ! // do not check very often here, since this is a loop in a loop ! if (nfa_did_time_out(2000)) break; #endif t = &thislist->t[listidx]; --- 5863,5869 ---- if (got_int) break; #ifdef FEAT_RELTIME ! if (nfa_did_time_out()) break; #endif t = &thislist->t[listidx]; *************** *** 7127,7134 **** if (got_int) break; #ifdef FEAT_RELTIME ! // check regularly but not too often here ! if (nfa_did_time_out(800)) break; #endif } --- 7109,7116 ---- if (got_int) break; #ifdef FEAT_RELTIME ! // Check for timeout once in a twenty times to avoid overhead. ! if (nfa_did_time_out()) break; #endif } *************** *** 7160,7166 **** nfa_regtry( nfa_regprog_T *prog, colnr_T col, - proftime_T *tm UNUSED, // timeout limit or NULL int *timed_out UNUSED) // flag set on timeout or NULL { int i; --- 7142,7147 ---- *************** *** 7173,7179 **** rex.input = rex.line + col; #ifdef FEAT_RELTIME - nfa_time_limit = tm; nfa_timed_out = timed_out; #endif --- 7154,7159 ---- *************** *** 7301,7307 **** nfa_regexec_both( char_u *line, colnr_T startcol, // column to start looking for match - proftime_T *tm, // timeout limit or NULL int *timed_out) // flag set on timeout or NULL { nfa_regprog_T *prog; --- 7281,7286 ---- *************** *** 7397,7403 **** prog->state[i].lastlist[1] = 0; } ! retval = nfa_regtry(prog, col, tm, timed_out); #ifdef DEBUG nfa_regengine.expr = NULL; --- 7376,7382 ---- prog->state[i].lastlist[1] = 0; } ! retval = nfa_regtry(prog, col, timed_out); #ifdef DEBUG nfa_regengine.expr = NULL; *************** *** 7577,7583 **** rex.reg_ic = rmp->rm_ic; rex.reg_icombine = FALSE; rex.reg_maxcol = 0; ! return nfa_regexec_both(line, col, NULL, NULL); } --- 7556,7562 ---- rex.reg_ic = rmp->rm_ic; rex.reg_icombine = FALSE; rex.reg_maxcol = 0; ! return nfa_regexec_both(line, col, NULL); } *************** *** 7613,7623 **** buf_T *buf, // buffer in which to search linenr_T lnum, // nr of line to start looking for match colnr_T col, // column to start looking for match - proftime_T *tm, // timeout limit or NULL int *timed_out) // flag set on timeout or NULL { init_regexec_multi(rmp, win, buf, lnum); ! return nfa_regexec_both(NULL, col, tm, timed_out); } #ifdef DEBUG --- 7592,7601 ---- buf_T *buf, // buffer in which to search linenr_T lnum, // nr of line to start looking for match colnr_T col, // column to start looking for match int *timed_out) // flag set on timeout or NULL { init_regexec_multi(rmp, win, buf, lnum); ! return nfa_regexec_both(NULL, col, timed_out); } #ifdef DEBUG *** ../vim-8.2.5056/src/screen.c 2022-05-07 20:01:10.066731684 +0100 --- src/screen.c 2022-06-05 13:46:55.628445075 +0100 *************** *** 1760,1769 **** end_search_hl(); // just in case it wasn't called before last_pat_prog(&screen_search_hl.rm); screen_search_hl.attr = HL_ATTR(HLF_L); - # ifdef FEAT_RELTIME - // Set the time limit to 'redrawtime'. - profile_setlimit(p_rdt, &screen_search_hl.tm); - # endif } } --- 1760,1765 ---- *************** *** 5029,5032 **** return NULL; // no error } - --- 5025,5027 ---- *** ../vim-8.2.5056/src/search.c 2022-06-01 15:23:07.826491258 +0100 --- src/search.c 2022-06-05 13:46:55.628445075 +0100 *************** *** 658,676 **** int break_loop = FALSE; #endif linenr_T stop_lnum = 0; // stop after this line number when != 0 ! #ifdef FEAT_RELTIME ! proftime_T *tm = NULL; // timeout limit or NULL ! int *timed_out = NULL; // set when timed out or NULL ! #endif ! ! if (extra_arg != NULL) ! { ! stop_lnum = extra_arg->sa_stop_lnum; ! #ifdef FEAT_RELTIME ! tm = extra_arg->sa_tm; ! timed_out = &extra_arg->sa_timed_out; ! #endif ! } if (search_regcomp(pat, RE_SEARCH, pat_use, (options & (SEARCH_HIS + SEARCH_KEEP)), ®match) == FAIL) --- 658,665 ---- int break_loop = FALSE; #endif linenr_T stop_lnum = 0; // stop after this line number when != 0 ! int unused_timeout_flag = FALSE; ! int *timed_out = &unused_timeout_flag; // set when timed out. if (search_regcomp(pat, RE_SEARCH, pat_use, (options & (SEARCH_HIS + SEARCH_KEEP)), ®match) == FAIL) *************** *** 680,685 **** --- 669,686 ---- return FAIL; } + if (extra_arg != NULL) + { + stop_lnum = extra_arg->sa_stop_lnum; + #ifdef FEAT_RELTIME + if (extra_arg->sa_tm > 0) + { + init_regexp_timeout(extra_arg->sa_tm); + timed_out = &extra_arg->sa_timed_out; + } + #endif + } + /* * find the string */ *************** *** 753,763 **** if (stop_lnum != 0 && (dir == FORWARD ? lnum > stop_lnum : lnum < stop_lnum)) break; ! #ifdef FEAT_RELTIME ! // Stop after passing the "tm" time limit. ! if (tm != NULL && profile_passed_limit(tm)) break; - #endif /* * Look for a match somewhere in line "lnum". --- 754,762 ---- if (stop_lnum != 0 && (dir == FORWARD ? lnum > stop_lnum : lnum < stop_lnum)) break; ! // Stop after passing the time limit. ! if (*timed_out) break; /* * Look for a match somewhere in line "lnum". *************** *** 765,786 **** col = at_first_line && (options & SEARCH_COL) ? pos->col : (colnr_T)0; nmatched = vim_regexec_multi(®match, win, buf, ! lnum, col, ! #ifdef FEAT_RELTIME ! tm, timed_out ! #else ! NULL, NULL ! #endif ! ); // vim_regexec_multi() may clear "regprog" if (regmatch.regprog == NULL) break; // Abort searching on an error (e.g., out of stack). ! if (called_emsg > called_emsg_before ! #ifdef FEAT_RELTIME ! || (timed_out != NULL && *timed_out) ! #endif ! ) break; if (nmatched > 0) { --- 764,775 ---- col = at_first_line && (options & SEARCH_COL) ? pos->col : (colnr_T)0; nmatched = vim_regexec_multi(®match, win, buf, ! lnum, col, timed_out); // vim_regexec_multi() may clear "regprog" if (regmatch.regprog == NULL) break; // Abort searching on an error (e.g., out of stack). ! if (called_emsg > called_emsg_before || *timed_out) break; if (nmatched > 0) { *************** *** 863,875 **** if (ptr[matchcol] == NUL || (nmatched = vim_regexec_multi(®match, win, buf, lnum + matchpos.lnum, ! matchcol, ! #ifdef FEAT_RELTIME ! tm, timed_out ! #else ! NULL, NULL ! #endif ! )) == 0) { match_ok = FALSE; break; --- 852,858 ---- if (ptr[matchcol] == NUL || (nmatched = vim_regexec_multi(®match, win, buf, lnum + matchpos.lnum, ! matchcol, timed_out)) == 0) { match_ok = FALSE; break; *************** *** 974,994 **** if (ptr[matchcol] == NUL || (nmatched = vim_regexec_multi(®match, win, buf, lnum + matchpos.lnum, ! matchcol, ! #ifdef FEAT_RELTIME ! tm, timed_out ! #else ! NULL, NULL ! #endif ! )) == 0) { - #ifdef FEAT_RELTIME // If the search timed out, we did find a match // but it might be the wrong one, so that's not // OK. ! if (timed_out != NULL && *timed_out) match_ok = FALSE; - #endif break; } // vim_regexec_multi() may clear "regprog" --- 957,969 ---- if (ptr[matchcol] == NUL || (nmatched = vim_regexec_multi(®match, win, buf, lnum + matchpos.lnum, ! matchcol, timed_out)) == 0) { // If the search timed out, we did find a match // but it might be the wrong one, so that's not // OK. ! if (*timed_out) match_ok = FALSE; break; } // vim_regexec_multi() may clear "regprog" *************** *** 1097,1106 **** * twice. */ if (!p_ws || stop_lnum != 0 || got_int ! || called_emsg > called_emsg_before ! #ifdef FEAT_RELTIME ! || (timed_out != NULL && *timed_out) ! #endif #ifdef FEAT_SEARCH_EXTRA || break_loop #endif --- 1072,1078 ---- * twice. */ if (!p_ws || stop_lnum != 0 || got_int ! || called_emsg > called_emsg_before || *timed_out #ifdef FEAT_SEARCH_EXTRA || break_loop #endif *************** *** 1124,1133 **** if (extra_arg != NULL) extra_arg->sa_wrapped = TRUE; } ! if (got_int || called_emsg > called_emsg_before ! #ifdef FEAT_RELTIME ! || (timed_out != NULL && *timed_out) ! #endif #ifdef FEAT_SEARCH_EXTRA || break_loop #endif --- 1096,1102 ---- if (extra_arg != NULL) extra_arg->sa_wrapped = TRUE; } ! if (got_int || called_emsg > called_emsg_before || *timed_out #ifdef FEAT_SEARCH_EXTRA || break_loop #endif *************** *** 1136,1141 **** --- 1105,1113 ---- } while (--count > 0 && found); // stop after count matches or no match + # ifdef FEAT_RELTIME + disable_regexp_timeout(); + # endif vim_regfree(regmatch.regprog); if (!found) // did not find it *************** *** 2915,2921 **** { regmatch.startpos[0].col++; nmatched = vim_regexec_multi(®match, curwin, curbuf, ! pos.lnum, regmatch.startpos[0].col, NULL, NULL); if (nmatched != 0) break; } while (regmatch.regprog != NULL --- 2887,2893 ---- { regmatch.startpos[0].col++; nmatched = vim_regexec_multi(®match, curwin, curbuf, ! pos.lnum, regmatch.startpos[0].col, NULL); if (nmatched != 0) break; } while (regmatch.regprog != NULL *** ../vim-8.2.5056/src/structs.h 2022-05-22 19:13:45.496327034 +0100 --- src/structs.h 2022-06-05 13:46:55.628445075 +0100 *************** *** 3329,3337 **** // matchaddpos(). TRUE/FALSE char has_cursor; // TRUE if the cursor is inside the match, used for // CurSearch - #ifdef FEAT_RELTIME - proftime_T tm; // for a time limit - #endif } match_T; // number of positions supported by matchaddpos() --- 3329,3334 ---- *************** *** 4419,4425 **** { linenr_T sa_stop_lnum; // stop after this line number when != 0 #ifdef FEAT_RELTIME ! proftime_T *sa_tm; // timeout limit or NULL int sa_timed_out; // set when timed out #endif int sa_wrapped; // search wrapped around --- 4416,4422 ---- { linenr_T sa_stop_lnum; // stop after this line number when != 0 #ifdef FEAT_RELTIME ! long sa_tm; // timeout limit or zero int sa_timed_out; // set when timed out #endif int sa_wrapped; // search wrapped around *** ../vim-8.2.5056/src/syntax.c 2022-04-16 16:49:20.370662695 +0100 --- src/syntax.c 2022-06-05 13:46:55.628445075 +0100 *************** *** 266,274 **** static win_T *syn_win; // current window for highlighting static buf_T *syn_buf; // current buffer for highlighting static synblock_T *syn_block; // current buffer for highlighting - #ifdef FEAT_RELTIME - static proftime_T *syn_tm; // timeout limit - #endif static linenr_T current_lnum = 0; // lnum of current state static colnr_T current_col = 0; // column of current state static int current_state_stored = 0; // TRUE if stored current state --- 266,271 ---- *************** *** 350,367 **** static int get_id_list(char_u **arg, int keylen, short **list, int skip); static void syn_combine_list(short **clstr1, short **clstr2, int list_op); - #if defined(FEAT_RELTIME) || defined(PROTO) - /* - * Set the timeout used for syntax highlighting. - * Use NULL to reset, no timeout. - */ - void - syn_set_timeout(proftime_T *tm) - { - syn_tm = tm; - } - #endif - /* * Start the syntax recognition for a line. This function is normally called * from the screen updating, once for each displayed line. --- 347,352 ---- *************** *** 3166,3174 **** syn_time_T *st UNUSED) { int r; - #ifdef FEAT_RELTIME int timed_out = FALSE; - #endif #ifdef FEAT_PROFILE proftime_T pt; --- 3151,3157 ---- *************** *** 3183,3195 **** return FALSE; rmp->rmm_maxcol = syn_buf->b_p_smc; ! r = vim_regexec_multi(rmp, syn_win, syn_buf, lnum, col, ! #ifdef FEAT_RELTIME ! syn_tm, &timed_out ! #else ! NULL, NULL ! #endif ! ); #ifdef FEAT_PROFILE if (syn_time_on) --- 3166,3172 ---- return FALSE; rmp->rmm_maxcol = syn_buf->b_p_smc; ! r = vim_regexec_multi(rmp, syn_win, syn_buf, lnum, col, &timed_out); #ifdef FEAT_PROFILE if (syn_time_on) *** ../vim-8.2.5056/src/testdir/test_hlsearch.vim 2020-09-04 20:18:40.484161926 +0100 --- src/testdir/test_hlsearch.vim 2022-06-05 13:46:55.628445075 +0100 *************** *** 37,42 **** --- 37,51 ---- func Test_hlsearch_hangs() CheckFunction reltimefloat + " So, it turns out the Windows 7 implements TimerQueue timers differently + " and they can expire *before* the requested time has elapsed. So allow for + " the timeout occurring after 80 ms (5 * 16 (the typical clock tick)). + if has("win32") + let min_timeout = 0.08 + else + let min_timeout = 0.1 + endif + " This pattern takes a long time to match, it should timeout. new call setline(1, ['aaa', repeat('abc ', 1000), 'ccc']) *************** *** 45,51 **** let @/ = '\%#=1a*.*X\@<=b*' redraw let elapsed = reltimefloat(reltime(start)) ! call assert_true(elapsed > 0.1) call assert_true(elapsed < 1.0) set nohlsearch redrawtime& bwipe! --- 54,60 ---- let @/ = '\%#=1a*.*X\@<=b*' redraw let elapsed = reltimefloat(reltime(start)) ! call assert_true(elapsed > min_timeout) call assert_true(elapsed < 1.0) set nohlsearch redrawtime& bwipe! *** ../vim-8.2.5056/src/testdir/test_search.vim 2022-05-31 13:42:54.834788844 +0100 --- src/testdir/test_search.vim 2022-06-05 13:46:55.628445075 +0100 *************** *** 1550,1555 **** --- 1550,1581 ---- bwipe! endfunc + func Test_search_timeout() + new + let pattern = '\%#=1a*.*X\@<=b*' + let search_timeout = 0.02 + let slow_target_timeout = search_timeout * 15.0 + + for n in range(40, 400, 30) + call setline(1, ['aaa', repeat('abc ', n), 'ccc']) + let start = reltime() + call search(pattern, '', 0) + let elapsed = reltimefloat(reltime(start)) + if elapsed > slow_target_timeout + break + endif + endfor + call assert_true(elapsed > slow_target_timeout) + + let max_time = elapsed / 2.0 + let start = reltime() + call search(pattern, '', 0, float2nr(search_timeout * 1000)) + let elapsed = reltimefloat(reltime(start)) + call assert_true(elapsed < max_time) + + bwipe! + endfunc + func Test_search_display_pattern() new call setline(1, ['foo', 'bar', 'foobar']) *** ../vim-8.2.5056/src/testdir/test_syntax.vim 2022-04-16 16:49:20.370662695 +0100 --- src/testdir/test_syntax.vim 2022-06-05 13:46:55.632445073 +0100 *************** *** 527,532 **** --- 527,541 ---- CheckFunction reltimefloat CheckFeature syntax + " So, it turns out the Windows 7 implements TimerQueue timers differently + " and they can expire *before* the requested time has elapsed. So allow for + " the timeout occurring after 80 ms (5 * 16 (the typical clock tick)). + if has("win32") + let min_timeout = 0.08 + else + let min_timeout = 0.1 + endif + " This pattern takes a long time to match, it should timeout. new call setline(1, ['aaa', repeat('abc ', 1000), 'ccc']) *************** *** 535,541 **** syn match Error /\%#=1a*.*X\@<=b*/ redraw let elapsed = reltimefloat(reltime(start)) ! call assert_true(elapsed > 0.1) call assert_true(elapsed < 1.0) " second time syntax HL is disabled --- 544,550 ---- syn match Error /\%#=1a*.*X\@<=b*/ redraw let elapsed = reltimefloat(reltime(start)) ! call assert_true(elapsed > min_timeout) call assert_true(elapsed < 1.0) " second time syntax HL is disabled *************** *** 549,555 **** exe "normal \" redraw let elapsed = reltimefloat(reltime(start)) ! call assert_true(elapsed > 0.1) call assert_true(elapsed < 1.0) set redrawtime& --- 558,564 ---- exe "normal \" redraw let elapsed = reltimefloat(reltime(start)) ! call assert_true(elapsed > min_timeout) call assert_true(elapsed < 1.0) set redrawtime& *************** *** 642,648 **** \ "\tNote: asdf", \ '}', \ ], 'Xtest.c') ! " This makes the default for 'background' use "dark", check that the " response to t_RB corrects it to "light". let $COLORFGBG = '15;0' --- 651,657 ---- \ "\tNote: asdf", \ '}', \ ], 'Xtest.c') ! " This makes the default for 'background' use "dark", check that the " response to t_RB corrects it to "light". let $COLORFGBG = '15;0' *** ../vim-8.2.5056/src/version.c 2022-06-04 22:15:48.792982835 +0100 --- src/version.c 2022-06-05 14:38:52.279675769 +0100 *************** *** 736,737 **** --- 736,739 ---- { /* Add new patch number below this line */ + /**/ + 5057, /**/ -- FATHER: You only killed the bride's father - that's all - LAUNCELOT: Oh dear, I didn't really mean to... FATHER: Didn't mean to? You put your sword right through his head! LAUNCELOT: Gosh - Is he all right? "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///