# HG changeset patch # User Bram Moolenaar # Date 1548363605 -3600 # Node ID 536fca2cee193d9b9ef0def0450bddb2fe846ed4 # Parent 19317f8fdd2c4c13efafd504532f961a476a8d04 patch 8.1.0815: dialog for file changed outside of Vim not tested commit https://github.com/vim/vim/commit/5e66b42aae7c67a3ef67617d4bd43052ac2b73ce Author: Bram Moolenaar Date: Thu Jan 24 21:58:10 2019 +0100 patch 8.1.0815: dialog for file changed outside of Vim not tested Problem: Dialog for file changed outside of Vim not tested. Solution: Add a test. Move FileChangedShell test. Add 'L' flag to feedkeys(). diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -1,4 +1,4 @@ -*eval.txt* For Vim version 8.1. Last change: 2019 Jan 21 +*eval.txt* For Vim version 8.1. Last change: 2019 Jan 24 VIM REFERENCE MANUAL by Bram Moolenaar @@ -662,6 +662,16 @@ is not available it returns -1 or the de :echo get(myblob, idx, 999) +Blob iteration ~ + +The |:for| loop executes commands for each byte of a Blob. The loop variable is +set to each byte in the Blob. Example: > + :for byte in 0z112233 + : call Doit(byte) + :endfor +This calls Doit() with 0x11, 0x22 and 0x33. + + Blob concatenation ~ Two blobs can be concatenated with the "+" operator: > @@ -793,8 +803,9 @@ Expression syntax summary, from least to etc. As above, append ? for ignoring case, # for matching case - expr5 is expr5 same |List| instance - expr5 isnot expr5 different |List| instance + expr5 is expr5 same |List|, |Dictionary| or |Blob| instance + expr5 isnot expr5 different |List|, |Dictionary| or |Blob| + instance |expr5| expr6 expr6 + expr6 .. number addition, list or blob concatenation @@ -962,12 +973,12 @@ Dictionary and arguments, use |get()| to if get(Part1, 'name') == get(Part2, 'name') " Part1 and Part2 refer to the same function -When using "is" or "isnot" with a |List| or a |Dictionary| this checks if the -expressions are referring to the same |List| or |Dictionary| instance. A copy -of a |List| is different from the original |List|. When using "is" without -a |List| or a |Dictionary| it is equivalent to using "equal", using "isnot" -equivalent to using "not equal". Except that a different type means the -values are different: > +Using "is" or "isnot" with a |List|, |Dictionary| or |Blob| checks whether +the expressions are referring to the same |List|, |Dictionary| or |Blob| +instance. A copy of a |List| is different from the original |List|. When +using "is" without a |List|, |Dictionary| or |Blob|, it is equivalent to +using "equal", using "isnot" equivalent to using "not equal". Except that +a different type means the values are different: > echo 4 == '4' 1 echo 4 is '4' @@ -1012,16 +1023,16 @@ can be matched like an ordinary characte expr5 and expr6 *expr5* *expr6* --------------- -expr6 + expr6 .. Number addition or |List| concatenation *expr-+* -expr6 - expr6 .. Number subtraction *expr--* -expr6 . expr6 .. String concatenation *expr-.* +expr6 + expr6 Number addition, |List| or |Blob| concatenation *expr-+* +expr6 - expr6 Number subtraction *expr--* +expr6 . expr6 String concatenation *expr-.* For |Lists| only "+" is possible and then both expr6 must be a list. The result is a new list with the two lists Concatenated. -expr7 * expr7 .. Number multiplication *expr-star* -expr7 / expr7 .. Number division *expr-/* -expr7 % expr7 .. Number modulo *expr-%* +expr7 * expr7 Number multiplication *expr-star* +expr7 / expr7 Number division *expr-/* +expr7 % expr7 Number modulo *expr-%* For all, except ".", Strings are converted to Numbers. For bitwise operators see |and()|, |or()| and |xor()|. @@ -4121,6 +4132,9 @@ feedkeys({string} [, {mode}]) *feedke 't' Handle keys as if typed; otherwise they are handled as if coming from a mapping. This matters for undo, opening folds, etc. + 'L' Lowlevel input. Only works for Unix or when using the + GUI. Keys are used as if they were coming from the + terminal. Other flags are not used. *E980* 'i' Insert the string instead of appending (see above). 'x' Execute commands until typeahead is empty. This is similar to using ":normal!". You can call feedkeys() @@ -5740,6 +5754,10 @@ job_start({command} [, {options}]) *jo |:!cmd| this does not wait for the job to finish. To start a job in a terminal window see |term_start()|. + If the job fails to start then |job_status()| on the returned + Job object results in "fail" and none of the callbacks will be + invoked. + {command} can be a String. This works best on MS-Windows. On Unix it is split up in white-separated parts to be passed to execvp(). Arguments in double quotes can contain white space. @@ -11044,28 +11062,34 @@ 7. Commands *expression-commands* NOTE: The ":append" and ":insert" commands don't work properly inside a ":while" and ":for" loop. -:for {var} in {list} *:for* *E690* *E732* +:for {var} in {object} *:for* *E690* *E732* :endfo[r] *:endfo* *:endfor* Repeat the commands between ":for" and ":endfor" for - each item in {list}. Variable {var} is set to the - value of each item. - When an error is detected for a command inside the - loop, execution continues after the "endfor". - Changing {list} inside the loop affects what items are - used. Make a copy if this is unwanted: > + each item in {object}. {object} can be a |List| or + a |Blob|. Variable {var} is set to the value of each + item. When an error is detected for a command inside + the loop, execution continues after the "endfor". + Changing {object} inside the loop affects what items + are used. Make a copy if this is unwanted: > :for item in copy(mylist) -< When not making a copy, Vim stores a reference to the - next item in the list, before executing the commands - with the current item. Thus the current item can be - removed without effect. Removing any later item means - it will not be found. Thus the following example - works (an inefficient way to make a list empty): > +< + When {object} is a |List| and not making a copy, Vim + stores a reference to the next item in the |List| + before executing the commands with the current item. + Thus the current item can be removed without effect. + Removing any later item means it will not be found. + Thus the following example works (an inefficient way + to make a |List| empty): > for item in mylist call remove(mylist, 0) endfor -< Note that reordering the list (e.g., with sort() or +< Note that reordering the |List| (e.g., with sort() or reverse()) may have unexpected effects. + When {object} is a |Blob|, Vim always makes a copy to + iterate over. Unlike with |List|, modifying the + |Blob| does not affect the iteration. + :for [{var1}, {var2}, ...] in {listlist} :endfo[r] Like ":for" above, but each item in {listlist} must be diff --git a/src/evalfunc.c b/src/evalfunc.c --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -3674,6 +3674,7 @@ f_feedkeys(typval_T *argvars, typval_T * int typed = FALSE; int execute = FALSE; int dangerous = FALSE; + int lowlevel = FALSE; char_u *keys_esc; /* This is not allowed in the sandbox. If the commands would still be @@ -3697,6 +3698,7 @@ f_feedkeys(typval_T *argvars, typval_T * case 'i': insert = TRUE; break; case 'x': execute = TRUE; break; case '!': dangerous = TRUE; break; + case 'L': lowlevel = TRUE; break; } } } @@ -3708,7 +3710,16 @@ f_feedkeys(typval_T *argvars, typval_T * keys_esc = vim_strsave_escape_csi(keys); if (keys_esc != NULL) { - ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE), + if (lowlevel) + { +#ifdef USE_INPUT_BUF + add_to_input_buf(keys, (int)STRLEN(keys)); +#else + emsg(_("E980: lowlevel input not supported")); +#endif + } + else + ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE), insert ? 0 : typebuf.tb_len, !typed, FALSE); vim_free(keys_esc); if (vgetc_busy diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak --- a/src/testdir/Make_all.mak +++ b/src/testdir/Make_all.mak @@ -121,6 +121,7 @@ NEW_TESTS = \ test_feedkeys \ test_file_perm \ test_file_size \ + test_filechanged \ test_fileformat \ test_filetype \ test_filter_cmd \ @@ -316,6 +317,7 @@ NEW_TESTS_RES = \ test_exit.res \ test_farsi.res \ test_file_size.res \ + test_filechanged.res \ test_find_complete.res \ test_fixeol.res \ test_fnameescape.res \ diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim --- a/src/testdir/test_autocmd.vim +++ b/src/testdir/test_autocmd.vim @@ -1386,92 +1386,4 @@ func Test_Changed_FirstTime() bwipe! endfunc -func Test_FileChangedShell_reload() - if !has('unix') - return - endif - augroup testreload - au FileChangedShell Xchanged let g:reason = v:fcs_reason | let v:fcs_choice = 'reload' - augroup END - new Xchanged - call setline(1, 'reload this') - write - " Need to wait until the timestamp would change by at least a second. - sleep 2 - silent !echo 'extra line' >>Xchanged - checktime - call assert_equal('changed', g:reason) - call assert_equal(2, line('$')) - call assert_equal('extra line', getline(2)) - - " Only triggers once - let g:reason = '' - checktime - call assert_equal('', g:reason) - - " When deleted buffer is not reloaded - silent !rm Xchanged - let g:reason = '' - checktime - call assert_equal('deleted', g:reason) - call assert_equal(2, line('$')) - call assert_equal('extra line', getline(2)) - - " When recreated buffer is reloaded - call setline(1, 'buffer is changed') - silent !echo 'new line' >>Xchanged - let g:reason = '' - checktime - call assert_equal('conflict', g:reason) - call assert_equal(1, line('$')) - call assert_equal('new line', getline(1)) - - " Only mode changed - silent !chmod +x Xchanged - let g:reason = '' - checktime - call assert_equal('mode', g:reason) - call assert_equal(1, line('$')) - call assert_equal('new line', getline(1)) - - " Only time changed - sleep 2 - silent !touch Xchanged - let g:reason = '' - checktime - call assert_equal('time', g:reason) - call assert_equal(1, line('$')) - call assert_equal('new line', getline(1)) - - if has('persistent_undo') - " With an undo file the reload can be undone and a change before the - " reload. - set undofile - call setline(2, 'before write') - write - call setline(2, 'after write') - sleep 2 - silent !echo 'different line' >>Xchanged - let g:reason = '' - checktime - call assert_equal('conflict', g:reason) - call assert_equal(3, line('$')) - call assert_equal('before write', getline(2)) - call assert_equal('different line', getline(3)) - " undo the reload - undo - call assert_equal(2, line('$')) - call assert_equal('after write', getline(2)) - " undo the change before reload - undo - call assert_equal(2, line('$')) - call assert_equal('before write', getline(2)) - - set noundofile - endif - - - au! testreload - bwipe! - call delete('Xchanged') -endfunc +" FileChangedShell tested in test_filechanged.vim diff --git a/src/testdir/test_filechanged.vim b/src/testdir/test_filechanged.vim new file mode 100644 --- /dev/null +++ b/src/testdir/test_filechanged.vim @@ -0,0 +1,146 @@ +" Tests for when a file was changed outside of Vim. + +func Test_FileChangedShell_reload() + if !has('unix') + return + endif + augroup testreload + au FileChangedShell Xchanged_r let g:reason = v:fcs_reason | let v:fcs_choice = 'reload' + augroup END + new Xchanged_r + call setline(1, 'reload this') + write + " Need to wait until the timestamp would change by at least a second. + sleep 2 + silent !echo 'extra line' >>Xchanged_r + checktime + call assert_equal('changed', g:reason) + call assert_equal(2, line('$')) + call assert_equal('extra line', getline(2)) + + " Only triggers once + let g:reason = '' + checktime + call assert_equal('', g:reason) + + " When deleted buffer is not reloaded + silent !rm Xchanged_r + let g:reason = '' + checktime + call assert_equal('deleted', g:reason) + call assert_equal(2, line('$')) + call assert_equal('extra line', getline(2)) + + " When recreated buffer is reloaded + call setline(1, 'buffer is changed') + silent !echo 'new line' >>Xchanged_r + let g:reason = '' + checktime + call assert_equal('conflict', g:reason) + call assert_equal(1, line('$')) + call assert_equal('new line', getline(1)) + + " Only mode changed + silent !chmod +x Xchanged_r + let g:reason = '' + checktime + call assert_equal('mode', g:reason) + call assert_equal(1, line('$')) + call assert_equal('new line', getline(1)) + + " Only time changed + sleep 2 + silent !touch Xchanged_r + let g:reason = '' + checktime + call assert_equal('time', g:reason) + call assert_equal(1, line('$')) + call assert_equal('new line', getline(1)) + + if has('persistent_undo') + " With an undo file the reload can be undone and a change before the + " reload. + set undofile + call setline(2, 'before write') + write + call setline(2, 'after write') + sleep 2 + silent !echo 'different line' >>Xchanged_r + let g:reason = '' + checktime + call assert_equal('conflict', g:reason) + call assert_equal(3, line('$')) + call assert_equal('before write', getline(2)) + call assert_equal('different line', getline(3)) + " undo the reload + undo + call assert_equal(2, line('$')) + call assert_equal('after write', getline(2)) + " undo the change before reload + undo + call assert_equal(2, line('$')) + call assert_equal('before write', getline(2)) + + set noundofile + endif + + au! testreload + bwipe! + call delete('Xchanged_r') +endfunc + +func Test_file_changed_dialog() + if !has('unix') + return + endif + au! FileChangedShell + + new Xchanged_d + call setline(1, 'reload this') + write + " Need to wait until the timestamp would change by at least a second. + sleep 2 + silent !echo 'extra line' >>Xchanged_d + call feedkeys('L', 'L') + checktime + call assert_match('W11:', v:warningmsg) + call assert_equal(2, line('$')) + call assert_equal('reload this', getline(1)) + call assert_equal('extra line', getline(2)) + + " delete buffer, only shows an error, no prompt + silent !rm Xchanged_d + checktime + call assert_match('E211:', v:warningmsg) + call assert_equal(2, line('$')) + call assert_equal('extra line', getline(2)) + + " Recreate buffer and reload + call setline(1, 'buffer is changed') + silent !echo 'new line' >Xchanged_d + call feedkeys('L', 'L') + checktime + call assert_match('W12:', v:warningmsg) + call assert_equal(1, line('$')) + call assert_equal('new line', getline(1)) + + " Only mode changed, reload + silent !chmod +x Xchanged_d + call feedkeys('L', 'L') + checktime + call assert_match('W16:', v:warningmsg) + call assert_equal(1, line('$')) + call assert_equal('new line', getline(1)) + + " Only time changed, no prompt + sleep 2 + silent !touch Xchanged_d + let v:warningmsg = '' + checktime + call assert_equal('', v:warningmsg) + call assert_equal(1, line('$')) + call assert_equal('new line', getline(1)) + + bwipe! + call delete('Xchanged_d') +endfunc diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -788,7 +788,9 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ - 84, + 815, +/**/ + 814, /**/ 813, /**/