From 2db0ec4b2ec405aca4e642e0420ce703f94914a8 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 31 Aug 2017 20:17:59 +0200 Subject: [PATCH 01/26] patch 8.0.1027: more terminals can't handle requesting cursor mode Problem: More terminals can't handle requesting cursor mode. Solution: Recognize Putty. (Hirohito Higashi) Also include Xfce in the version check. (Dominique Pelle) Recognize Konsole. --- src/term.c | 17 ++++++++++++++--- src/version.c | 2 ++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/term.c b/src/term.c index 424489206f..85292db857 100644 --- a/src/term.c +++ b/src/term.c @@ -4562,10 +4562,21 @@ check_termcode( && STRNCMP(tp + extra - 2, "1;95;0c", 7) == 0) is_not_xterm = TRUE; # endif - /* Gnome Terminal.app sends 1;3801;0 or 1;4402;0, - * assuming any version number over 3000 is not an + /* Gnome terminal sends 1;3801;0 or 1;4402;0. + * xfce4-terminal sends 1;2802;0. + * Assuming any version number over 2800 is not an * xterm. */ - if (col >= 3000) + if (col >= 2800) + is_not_xterm = TRUE; + + /* PuTTY sends 0;136;0 */ + if (col == 136 + && STRNCMP(tp + extra - 2, "0;136;0c", 8) == 0) + is_not_xterm = TRUE; + + /* Konsole sends 0;115;0 */ + if (col == 115 + && STRNCMP(tp + extra - 2, "0;115;0c", 8) == 0) is_not_xterm = TRUE; /* Only request the cursor style if t_SH and t_RS are diff --git a/src/version.c b/src/version.c index b33b2d42b4..56803bc047 100644 --- a/src/version.c +++ b/src/version.c @@ -769,6 +769,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1027, /**/ 1026, /**/ From 3d593c2dc97c5426316bf343910cad911b2f6b49 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 31 Aug 2017 20:42:18 +0200 Subject: [PATCH 02/26] patch 8.0.1028: MS-Windows: viminfo uses $VIM/_viminfo if $HOME not set Problem: MS-Windows: viminfo uses $VIM/_viminfo if $HOME not set. (Yongwei Wu) Solution: Use vim_getenv() but check it's returning the default "C:/". --- src/ex_cmds.c | 7 ++++++- src/version.c | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/ex_cmds.c b/src/ex_cmds.c index 8b21b81f2a..1cb15f2047 100644 --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -2098,11 +2098,16 @@ viminfo_filename(char_u *file) else if ((file = find_viminfo_parameter('n')) == NULL || *file == NUL) { #ifdef VIMINFO_FILE2 - /* don't use $HOME when not defined (turned into "c:/"!). */ # ifdef VMS if (mch_getenv((char_u *)"SYS$LOGIN") == NULL) # else +# ifdef MSWIN + /* Use $VIM only if $HOME is the default "C:/". */ + if (STRCMP(vim_getenv((char_u *)"HOME", NULL), "C:/") == 0 + && mch_getenv((char_u *)"HOME") == NULL) +# else if (mch_getenv((char_u *)"HOME") == NULL) +# endif # endif { /* don't use $VIM when not available. */ diff --git a/src/version.c b/src/version.c index 56803bc047..37afc35012 100644 --- a/src/version.c +++ b/src/version.c @@ -769,6 +769,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1028, /**/ 1027, /**/ From da73253a0b908bad03ddcd625fe3fb32008efbf6 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 31 Aug 2017 20:58:02 +0200 Subject: [PATCH 03/26] patch 8.0.1029: return value of getqflist() is inconsistent Problem: Return value of getqflist() is inconsistent. (Lcd47) Solution: Always return an "items" entry. --- src/quickfix.c | 15 ++++++++------- src/testdir/test_quickfix.vim | 2 +- src/version.c | 2 ++ 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/quickfix.c b/src/quickfix.c index 8277b937e9..1082fbd374 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -4653,6 +4653,11 @@ qf_get_list_from_text(dictitem_T *di, dict_T *retdict) || (di->di_tv.v_type == VAR_LIST && di->di_tv.vval.v_list != NULL)) { + list_T *l = list_alloc(); + + if (l == NULL) + return FAIL; + qi = (qf_info_T *)alloc((unsigned)sizeof(qf_info_T)); if (qi != NULL) { @@ -4662,17 +4667,13 @@ qf_get_list_from_text(dictitem_T *di, dict_T *retdict) if (qf_init_ext(qi, 0, NULL, NULL, &di->di_tv, p_efm, TRUE, (linenr_T)0, (linenr_T)0, NULL, NULL) > 0) { - list_T *l = list_alloc(); - if (l != NULL) - { - (void)get_errorlist(qi, NULL, 0, l); - dict_add_list(retdict, "items", l); - status = OK; - } + (void)get_errorlist(qi, NULL, 0, l); qf_free(qi, 0); } free(qi); } + dict_add_list(retdict, "items", l); + status = OK; } return status; diff --git a/src/testdir/test_quickfix.vim b/src/testdir/test_quickfix.vim index 076d583fd0..d6b65e339f 100644 --- a/src/testdir/test_quickfix.vim +++ b/src/testdir/test_quickfix.vim @@ -2536,7 +2536,7 @@ func XgetListFromText(cchar) call assert_equal(30, l[1].lnum) call assert_equal({}, g:Xgetlist({'text' : 10})) - call assert_equal({}, g:Xgetlist({'text' : []})) + call assert_equal([], g:Xgetlist({'text' : []}).items) " Make sure that the quickfix stack is not modified call assert_equal(0, g:Xgetlist({'nr' : '$'}).nr) diff --git a/src/version.c b/src/version.c index 37afc35012..fbf175efdb 100644 --- a/src/version.c +++ b/src/version.c @@ -769,6 +769,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1029, /**/ 1028, /**/ From 9e8dcf9d6fa15523800005a32d40cf0382178ab0 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 31 Aug 2017 21:35:45 +0200 Subject: [PATCH 04/26] patch 8.0.1030: MS-Windows: wrong size computation in is_cygpty() Problem: MS-Windows: wrong size computation in is_cygpty(). Solution: Compute the size properly. (Ken Takata) --- src/iscygpty.c | 24 ++++++++++++++---------- src/iscygpty.h | 7 ++++++- src/version.c | 2 ++ 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/iscygpty.c b/src/iscygpty.c index d7037c56fc..722f88f2f4 100644 --- a/src/iscygpty.c +++ b/src/iscygpty.c @@ -2,7 +2,7 @@ * iscygpty.c -- part of ptycheck * https://github.com/k-takata/ptycheck * - * Copyright (c) 2015-2016 K.Takata + * Copyright (c) 2015-2017 K.Takata * * You can redistribute it and/or modify it under the terms of either * the MIT license (as described below) or the Vim license. @@ -27,6 +27,8 @@ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#ifdef _WIN32 + #include #include #include @@ -60,19 +62,19 @@ //#define USE_DYNFILEID #ifdef USE_DYNFILEID typedef BOOL (WINAPI *pfnGetFileInformationByHandleEx)( - HANDLE hFile, + HANDLE hFile, FILE_INFO_BY_HANDLE_CLASS FileInformationClass, - LPVOID lpFileInformation, - DWORD dwBufferSize + LPVOID lpFileInformation, + DWORD dwBufferSize ); static pfnGetFileInformationByHandleEx pGetFileInformationByHandleEx = NULL; # ifndef USE_FILEEXTD static BOOL WINAPI stub_GetFileInformationByHandleEx( - HANDLE hFile, + HANDLE hFile, FILE_INFO_BY_HANDLE_CLASS FileInformationClass, - LPVOID lpFileInformation, - DWORD dwBufferSize + LPVOID lpFileInformation, + DWORD dwBufferSize ) { return FALSE; @@ -111,7 +113,7 @@ int is_cygpty(int fd) return 0; #else HANDLE h; - int size = sizeof(FILE_NAME_INFO) + sizeof(WCHAR) * MAX_PATH; + int size = sizeof(FILE_NAME_INFO) + sizeof(WCHAR) * (MAX_PATH - 1); FILE_NAME_INFO *nameinfo; WCHAR *p = NULL; @@ -125,7 +127,7 @@ int is_cygpty(int fd) if (GetFileType(h) != FILE_TYPE_PIPE) { return 0; } - nameinfo = malloc(size); + nameinfo = malloc(size + sizeof(WCHAR)); if (nameinfo == NULL) { return 0; } @@ -178,4 +180,6 @@ int is_cygpty_used(void) return ret; } -/* vi:set ts=8 sts=4 sw=4 noet: */ +#endif /* _WIN32 */ + +/* vim: set ts=4 sw=4: */ diff --git a/src/iscygpty.h b/src/iscygpty.h index fbca4b4095..82fd0affbd 100644 --- a/src/iscygpty.h +++ b/src/iscygpty.h @@ -2,7 +2,7 @@ * iscygpty.h -- part of ptycheck * https://github.com/k-takata/ptycheck * - * Copyright (c) 2015-2016 K.Takata + * Copyright (c) 2015-2017 K.Takata * * You can redistribute it and/or modify it under the terms of either * the MIT license (as described below) or the Vim license. @@ -30,7 +30,12 @@ #ifndef _ISCYGPTY_H #define _ISCYGPTY_H +#ifdef _WIN32 int is_cygpty(int fd); int is_cygpty_used(void); +#else +#define is_cygpty(fd) 0 +#define is_cygpty_used() 0 +#endif #endif /* _ISCYGPTY_H */ diff --git a/src/version.c b/src/version.c index fbf175efdb..d5257a7579 100644 --- a/src/version.c +++ b/src/version.c @@ -769,6 +769,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1030, /**/ 1029, /**/ From 2c809b7c7d2bb5e4b7fd09c3d312cadecf0c1ff0 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 1 Sep 2017 18:34:02 +0200 Subject: [PATCH 05/26] patch 8.0.1031: "text" argument for getqflist() is confusing Problem: "text" argument for getqflist() is confusing. (Lcd47) Solution: Use "lines" instead. (Yegappan Lakshmanan) --- runtime/doc/eval.txt | 22 +++++++------- src/quickfix.c | 20 +++++-------- src/testdir/test_quickfix.vim | 55 +++++++++++++++++------------------ src/version.c | 2 ++ 4 files changed, 48 insertions(+), 51 deletions(-) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index ecb41c4b81..b9f3c09b16 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -4636,14 +4636,13 @@ getqflist([{what}]) *getqflist()* |quickfix-ID|; zero means the id for the current list or the list specifed by 'nr' items quickfix list entries + lines use 'errorformat' to extract items from a list + of lines and return the resulting entries. + Only a |List| type is accepted. The current + quickfix list is not modified. nr get information for this quickfix list; zero means the current quickfix list and '$' means the last quickfix list - text use 'errorformat' to extract items from the - text and return the resulting entries. The - value can be a string with one line or a list - with multiple lines. The current quickfix list - is not modified. title get the list title winid get the |window-ID| (if opened) all all of the above quickfix properties @@ -4671,6 +4670,7 @@ getqflist([{what}]) *getqflist()* Examples: > :echo getqflist({'all': 1}) :echo getqflist({'nr': 2, 'title': 1}) + :echo getqflist({'lines' : ["F1:10:L10"]}) < getreg([{regname} [, 1 [, {list}]]]) *getreg()* @@ -7071,13 +7071,12 @@ setqflist({list} [, {action}[, {what}]]) *setqflist()* argument is ignored. The following items can be specified in {what}: context any Vim type can be stored as a context - text use 'errorformat' to extract items from the - text and add the resulting entries to the - quickfix list {nr}. The value can be a string - with one line or a list with multiple lines. id quickfix list identifier |quickfix-ID| items list of quickfix entries. Same as the {list} argument. + lines use 'errorformat' to parse a list of lines and + add the resulting entries to the quickfix list + {nr} or {id}. Only a |List| value is supported. nr list number in the quickfix stack; zero means the current quickfix list and '$' means the last quickfix list @@ -7091,8 +7090,9 @@ setqflist({list} [, {action}[, {what}]]) *setqflist()* specify the list. Examples: > - :call setqflist([], 'r', {'title': 'My search'}) - :call setqflist([], 'r', {'nr': 2, 'title': 'Errors'}) + :call setqflist([], 'r', {'title': 'My search'}) + :call setqflist([], 'r', {'nr': 2, 'title': 'Errors'}) + :call setqflist([], 'a', {'id':myid, 'lines':["F1:10:L10"]}) < Returns zero for success, -1 for failure. diff --git a/src/quickfix.c b/src/quickfix.c index 1082fbd374..5cbb1519ad 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -4643,15 +4643,13 @@ enum { * Parse text from 'di' and return the quickfix list items */ static int -qf_get_list_from_text(dictitem_T *di, dict_T *retdict) +qf_get_list_from_lines(dictitem_T *di, dict_T *retdict) { int status = FAIL; qf_info_T *qi; - /* Only string and list values are supported */ - if ((di->di_tv.v_type == VAR_STRING && di->di_tv.vval.v_string != NULL) - || (di->di_tv.v_type == VAR_LIST - && di->di_tv.vval.v_list != NULL)) + /* Only a List value is supported */ + if (di->di_tv.v_type == VAR_LIST && di->di_tv.vval.v_list != NULL) { list_T *l = list_alloc(); @@ -4693,8 +4691,8 @@ get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict) dictitem_T *di; int flags = QF_GETLIST_NONE; - if ((di = dict_find(what, (char_u *)"text", -1)) != NULL) - return qf_get_list_from_text(di, retdict); + if ((di = dict_find(what, (char_u *)"lines", -1)) != NULL) + return qf_get_list_from_lines(di, retdict); if (wp != NULL) qi = GET_LOC_LIST(wp); @@ -5053,12 +5051,10 @@ qf_set_properties(qf_info_T *qi, dict_T *what, int action, char_u *title) } } - if ((di = dict_find(what, (char_u *)"text", -1)) != NULL) + if ((di = dict_find(what, (char_u *)"lines", -1)) != NULL) { - /* Only string and list values are supported */ - if ((di->di_tv.v_type == VAR_STRING && di->di_tv.vval.v_string != NULL) - || (di->di_tv.v_type == VAR_LIST - && di->di_tv.vval.v_list != NULL)) + /* Only a List value is supported */ + if (di->di_tv.v_type == VAR_LIST && di->di_tv.vval.v_list != NULL) { if (action == 'r') qf_free_items(qi, qf_idx); diff --git a/src/testdir/test_quickfix.vim b/src/testdir/test_quickfix.vim index d6b65e339f..64f1baea2c 100644 --- a/src/testdir/test_quickfix.vim +++ b/src/testdir/test_quickfix.vim @@ -2299,25 +2299,26 @@ func Xsetexpr_tests(cchar) call s:setup_commands(a:cchar) let t = ["File1:10:Line10", "File1:20:Line20"] - call g:Xsetlist([], ' ', {'text' : t}) - call g:Xsetlist([], 'a', {'text' : "File1:30:Line30"}) + call g:Xsetlist([], ' ', {'lines' : t}) + call g:Xsetlist([], 'a', {'lines' : ["File1:30:Line30"]}) let l = g:Xgetlist() call assert_equal(3, len(l)) call assert_equal(20, l[1].lnum) call assert_equal('Line30', l[2].text) - call g:Xsetlist([], 'r', {'text' : "File2:5:Line5"}) + call g:Xsetlist([], 'r', {'lines' : ["File2:5:Line5"]}) let l = g:Xgetlist() call assert_equal(1, len(l)) call assert_equal('Line5', l[0].text) - call assert_equal(-1, g:Xsetlist([], 'a', {'text' : 10})) + call assert_equal(-1, g:Xsetlist([], 'a', {'lines' : 10})) + call assert_equal(-1, g:Xsetlist([], 'a', {'lines' : "F1:10:L10"})) call g:Xsetlist([], 'f') " Add entries to multiple lists - call g:Xsetlist([], 'a', {'nr' : 1, 'text' : ["File1:10:Line10"]}) - call g:Xsetlist([], 'a', {'nr' : 2, 'text' : ["File2:20:Line20"]}) - call g:Xsetlist([], 'a', {'nr' : 1, 'text' : ["File1:15:Line15"]}) - call g:Xsetlist([], 'a', {'nr' : 2, 'text' : ["File2:25:Line25"]}) + call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["File1:10:Line10"]}) + call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["File2:20:Line20"]}) + call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["File1:15:Line15"]}) + call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["File2:25:Line25"]}) call assert_equal('Line15', g:Xgetlist({'nr':1, 'items':1}).items[1].text) call assert_equal('Line25', g:Xgetlist({'nr':2, 'items':1}).items[1].text) endfunc @@ -2334,10 +2335,10 @@ func Xmultidirstack_tests(cchar) call g:Xsetlist([], 'f') Xexpr "" | Xexpr "" - call g:Xsetlist([], 'a', {'nr' : 1, 'text' : "Entering dir 'Xone/a'"}) - call g:Xsetlist([], 'a', {'nr' : 2, 'text' : "Entering dir 'Xtwo/a'"}) - call g:Xsetlist([], 'a', {'nr' : 1, 'text' : "one.txt:3:one one one"}) - call g:Xsetlist([], 'a', {'nr' : 2, 'text' : "two.txt:5:two two two"}) + call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["Entering dir 'Xone/a'"]}) + call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["Entering dir 'Xtwo/a'"]}) + call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["one.txt:3:one one one"]}) + call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["two.txt:5:two two two"]}) let l1 = g:Xgetlist({'nr':1, 'items':1}) let l2 = g:Xgetlist({'nr':2, 'items':1}) @@ -2371,10 +2372,10 @@ func Xmultifilestack_tests(cchar) call g:Xsetlist([], 'f') Xexpr "" | Xexpr "" - call g:Xsetlist([], 'a', {'nr' : 1, 'text' : "[one.txt]"}) - call g:Xsetlist([], 'a', {'nr' : 2, 'text' : "[two.txt]"}) - call g:Xsetlist([], 'a', {'nr' : 1, 'text' : "(3,5) one one one"}) - call g:Xsetlist([], 'a', {'nr' : 2, 'text' : "(5,9) two two two"}) + call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["[one.txt]"]}) + call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["[two.txt]"]}) + call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["(3,5) one one one"]}) + call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["(5,9) two two two"]}) let l1 = g:Xgetlist({'nr':1, 'items':1}) let l2 = g:Xgetlist({'nr':2, 'items':1}) @@ -2523,28 +2524,26 @@ endfunc " Test for getting the quickfix list items from some text without modifying " the quickfix stack -func XgetListFromText(cchar) +func XgetListFromLines(cchar) call s:setup_commands(a:cchar) call g:Xsetlist([], 'f') - let l = g:Xgetlist({'text' : "File1:10:Line10"}).items - call assert_equal(1, len(l)) - call assert_equal('Line10', l[0].text) - - let l = g:Xgetlist({'text' : ["File2:20:Line20", "File2:30:Line30"]}).items + let l = g:Xgetlist({'lines' : ["File2:20:Line20", "File2:30:Line30"]}).items call assert_equal(2, len(l)) call assert_equal(30, l[1].lnum) - call assert_equal({}, g:Xgetlist({'text' : 10})) - call assert_equal([], g:Xgetlist({'text' : []}).items) + call assert_equal({}, g:Xgetlist({'lines' : 10})) + call assert_equal({}, g:Xgetlist({'lines' : 'File1:10:Line10'})) + call assert_equal([], g:Xgetlist({'lines' : []}).items) + call assert_equal([], g:Xgetlist({'lines' : [10, 20]}).items) " Make sure that the quickfix stack is not modified call assert_equal(0, g:Xgetlist({'nr' : '$'}).nr) endfunc -func Test_get_list_from_text() - call XgetListFromText('c') - call XgetListFromText('l') +func Test_get_list_from_lines() + call XgetListFromLines('c') + call XgetListFromLines('l') endfunc " Tests for the quickfix list id @@ -2567,7 +2566,7 @@ func Xqfid_tests(cchar) call g:Xsetlist([], 'a', {'id':start_id, 'context':[1,2]}) call assert_equal([1,2], g:Xgetlist({'nr':1, 'context':1}).context) - call g:Xsetlist([], 'a', {'id':start_id+1, 'text':'F1:10:L10'}) + call g:Xsetlist([], 'a', {'id':start_id+1, 'lines':['F1:10:L10']}) call assert_equal('L10', g:Xgetlist({'nr':2, 'items':1}).items[0].text) call assert_equal(-1, g:Xsetlist([], 'a', {'id':999, 'title':'Vim'})) call assert_equal(-1, g:Xsetlist([], 'a', {'id':'abc', 'title':'Vim'})) diff --git a/src/version.c b/src/version.c index d5257a7579..4eff429707 100644 --- a/src/version.c +++ b/src/version.c @@ -769,6 +769,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1031, /**/ 1030, /**/ From 9ac9dfa9e2b20659e5806982f027fa4fd637c3c7 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 1 Sep 2017 18:41:26 +0200 Subject: [PATCH 06/26] patch 8.0.1032: "make tags" doesn't work well on MS-Windows Problem: "make tags" doesn't work well on MS-Windows. Solution: Add or fix tags target. (Ken Takata) --- src/Make_cyg_ming.mak | 10 ++++++++++ src/Make_mvc.mak | 5 +++-- src/version.c | 2 ++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/Make_cyg_ming.mak b/src/Make_cyg_ming.mak index 52db561380..de2c5df524 100644 --- a/src/Make_cyg_ming.mak +++ b/src/Make_cyg_ming.mak @@ -76,6 +76,10 @@ endif # Set to yes to enable terminal support. TERMINAL=no +ifndef CTAGS +# this assumes ctags is Exuberant ctags +CTAGS = ctags -I INIT+ --fields=+S +endif # Link against the shared version of libstdc++ by default. Set # STATIC_STDCPLUS to "yes" to link against static version instead. @@ -885,6 +889,12 @@ xxd/xxd.exe: xxd/xxd.c GvimExt/gvimext.dll: GvimExt/gvimext.cpp GvimExt/gvimext.rc GvimExt/gvimext.h $(MAKE) -C GvimExt -f Make_ming.mak CROSS=$(CROSS) CROSS_COMPILE=$(CROSS_COMPILE) CXX='$(CXX)' STATIC_STDCPLUS=$(STATIC_STDCPLUS) +tags: notags + $(CTAGS) *.c *.cpp *.h if_perl.xs + +notags: + -$(DEL) tags + clean: -$(DEL) $(OUTDIR)$(DIRSLASH)*.o -$(DEL) $(OUTDIR)$(DIRSLASH)*.res diff --git a/src/Make_mvc.mak b/src/Make_mvc.mak index c8c1d11736..33d6dcbf2f 100644 --- a/src/Make_mvc.mak +++ b/src/Make_mvc.mak @@ -344,7 +344,8 @@ FEATURES = HUGE !endif !ifndef CTAGS -CTAGS = ctags +# this assumes ctags is Exuberant ctags +CTAGS = ctags -I INIT+ --fields=+S !endif !ifndef CSCOPE @@ -1220,7 +1221,7 @@ GvimExt/gvimext.dll: GvimExt/gvimext.cpp GvimExt/gvimext.rc GvimExt/gvimext.h tags: notags - $(CTAGS) *.c *.cpp *.h if_perl.xs proto\*.pro + $(CTAGS) *.c *.cpp *.h if_perl.xs notags: - if exist tags del tags diff --git a/src/version.c b/src/version.c index 4eff429707..beb8ee7203 100644 --- a/src/version.c +++ b/src/version.c @@ -769,6 +769,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1032, /**/ 1031, /**/ From 995e4afcfe60aa3c214ba680e7b027a4e05cf62b Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 1 Sep 2017 20:24:03 +0200 Subject: [PATCH 07/26] patch 8.0.1033: detecting background color does not work in screen Problem: Detecting background color does not work in screen, even when it is working like an xterm. Solution: Make "screen.xterm" use termcap entries like an xterm. (Lubomir Rintel, closes #2048) When termresponse version is huge also recognize as not being an xterm. --- src/os_unix.c | 1 + src/term.c | 24 ++++++++++++++---------- src/version.c | 2 ++ 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/os_unix.c b/src/os_unix.c index f77debc8a3..b34c31645b 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -2280,6 +2280,7 @@ vim_is_xterm(char_u *name) || STRNICMP(name, "kterm", 5) == 0 || STRNICMP(name, "mlterm", 6) == 0 || STRNICMP(name, "rxvt", 4) == 0 + || STRNICMP(name, "screen.xterm", 12) == 0 || STRCMP(name, "builtin_xterm") == 0); } diff --git a/src/term.c b/src/term.c index 85292db857..7460be9772 100644 --- a/src/term.c +++ b/src/term.c @@ -4496,6 +4496,8 @@ check_termcode( /* eat it when at least one digit and ending in 'c' */ if (*T_CRV != NUL && i > 2 + (tp[0] != CSI) && tp[i] == 'c') { + int version = col; + LOG_TR("Received CRV response"); crv_status = STATUS_GOT; # ifdef FEAT_AUTOCMD @@ -4508,10 +4510,11 @@ check_termcode( switch_to_8bit(); /* rxvt sends its version number: "20703" is 2.7.3. + * Screen sends 40500. * Ignore it for when the user has set 'term' to xterm, * even though it's an rxvt. */ - if (col > 20000) - col = 0; + if (version > 20000) + version = 0; if (tp[1 + (tp[0] != CSI)] == '>' && semicols == 2) { @@ -4522,19 +4525,19 @@ check_termcode( if (!option_was_set((char_u *)"ttym")) { # ifdef TTYM_SGR - if (col >= 277) + if (version >= 277) set_option_value((char_u *)"ttym", 0L, (char_u *)"sgr", 0); else # endif /* if xterm version >= 95 use mouse dragging */ - if (col >= 95) + if (version >= 95) set_option_value((char_u *)"ttym", 0L, (char_u *)"xterm2", 0); } /* if xterm version >= 141 try to get termcap codes */ - if (col >= 141) + if (version >= 141) { LOG_TR("Enable checking for XT codes"); check_for_codes = TRUE; @@ -4543,7 +4546,7 @@ check_termcode( } /* libvterm sends 0;100;0 */ - if (col == 100 + if (version == 100 && STRNCMP(tp + extra - 2, "0;100;0c", 8) == 0) { /* If run from Vim $COLORS is set to the number of @@ -4558,24 +4561,25 @@ check_termcode( * compatible. */ # ifdef MACOS /* Mac Terminal.app sends 1;95;0 */ - if (col == 95 + if (version == 95 && STRNCMP(tp + extra - 2, "1;95;0c", 7) == 0) is_not_xterm = TRUE; # endif /* Gnome terminal sends 1;3801;0 or 1;4402;0. * xfce4-terminal sends 1;2802;0. + * screen sends 83;40500;0 * Assuming any version number over 2800 is not an - * xterm. */ + * xterm (without the limit for rxvt and screen). */ if (col >= 2800) is_not_xterm = TRUE; /* PuTTY sends 0;136;0 */ - if (col == 136 + if (version == 136 && STRNCMP(tp + extra - 2, "0;136;0c", 8) == 0) is_not_xterm = TRUE; /* Konsole sends 0;115;0 */ - if (col == 115 + if (version == 115 && STRNCMP(tp + extra - 2, "0;115;0c", 8) == 0) is_not_xterm = TRUE; diff --git a/src/version.c b/src/version.c index beb8ee7203..807b2f1ab9 100644 --- a/src/version.c +++ b/src/version.c @@ -769,6 +769,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1033, /**/ 1032, /**/ From 3346cc4ffb459ecddb97a8c19bcc5834afa4dead Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 2 Sep 2017 14:54:21 +0200 Subject: [PATCH 08/26] patch 8.0.1034: sending buffer lines to terminal doesn't work on MS-Windows Problem: Sending buffer lines to terminal doesn't work on MS-Windows. Solution: Send CTRL-D to mark the end of the text. (Yasuhiro Matsumoto, closes #2043) Add the "eof_chars" option. --- src/channel.c | 23 +++++++++++++++++++++++ src/proto/terminal.pro | 1 + src/structs.h | 6 +++++- src/terminal.c | 25 ++++++++++++++++++++++++- src/testdir/test_terminal.vim | 8 ++++---- src/version.c | 2 ++ 6 files changed, 59 insertions(+), 6 deletions(-) diff --git a/src/channel.c b/src/channel.c index b7a268a79a..94a762c610 100644 --- a/src/channel.c +++ b/src/channel.c @@ -1417,6 +1417,13 @@ channel_write_in(channel_T *channel) in_part->ch_buf_top = lnum; if (lnum > buf->b_ml.ml_line_count || lnum > in_part->ch_buf_bot) { +#if defined(WIN32) && defined(FEAT_TERMINAL) + /* Send CTRL-D or "eof_chars" to close stdin on Windows. A console + * application doesn't treat closing stdin like UNIX. */ + if (channel->ch_job != NULL) + term_send_eof(channel); +#endif + /* Writing is done, no longer need the buffer. */ in_part->ch_bufref.br_buf = NULL; ch_log(channel, "Finished writing all lines to channel"); @@ -4626,6 +4633,22 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2) return FAIL; } } + else if (STRCMP(hi->hi_key, "eof_chars") == 0) + { +# ifdef WIN3264 + char_u *p; + + if (!(supported2 & JO2_EOF_CHARS)) + break; + opt->jo_set2 |= JO2_EOF_CHARS; + p = opt->jo_eof_chars = get_tv_string_chk(item); + if (p == NULL) + { + EMSG2(_(e_invarg2), "term_opencmd"); + return FAIL; + } +# endif + } else if (STRCMP(hi->hi_key, "term_rows") == 0) { if (!(supported2 & JO2_TERM_ROWS)) diff --git a/src/proto/terminal.pro b/src/proto/terminal.pro index 2b05d341e2..3811ba7a51 100644 --- a/src/proto/terminal.pro +++ b/src/proto/terminal.pro @@ -16,6 +16,7 @@ int term_update_window(win_T *wp); int term_is_finished(buf_T *buf); int term_show_buffer(buf_T *buf); void term_change_in_curbuf(void); +void term_send_eof(channel_T *ch); int term_get_attr(buf_T *buf, linenr_T lnum, int col); char_u *term_get_status_text(term_T *term); int set_ref_in_term(int copyID); diff --git a/src/structs.h b/src/structs.h index 4030f6d51f..20b7ef8057 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1713,7 +1713,8 @@ struct channel_S { #define JO2_CURWIN 0x0200 /* "curwin" */ #define JO2_HIDDEN 0x0400 /* "hidden" */ #define JO2_TERM_OPENCMD 0x0800 /* "term_opencmd" */ -#define JO2_ALL 0x0FFF +#define JO2_EOF_CHARS 0x1000 /* "eof_chars" */ +#define JO2_ALL 0x1FFF #define JO_MODE_ALL (JO_MODE + JO_IN_MODE + JO_OUT_MODE + JO_ERR_MODE) #define JO_CB_ALL \ @@ -1779,6 +1780,9 @@ typedef struct char_u *jo_term_name; char_u *jo_term_opencmd; int jo_term_finish; +# ifdef WIN3264 + char_u *jo_eof_chars; +# endif #endif } jobopt_T; diff --git a/src/terminal.c b/src/terminal.c index 8d6fdb8e03..0a3e1b71f0 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -114,6 +114,7 @@ struct terminal_S { #ifdef WIN3264 void *tl_winpty_config; void *tl_winpty; + char_u *tl_eof_chars; #endif /* last known vterm size */ @@ -389,6 +390,11 @@ term_start(typval_T *argvar, jobopt_T *opt, int forceit) if (opt->jo_term_opencmd != NULL) term->tl_opencmd = vim_strsave(opt->jo_term_opencmd); +# ifdef WIN3264 + if (opt->jo_eof_chars != NULL) + term->tl_eof_chars = vim_strsave(opt->jo_eof_chars); +# endif + set_string_option_direct((char_u *)"buftype", -1, (char_u *)"terminal", OPT_FREE|OPT_LOCAL, 0); @@ -570,6 +576,9 @@ free_terminal(buf_T *buf) vim_free(term->tl_title); vim_free(term->tl_status_text); vim_free(term->tl_opencmd); +# ifdef WIN3264 + vim_free(term->tl_eof_chars); +# endif vim_free(term->tl_cursor_color); vim_free(term); buf->b_term = NULL; @@ -2821,7 +2830,7 @@ f_term_start(typval_T *argvars, typval_T *rettv) + JO_EXIT_CB + JO_CLOSE_CALLBACK, JO2_TERM_NAME + JO2_TERM_FINISH + JO2_HIDDEN + JO2_TERM_OPENCMD + JO2_TERM_COLS + JO2_TERM_ROWS + JO2_VERTICAL + JO2_CURWIN - + JO2_CWD + JO2_ENV) == FAIL) + + JO2_CWD + JO2_ENV + JO2_EOF_CHARS) == FAIL) return; if (opt.jo_vertical) @@ -3188,6 +3197,20 @@ terminal_enabled(void) return dyn_winpty_init(FALSE) == OK; } +/* + * Called when a channel has sent all the lines to a terminal. + * Send a CTRL-D to mark the end of the text. + */ + void +term_send_eof(channel_T *ch) +{ + term_T *term; + + for (term = first_term; term != NULL; term = term->tl_next) + if (term->tl_job == ch->ch_job) + channel_send(ch, PART_IN, term->tl_eof_chars != NULL + ? term->tl_eof_chars : (char_u *)"\004\r\n", 3, NULL); +} # else diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index b6c926f401..573db1e01d 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -489,22 +489,22 @@ func Test_terminal_noblock() endfunc func Test_terminal_write_stdin() - " Todo: make this work on all systems. - if !has('unix') + if !executable('wc') + call ch_log('Test_terminal_write_stdin() is skipped because system doesn''t have wc command') return endif new call setline(1, ['one', 'two', 'three']) %term wc call WaitFor('getline(1) != ""') - let nrs = split(getline(1)) + let nrs = split(getline('$')) call assert_equal(['3', '3', '14'], nrs) bwipe call setline(1, ['one', 'two', 'three', 'four']) 2,3term wc call WaitFor('getline(1) != ""') - let nrs = split(getline(1)) + let nrs = split(getline('$')) call assert_equal(['2', '2', '10'], nrs) bwipe diff --git a/src/version.c b/src/version.c index 807b2f1ab9..b76c2a9d43 100644 --- a/src/version.c +++ b/src/version.c @@ -769,6 +769,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1034, /**/ 1033, /**/ From ef68e4fa528165f8dd63156feeffc1af629b8d8a Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 2 Sep 2017 16:28:36 +0200 Subject: [PATCH 09/26] patch 8.0.1035: sending buffer lines to terminal doesn't work on MS-Windows Problem: Sending buffer lines to terminal doesn't work on MS-Windows. Solution: Use CR instead of NL after every line. Make the EOF text work properly. Add the ++eof argument to :terminal. --- runtime/doc/eval.txt | 6 ++++++ runtime/doc/terminal.txt | 20 +++++++++++++++----- src/channel.c | 13 +++++++++---- src/structs.h | 1 + src/terminal.c | 34 ++++++++++++++++++++++++++++++---- src/version.c | 2 ++ 6 files changed, 63 insertions(+), 13 deletions(-) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index b9f3c09b16..e8bf16e4e5 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -8141,6 +8141,12 @@ term_start({cmd}, {options}) *term_start()* have "%d" where the buffer number goes, e.g. "10split|buffer %d"; when not specified "botright sbuf %d" is used + "eof_chars" Text to send after all buffer lines were + written to the terminal. When not set + CTRL-D is used. For Python use CTRL-Z or + "exit()". For a shell use "exit". A CR + is always added. + {only on MS-Windows} {only available when compiled with the |+terminal| feature} diff --git a/runtime/doc/terminal.txt b/runtime/doc/terminal.txt index 9e903d26a4..7be6927a0b 100644 --- a/runtime/doc/terminal.txt +++ b/runtime/doc/terminal.txt @@ -133,6 +133,14 @@ Syntax ~ height. ++cols={width} Use {width} for the terminal window width. + ++eof={text} when using [range], text to send after + the last line was written. The default + is to send CTRL-D. A CR is appended. + E.g. for a shell use "++eof=exit" and + for Python "++eof=exit()". Special + codes can be used like with `:map`, + e.g. "" for CTRL-Z. + {only on MS-Windows} If you want to use more options use the |term_start()| function. @@ -141,11 +149,13 @@ When the buffer associated with the terminal is unloaded or wiped out the job is killed, similar to calling `job_stop(job, "kill")` So long as the job is running the window behaves like it contains a modified -buffer. Trying to close the window with `CTRL-W :close` or `CTRL-W :hide` -fails, unless "!" is added, in which case the job is ended. The text in the -window is lost. The buffer still exists, but getting it in a window with -`:buffer` will show an -empty buffer. +buffer. Trying to close the window with `CTRL-W :quit` fails. When using +`CTRL-W :quit!` the job is ended. The text in the window is lost. The buffer +still exists, but getting it in a window with `:buffer` will show an empty +buffer. + +Trying to close the window with `CTRL-W :close` also fails. Using +`CTRL-W :close!` will close the window and make the buffer hidden. You can use `CTRL-W :hide` to close the terminal window and make the buffer hidden, the job keeps running. The `:buffer` command can be used to turn the diff --git a/src/channel.c b/src/channel.c index 94a762c610..5a7e2a7301 100644 --- a/src/channel.c +++ b/src/channel.c @@ -1300,11 +1300,16 @@ write_buf_line(buf_T *buf, linenr_T lnum, channel_T *channel) return; memcpy((char *)p, (char *)line, len); - for (i = 0; i < len; ++i) - if (p[i] == NL) - p[i] = NUL; + if (channel->ch_write_text_mode) + p[len] = CAR; + else + { + for (i = 0; i < len; ++i) + if (p[i] == NL) + p[i] = NUL; - p[len] = NL; + p[len] = NL; + } p[len + 1] = NUL; channel_send(channel, PART_IN, p, len + 1, "write_buf_line"); vim_free(p); diff --git a/src/structs.h b/src/structs.h index 20b7ef8057..6cfb5f2f1e 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1632,6 +1632,7 @@ struct channel_S { int ch_last_msg_id; /* ID of the last message */ chanpart_T ch_part[PART_COUNT]; /* info for socket, out, err and in */ + int ch_write_text_mode; /* write buffer lines with CR, not NL */ char *ch_hostname; /* only for socket, allocated */ int ch_port; /* only for socket */ diff --git a/src/terminal.c b/src/terminal.c index 0a3e1b71f0..55575d14fe 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -496,6 +496,24 @@ ex_terminal(exarg_T *eap) opt.jo_term_cols = atoi((char *)ep + 1); p = skiptowhite(cmd); } + else if ((int)(p - cmd) == 3 && STRNICMP(cmd, "eof", 3) == 0 + && ep != NULL) + { +# ifdef WIN3264 + char_u *buf = NULL; + char_u *keys; + + p = skiptowhite(cmd); + *p = NUL; + keys = replace_termcodes(ep + 1, &buf, TRUE, TRUE, TRUE); + opt.jo_set2 |= JO2_EOF_CHARS; + opt.jo_eof_chars = vim_strsave(keys); + vim_free(buf); + *p = ' '; +# else + p = skiptowhite(cmd); +# endif + } else { if (*p) @@ -3069,8 +3087,6 @@ term_and_job_init( if (job == NULL) goto failed; - /* TODO: when all lines are written and the fd is closed, the command - * doesn't get EOF and hangs. */ if (opt->jo_set & JO_IN_BUF) job->jv_in_buf = buflist_findnr(opt->jo_io_buf[PART_IN]); @@ -3092,6 +3108,9 @@ term_and_job_init( GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)); + /* Write lines with CR instead of NL. */ + channel->ch_write_text_mode = TRUE; + jo = CreateJobObject(NULL, NULL); if (jo == NULL) goto failed; @@ -3208,8 +3227,15 @@ term_send_eof(channel_T *ch) for (term = first_term; term != NULL; term = term->tl_next) if (term->tl_job == ch->ch_job) - channel_send(ch, PART_IN, term->tl_eof_chars != NULL - ? term->tl_eof_chars : (char_u *)"\004\r\n", 3, NULL); + { + if (term->tl_eof_chars != NULL) + channel_send(ch, PART_IN, term->tl_eof_chars, + (int)STRLEN(term->tl_eof_chars), NULL); + else + /* Default: CTRL-D */ + channel_send(ch, PART_IN, (char_u *)"\004", 1, NULL); + channel_send(ch, PART_IN, (char_u *)"\r", 1, NULL); + } } # else diff --git a/src/version.c b/src/version.c index b76c2a9d43..520d46bef5 100644 --- a/src/version.c +++ b/src/version.c @@ -769,6 +769,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1035, /**/ 1034, /**/ From dada6d2a8e887309e88cb126f1251d81f91b4b9d Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 2 Sep 2017 17:18:35 +0200 Subject: [PATCH 10/26] patch 8.0.1036: ++eof argument for terminal only available on MS-Windows Problem: ++eof argument for terminal only available on MS-Windows. Solution: Also support ++eof on Unix. Add a test. --- src/channel.c | 7 ++--- src/structs.h | 2 -- src/terminal.c | 58 ++++++++++++++++------------------- src/testdir/test_terminal.vim | 31 ++++++++++++++++--- src/version.c | 2 ++ 5 files changed, 58 insertions(+), 42 deletions(-) diff --git a/src/channel.c b/src/channel.c index 5a7e2a7301..30a4304d8a 100644 --- a/src/channel.c +++ b/src/channel.c @@ -1422,9 +1422,8 @@ channel_write_in(channel_T *channel) in_part->ch_buf_top = lnum; if (lnum > buf->b_ml.ml_line_count || lnum > in_part->ch_buf_bot) { -#if defined(WIN32) && defined(FEAT_TERMINAL) - /* Send CTRL-D or "eof_chars" to close stdin on Windows. A console - * application doesn't treat closing stdin like UNIX. */ +#if defined(FEAT_TERMINAL) + /* Send CTRL-D or "eof_chars" to close stdin on MS-Windows. */ if (channel->ch_job != NULL) term_send_eof(channel); #endif @@ -4640,7 +4639,6 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2) } else if (STRCMP(hi->hi_key, "eof_chars") == 0) { -# ifdef WIN3264 char_u *p; if (!(supported2 & JO2_EOF_CHARS)) @@ -4652,7 +4650,6 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2) EMSG2(_(e_invarg2), "term_opencmd"); return FAIL; } -# endif } else if (STRCMP(hi->hi_key, "term_rows") == 0) { diff --git a/src/structs.h b/src/structs.h index 6cfb5f2f1e..f19377e36a 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1781,9 +1781,7 @@ typedef struct char_u *jo_term_name; char_u *jo_term_opencmd; int jo_term_finish; -# ifdef WIN3264 char_u *jo_eof_chars; -# endif #endif } jobopt_T; diff --git a/src/terminal.c b/src/terminal.c index 55575d14fe..faa74f7f47 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -110,11 +110,11 @@ struct terminal_S { int tl_channel_closed; int tl_finish; /* 'c' for ++close, 'o' for ++open */ char_u *tl_opencmd; + char_u *tl_eof_chars; #ifdef WIN3264 void *tl_winpty_config; void *tl_winpty; - char_u *tl_eof_chars; #endif /* last known vterm size */ @@ -390,10 +390,8 @@ term_start(typval_T *argvar, jobopt_T *opt, int forceit) if (opt->jo_term_opencmd != NULL) term->tl_opencmd = vim_strsave(opt->jo_term_opencmd); -# ifdef WIN3264 if (opt->jo_eof_chars != NULL) term->tl_eof_chars = vim_strsave(opt->jo_eof_chars); -# endif set_string_option_direct((char_u *)"buftype", -1, (char_u *)"terminal", OPT_FREE|OPT_LOCAL, 0); @@ -499,7 +497,6 @@ ex_terminal(exarg_T *eap) else if ((int)(p - cmd) == 3 && STRNICMP(cmd, "eof", 3) == 0 && ep != NULL) { -# ifdef WIN3264 char_u *buf = NULL; char_u *keys; @@ -510,9 +507,6 @@ ex_terminal(exarg_T *eap) opt.jo_eof_chars = vim_strsave(keys); vim_free(buf); *p = ' '; -# else - p = skiptowhite(cmd); -# endif } else { @@ -594,9 +588,7 @@ free_terminal(buf_T *buf) vim_free(term->tl_title); vim_free(term->tl_status_text); vim_free(term->tl_opencmd); -# ifdef WIN3264 vim_free(term->tl_eof_chars); -# endif vim_free(term->tl_cursor_color); vim_free(term); buf->b_term = NULL; @@ -2917,6 +2909,32 @@ f_term_wait(typval_T *argvars, typval_T *rettv UNUSED) } } +/* + * Called when a channel has sent all the lines to a terminal. + * Send a CTRL-D to mark the end of the text. + */ + void +term_send_eof(channel_T *ch) +{ + term_T *term; + + for (term = first_term; term != NULL; term = term->tl_next) + if (term->tl_job == ch->ch_job) + { + if (term->tl_eof_chars != NULL) + { + channel_send(ch, PART_IN, term->tl_eof_chars, + (int)STRLEN(term->tl_eof_chars), NULL); + channel_send(ch, PART_IN, (char_u *)"\r", 1, NULL); + } +# ifdef WIN3264 + else + /* Default: CTRL-D */ + channel_send(ch, PART_IN, (char_u *)"\004\r", 2, NULL); +# endif + } +} + # if defined(WIN3264) || defined(PROTO) /************************************** @@ -3216,28 +3234,6 @@ terminal_enabled(void) return dyn_winpty_init(FALSE) == OK; } -/* - * Called when a channel has sent all the lines to a terminal. - * Send a CTRL-D to mark the end of the text. - */ - void -term_send_eof(channel_T *ch) -{ - term_T *term; - - for (term = first_term; term != NULL; term = term->tl_next) - if (term->tl_job == ch->ch_job) - { - if (term->tl_eof_chars != NULL) - channel_send(ch, PART_IN, term->tl_eof_chars, - (int)STRLEN(term->tl_eof_chars), NULL); - else - /* Default: CTRL-D */ - channel_send(ch, PART_IN, (char_u *)"\004", 1, NULL); - channel_send(ch, PART_IN, (char_u *)"\r", 1, NULL); - } -} - # else /************************************** diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index 573db1e01d..c70b612953 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -490,24 +490,47 @@ endfunc func Test_terminal_write_stdin() if !executable('wc') - call ch_log('Test_terminal_write_stdin() is skipped because system doesn''t have wc command') - return + throw 'skipped: wc command not available' endif new call setline(1, ['one', 'two', 'three']) %term wc - call WaitFor('getline(1) != ""') + call WaitFor('getline("$") =~ "3"') let nrs = split(getline('$')) call assert_equal(['3', '3', '14'], nrs) bwipe + new call setline(1, ['one', 'two', 'three', 'four']) 2,3term wc - call WaitFor('getline(1) != ""') + call WaitFor('getline("$") =~ "2"') let nrs = split(getline('$')) call assert_equal(['2', '2', '10'], nrs) bwipe + if executable('python') + new + call setline(1, ['print("hello")']) + 1term ++eof=exit() python + " MS-Windows echoes the input, Unix doesn't. + call WaitFor('getline("$") =~ "exit" || getline(1) =~ "hello"') + if getline(1) =~ 'hello' + call assert_equal('hello', getline(1)) + else + call assert_equal('hello', getline(line('$') - 1)) + endif + bwipe + + if has('win32') + new + call setline(1, ['print("hello")']) + 1term ++eof= python + call WaitFor('getline("$") =~ "Z"') + call assert_equal('hello', getline(line('$') - 1)) + bwipe + endif + endif + bwipe! endfunc diff --git a/src/version.c b/src/version.c index 520d46bef5..579f0a2b60 100644 --- a/src/version.c +++ b/src/version.c @@ -769,6 +769,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1036, /**/ 1035, /**/ From da22b8cc8b1b96fabd5a4c35c57b04a351340fb1 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 2 Sep 2017 18:01:50 +0200 Subject: [PATCH 11/26] patch 8.0.1037: "icase" of 'diffopt' is not used for highlighting Problem: "icase" of 'diffopt' is not used for highlighting differences. Solution: Also use "icase". (Rick Howe) --- src/diff.c | 57 +++++++++++++++++++++++++++++++---- src/testdir/test_diffmode.vim | 8 +++-- src/version.c | 2 ++ 3 files changed, 59 insertions(+), 8 deletions(-) diff --git a/src/diff.c b/src/diff.c index dac39c21e8..cd3ffa48f1 100644 --- a/src/diff.c +++ b/src/diff.c @@ -1949,6 +1949,40 @@ diffopt_horizontal(void) return (diff_flags & DIFF_HORIZONTAL) != 0; } +/* + * Compare the characters at "p1" and "p2". If they are equal (possibly + * ignoring case) return TRUE and set "len" to the number of bytes. + */ + static int +diff_equal_char(char_u *p1, char_u *p2, int *len) +{ +#ifdef FEAT_MBYTE + int l = (*mb_ptr2len)(p1); + + if (l != (*mb_ptr2len)(p2)) + return FALSE; + if (l > 1) + { + if (STRNCMP(p1, p2, l) != 0 + && (!enc_utf8 + || !(diff_flags & DIFF_ICASE) + || utf_fold(utf_ptr2char(p1)) + != utf_fold(utf_ptr2char(p2)))) + return FALSE; + *len = l; + } + else +#endif + { + if ((*p1 != *p2) + && (!(diff_flags & DIFF_ICASE) + || TOLOWER_LOC(*p1) != TOLOWER_LOC(*p2))) + return FALSE; + *len = 1; + } + return TRUE; +} + /* * Find the difference within a changed line. * Returns TRUE if the line was added, no other buffer has it. @@ -1969,6 +2003,10 @@ diff_find_change( int idx; int off; int added = TRUE; +#ifdef FEAT_MBYTE + char_u *p1, *p2; + int l; +#endif /* Make a copy of the line, the next ml_get() will invalidate it. */ line_org = vim_strsave(ml_get_buf(wp->w_buffer, lnum, FALSE)); @@ -2017,10 +2055,11 @@ diff_find_change( } else { - if (line_org[si_org] != line_new[si_new]) + if (!diff_equal_char(line_org + si_org, line_new + si_new, + &l)) break; - ++si_org; - ++si_new; + si_org += l; + si_new += l; } } #ifdef FEAT_MBYTE @@ -2056,10 +2095,16 @@ diff_find_change( } else { - if (line_org[ei_org] != line_new[ei_new]) + p1 = line_org + ei_org; + p2 = line_new + ei_new; +#ifdef FEAT_MBYTE + p1 -= (*mb_head_off)(line_org, p1); + p2 -= (*mb_head_off)(line_new, p2); +#endif + if (!diff_equal_char(p1, p2, &l)) break; - --ei_org; - --ei_new; + ei_org -= l; + ei_new -= l; } } if (*endp < ei_org) diff --git a/src/testdir/test_diffmode.vim b/src/testdir/test_diffmode.vim index 088ec5ccf6..3625a68e5a 100644 --- a/src/testdir/test_diffmode.vim +++ b/src/testdir/test_diffmode.vim @@ -280,13 +280,13 @@ func Test_diffopt_icase() set diffopt=icase,foldcolumn:0 e one - call setline(1, ['One', 'Two', 'Three', 'Four']) + call setline(1, ['One', 'Two', 'Three', 'Four', 'Fi#ve']) redraw let normattr = screenattr(1, 1) diffthis botright vert new two - call setline(1, ['one', 'TWO', 'Three ', 'Four']) + call setline(1, ['one', 'TWO', 'Three ', 'Four', 'fI=VE']) diffthis redraw @@ -295,6 +295,10 @@ func Test_diffopt_icase() call assert_notequal(normattr, screenattr(3, 1)) call assert_equal(normattr, screenattr(4, 1)) + let dtextattr = screenattr(5, 3) + call assert_notequal(dtextattr, screenattr(5, 1)) + call assert_notequal(dtextattr, screenattr(5, 5)) + diffoff! %bwipe! set diffopt& diff --git a/src/version.c b/src/version.c index 579f0a2b60..8af46882e4 100644 --- a/src/version.c +++ b/src/version.c @@ -769,6 +769,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1037, /**/ 1036, /**/ From cf4b00c856ef714482d8d060332ac9a4d74e6b88 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 2 Sep 2017 18:33:56 +0200 Subject: [PATCH 12/26] patch 8.0.1038: strike-through text not supported Problem: Strike-through text not supported. Solution: Add support for the "strikethrough" attribute. (Christian Brabandt, Ken Takata) --- runtime/doc/eval.txt | 1 + runtime/doc/options.txt | 1 + runtime/doc/syntax.txt | 10 ++++++---- src/evalfunc.c | 4 ++++ src/gui.c | 5 +++++ src/gui.h | 1 + src/gui_gtk_x11.c | 39 +++++++++++++++++++++++++++++---------- src/gui_mac.c | 5 +++++ src/gui_w32.c | 12 ++++++++++++ src/gui_x11.c | 10 ++++++++++ src/option.c | 2 ++ src/screen.c | 11 ++++++++++- src/syntax.c | 6 ++++-- src/term.c | 7 +++++++ src/term.h | 4 ++++ src/terminal.c | 4 ++-- src/version.c | 2 ++ src/vim.h | 3 ++- 18 files changed, 107 insertions(+), 20 deletions(-) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index e8bf16e4e5..aea1cce3a4 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -7723,6 +7723,7 @@ synIDattr({synID}, {what} [, {mode}]) *synIDattr()* "standout" "1" if standout "underline" "1" if underlined "undercurl" "1" if undercurled + "strike" "1" if strikethrough Example (echoes the color of the syntax item under the cursor): > diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 0018eaaacb..859fbe8f75 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -4105,6 +4105,7 @@ A jump table for the options with a short description can be found at |Q_op|. s standout (termcap entry "so" and "se") u underline (termcap entry "us" and "ue") c undercurl (termcap entry "Cs" and "Ce") + t strikethrough (termcap entry "Ts" and "Te") n no highlighting - no highlighting : use a highlight group diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt index feeadb3d30..8f887c4288 100644 --- a/runtime/doc/syntax.txt +++ b/runtime/doc/syntax.txt @@ -4699,13 +4699,14 @@ the same syntax file on all terminals, and use the optimal highlighting. *bold* *underline* *undercurl* *inverse* *italic* *standout* - *nocombine* + *nocombine* *strikethrough* term={attr-list} *attr-list* *highlight-term* *E418* attr-list is a comma separated list (without spaces) of the following items (in any order): bold underline undercurl not always available + strikethrough not always available reverse inverse same as reverse italic @@ -4716,8 +4717,8 @@ term={attr-list} *attr-list* *highlight-term* *E418* Note that "bold" can be used here and by using a bold font. They have the same effect. "undercurl" is a curly underline. When "undercurl" is not possible - then "underline" is used. In general "undercurl" is only available in - the GUI. The color is set with |highlight-guisp|. + then "underline" is used. In general "undercurl" and "strikethrough" + is only available in the GUI. The color is set with |highlight-guisp|. start={term-list} *highlight-start* *E422* stop={term-list} *term-list* *highlight-stop* @@ -4882,7 +4883,8 @@ guifg={color-name} *highlight-guifg* guibg={color-name} *highlight-guibg* guisp={color-name} *highlight-guisp* These give the foreground (guifg), background (guibg) and special - (guisp) color to use in the GUI. "guisp" is used for undercurl. + (guisp) color to use in the GUI. "guisp" is used for undercurl and + strikethrough. There are a few special names: NONE no color (transparent) bg use normal background color diff --git a/src/evalfunc.c b/src/evalfunc.c index d11d96db94..1cdb6b682a 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -11843,6 +11843,10 @@ f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv) case 's': if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */ p = highlight_color(id, what, modec); + /* strikeout */ + else if (TOLOWER_ASC(what[1]) == 't' && + TOLOWER_ASC(what[2]) == 'r') + p = highlight_has_attr(id, HL_STRIKETHROUGH, modec); else /* standout */ p = highlight_has_attr(id, HL_STANDOUT, modec); break; diff --git a/src/gui.c b/src/gui.c index f774750f2b..97fac50432 100644 --- a/src/gui.c +++ b/src/gui.c @@ -2396,6 +2396,7 @@ gui_outstr_nowrap( /* Do we underline the text? */ if (hl_mask_todo & HL_UNDERLINE) draw_flags |= DRAW_UNDERL; + #else /* Do we underline the text? */ if ((hl_mask_todo & HL_UNDERLINE) || (hl_mask_todo & HL_ITALIC)) @@ -2405,6 +2406,10 @@ gui_outstr_nowrap( if (hl_mask_todo & HL_UNDERCURL) draw_flags |= DRAW_UNDERC; + /* Do we strikethrough the text? */ + if (hl_mask_todo & HL_STRIKETHROUGH) + draw_flags |= DRAW_STRIKE; + /* Do we draw transparently? */ if (flags & GUI_MON_TRS_CURSOR) draw_flags |= DRAW_TRANSP; diff --git a/src/gui.h b/src/gui.h index 476971624c..37cc239926 100644 --- a/src/gui.h +++ b/src/gui.h @@ -142,6 +142,7 @@ # define DRAW_ITALIC 0x10 /* draw italic text */ #endif #define DRAW_CURSOR 0x20 /* drawing block cursor (win32) */ +#define DRAW_STRIKE 0x40 /* strikethrough */ /* For our own tearoff menu item */ #define TEAR_STRING "-->Detach" diff --git a/src/gui_gtk_x11.c b/src/gui_gtk_x11.c index 3d4ac93ae4..361f16c659 100644 --- a/src/gui_gtk_x11.c +++ b/src/gui_gtk_x11.c @@ -5908,6 +5908,27 @@ draw_under(int flags, int row, int col, int cells) #endif } + /* Draw a strikethrough line */ + if (flags & DRAW_STRIKE) + { +#if GTK_CHECK_VERSION(3,0,0) + cairo_set_line_width(cr, 1.0); + cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT); + cairo_set_source_rgba(cr, + gui.spcolor->red, gui.spcolor->green, gui.spcolor->blue, + gui.spcolor->alpha); + cairo_move_to(cr, FILL_X(col), y + 1 - gui.char_height/2 + 0.5); + cairo_line_to(cr, FILL_X(col + cells), y + 1 - gui.char_height/2 + 0.5); + cairo_stroke(cr); +#else + gdk_gc_set_foreground(gui.text_gc, gui.spcolor); + gdk_draw_line(gui.drawarea->window, gui.text_gc, + FILL_X(col), y + 1 - gui.char_height/2, + FILL_X(col + cells), y + 1 - gui.char_height/2); + gdk_gc_set_foreground(gui.text_gc, gui.fgcolor); +#endif + } + /* Underline: draw a line at the bottom of the character cell. */ if (flags & DRAW_UNDERL) { @@ -5916,16 +5937,14 @@ draw_under(int flags, int row, int col, int cells) if (p_linespace > 1) y -= p_linespace - 1; #if GTK_CHECK_VERSION(3,0,0) - { - cairo_set_line_width(cr, 1.0); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT); - cairo_set_source_rgba(cr, - gui.fgcolor->red, gui.fgcolor->green, gui.fgcolor->blue, - gui.fgcolor->alpha); - cairo_move_to(cr, FILL_X(col), y + 0.5); - cairo_line_to(cr, FILL_X(col + cells), y + 0.5); - cairo_stroke(cr); - } + cairo_set_line_width(cr, 1.0); + cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT); + cairo_set_source_rgba(cr, + gui.fgcolor->red, gui.fgcolor->green, gui.fgcolor->blue, + gui.fgcolor->alpha); + cairo_move_to(cr, FILL_X(col), y + 0.5); + cairo_line_to(cr, FILL_X(col + cells), y + 0.5); + cairo_stroke(cr); #else gdk_draw_line(gui.drawarea->window, gui.text_gc, FILL_X(col), y, diff --git a/src/gui_mac.c b/src/gui_mac.c index dea648ac88..8803487dea 100644 --- a/src/gui_mac.c +++ b/src/gui_mac.c @@ -3899,6 +3899,11 @@ draw_string_QD(int row, int col, char_u *s, int len, int flags) MoveTo(FILL_X(col), FILL_Y(row + 1) - 1); LineTo(FILL_X(col + len) - 1, FILL_Y(row + 1) - 1); } + if (flags & DRAW_STRIKE) + { + MoveTo(FILL_X(col), FILL_Y(row + 1) - gui.char_height/2); + LineTo(FILL_X(col + len) - 1, FILL_Y(row + 1) - gui.char_height/2); + } } if (flags & DRAW_UNDERC) diff --git a/src/gui_w32.c b/src/gui_w32.c index e94379ba7c..c4a57e675a 100644 --- a/src/gui_w32.c +++ b/src/gui_w32.c @@ -6427,6 +6427,18 @@ gui_mch_draw_string( DeleteObject(SelectObject(s_hdc, old_pen)); } + /* Strikethrough */ + if (flags & DRAW_STRIKE) + { + hpen = CreatePen(PS_SOLID, 1, gui.currSpColor); + old_pen = SelectObject(s_hdc, hpen); + y = FILL_Y(row + 1) - gui.char_height/2; + MoveToEx(s_hdc, FILL_X(col), y, NULL); + /* Note: LineTo() excludes the last pixel in the line. */ + LineTo(s_hdc, FILL_X(col + len), y); + DeleteObject(SelectObject(s_hdc, old_pen)); + } + /* Undercurl */ if (flags & DRAW_UNDERC) { diff --git a/src/gui_x11.c b/src/gui_x11.c index a638222251..1e790a81c4 100644 --- a/src/gui_x11.c +++ b/src/gui_x11.c @@ -2542,6 +2542,16 @@ gui_mch_draw_string( y, FILL_X(col + cells) - 1, y); } + if (flags & DRAW_STRIKE) + { + int y = FILL_Y(row + 1) - gui.char_height/2; + + XSetForeground(gui.dpy, gui.text_gc, prev_sp_color); + XDrawLine(gui.dpy, gui.wid, gui.text_gc, FILL_X(col), + y, FILL_X(col + cells) - 1, y); + XSetForeground(gui.dpy, gui.text_gc, prev_fg_color); + } + #ifdef FEAT_XFONTSET if (current_fontset != NULL) XSetClipMask(gui.dpy, gui.text_gc, None); diff --git a/src/option.c b/src/option.c index 5f8489fdd4..a1304c9447 100644 --- a/src/option.c +++ b/src/option.c @@ -3216,8 +3216,10 @@ static struct vimoption options[] = p_term("t_so", T_SO) p_term("t_SR", T_CSR) p_term("t_sr", T_SR) + p_term("t_Te", T_STE) p_term("t_te", T_TE) p_term("t_ti", T_TI) + p_term("t_Ts", T_STS) p_term("t_ts", T_TS) p_term("t_u7", T_U7) p_term("t_ue", T_UE) diff --git a/src/screen.c b/src/screen.c index c3bcd3b446..ca7b658360 100644 --- a/src/screen.c +++ b/src/screen.c @@ -235,7 +235,7 @@ redraw_later_clear(void) else #endif /* Use attributes that is very unlikely to appear in text. */ - screen_attr = HL_BOLD | HL_UNDERLINE | HL_INVERSE; + screen_attr = HL_BOLD | HL_UNDERLINE | HL_INVERSE | HL_STRIKETHROUGH; } /* @@ -8086,6 +8086,8 @@ screen_start_highlight(int attr) out_str(T_CZH); if ((attr & HL_INVERSE) && T_MR != NULL) /* inverse (reverse) */ out_str(T_MR); + if ((attr & HL_STRIKETHROUGH) && T_STS != NULL) /* strike */ + out_str(T_STS); /* * Output the color or start string after bold etc., in case the @@ -8210,6 +8212,13 @@ screen_stop_highlight(void) else out_str(T_CZR); } + if (screen_attr & HL_STRIKETHROUGH) + { + if (STRCMP(T_STE, T_ME) == 0) + do_ME = TRUE; + else + out_str(T_STE); + } if (do_ME || (screen_attr & (HL_BOLD | HL_INVERSE))) out_str(T_ME); diff --git a/src/syntax.c b/src/syntax.c index 7303575202..00e292932d 100644 --- a/src/syntax.c +++ b/src/syntax.c @@ -86,9 +86,9 @@ static int include_link = 0; /* when 2 include "link" and "clear" */ */ static char *(hl_name_table[]) = {"bold", "standout", "underline", "undercurl", - "italic", "reverse", "inverse", "nocombine", "NONE"}; + "italic", "reverse", "inverse", "nocombine", "strikethrough", "NONE"}; static int hl_attr_table[] = - {HL_BOLD, HL_STANDOUT, HL_UNDERLINE, HL_UNDERCURL, HL_ITALIC, HL_INVERSE, HL_INVERSE, HL_NOCOMBINE, 0}; + {HL_BOLD, HL_STANDOUT, HL_UNDERLINE, HL_UNDERCURL, HL_ITALIC, HL_INVERSE, HL_INVERSE, HL_NOCOMBINE, HL_STRIKETHROUGH, 0}; #define ATTR_COMBINE(attr_a, attr_b) ((((attr_b) & HL_NOCOMBINE) ? attr_b : (attr_a)) | (attr_b)) static int get_attr_entry(garray_T *table, attrentry_T *aep); @@ -9951,6 +9951,8 @@ highlight_changed(void) break; case 'c': attr |= HL_UNDERCURL; break; + case 't': attr |= HL_STRIKETHROUGH; + break; case ':': ++p; /* highlight group name */ if (attr || *p == NUL) /* no combinations */ return FAIL; diff --git a/src/term.c b/src/term.c index 7460be9772..413d4bb88d 100644 --- a/src/term.c +++ b/src/term.c @@ -217,6 +217,8 @@ static struct builtin_term builtin_termcaps[] = {(int)KS_US, IF_EB("\033|8h", ESC_STR "|8h")}, /* HL_UNDERLINE */ {(int)KS_UCE, IF_EB("\033|8C", ESC_STR "|8C")}, /* HL_UNDERCURL */ {(int)KS_UCS, IF_EB("\033|8c", ESC_STR "|8c")}, /* HL_UNDERCURL */ + {(int)KS_STE, IF_EB("\033|4C", ESC_STR "|4C")}, /* HL_STRIKETHROUGH */ + {(int)KS_STS, IF_EB("\033|4c", ESC_STR "|4c")}, /* HL_STRIKETHROUGH */ {(int)KS_CZR, IF_EB("\033|4H", ESC_STR "|4H")}, /* HL_ITALIC */ {(int)KS_CZH, IF_EB("\033|4h", ESC_STR "|4h")}, /* HL_ITALIC */ {(int)KS_VB, IF_EB("\033|f", ESC_STR "|f")}, @@ -831,6 +833,8 @@ static struct builtin_term builtin_termcaps[] = {(int)KS_MD, IF_EB("\033[1m", ESC_STR "[1m")}, {(int)KS_UE, IF_EB("\033[m", ESC_STR "[m")}, {(int)KS_US, IF_EB("\033[4m", ESC_STR "[4m")}, + {(int)KS_STE, IF_EB("\033[29m", ESC_STR "[29m")}, + {(int)KS_STS, IF_EB("\033[9m", ESC_STR "[9m")}, {(int)KS_MS, "y"}, {(int)KS_UT, "y"}, {(int)KS_LE, "\b"}, @@ -1151,6 +1155,8 @@ static struct builtin_term builtin_termcaps[] = {(int)KS_US, "[US]"}, {(int)KS_UCE, "[UCE]"}, {(int)KS_UCS, "[UCS]"}, + {(int)KS_STE, "[STE]"}, + {(int)KS_STS, "[STS]"}, {(int)KS_MS, "[MS]"}, {(int)KS_UT, "[UT]"}, {(int)KS_XN, "[XN]"}, @@ -1595,6 +1601,7 @@ set_termname(char_u *term) {KS_MD, "md"}, {KS_SE, "se"}, {KS_SO, "so"}, {KS_CZH,"ZH"}, {KS_CZR,"ZR"}, {KS_UE, "ue"}, {KS_US, "us"}, {KS_UCE, "Ce"}, {KS_UCS, "Cs"}, + {KS_STE,"Te"}, {KS_STS,"Ts"}, {KS_CM, "cm"}, {KS_SR, "sr"}, {KS_CRI,"RI"}, {KS_VB, "vb"}, {KS_KS, "ks"}, {KS_KE, "ke"}, {KS_TI, "ti"}, {KS_TE, "te"}, diff --git a/src/term.h b/src/term.h index 0fedfeaa85..b95b4f6de8 100644 --- a/src/term.h +++ b/src/term.h @@ -55,6 +55,8 @@ enum SpecialKey KS_US, /* underscore (underline) mode */ KS_UCE, /* exit undercurl mode */ KS_UCS, /* undercurl mode */ + KS_STE, /* exit strikethrough mode */ + KS_STS, /* strikethrough mode */ KS_MS, /* save to move cur in reverse mode */ KS_CM, /* cursor motion */ KS_SR, /* scroll reverse (backward) */ @@ -149,6 +151,8 @@ extern char_u *(term_strings[]); /* current terminal strings */ #define T_US (TERM_STR(KS_US)) /* underscore (underline) mode */ #define T_UCE (TERM_STR(KS_UCE)) /* exit undercurl mode */ #define T_UCS (TERM_STR(KS_UCS)) /* undercurl mode */ +#define T_STE (TERM_STR(KS_STE)) /* exit strikethrough mode */ +#define T_STS (TERM_STR(KS_STS)) /* strikethrough mode */ #define T_MS (TERM_STR(KS_MS)) /* save to move cur in reverse mode */ #define T_CM (TERM_STR(KS_CM)) /* cursor motion */ #define T_SR (TERM_STR(KS_SR)) /* scroll reverse (backward) */ diff --git a/src/terminal.c b/src/terminal.c index faa74f7f47..05c0fd9169 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -1735,7 +1735,7 @@ cell2attr(VTermScreenCellAttrs cellattrs, VTermColor cellfg, VTermColor cellbg) if (cellattrs.italic) attr |= HL_ITALIC; if (cellattrs.strike) - attr |= HL_STANDOUT; + attr |= HL_STRIKETHROUGH; if (cellattrs.reverse) attr |= HL_INVERSE; @@ -2451,7 +2451,7 @@ f_term_getattr(typval_T *argvars, typval_T *rettv) {"bold", HL_BOLD}, {"italic", HL_ITALIC}, {"underline", HL_UNDERLINE}, - {"strike", HL_STANDOUT}, + {"strike", HL_STRIKETHROUGH}, {"reverse", HL_INVERSE}, }; diff --git a/src/version.c b/src/version.c index 8af46882e4..e8e508f8a6 100644 --- a/src/version.c +++ b/src/version.c @@ -769,6 +769,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1038, /**/ 1037, /**/ diff --git a/src/vim.h b/src/vim.h index 7fea70b90e..77081e202a 100644 --- a/src/vim.h +++ b/src/vim.h @@ -681,7 +681,8 @@ extern int (*dyn_libintl_putenv)(const char *envstring); #define HL_UNDERCURL 0x10 #define HL_STANDOUT 0x20 #define HL_NOCOMBINE 0x40 -#define HL_ALL 0x7f +#define HL_STRIKETHROUGH 0x80 +#define HL_ALL 0xff /* special attribute addition: Put message in history */ #define MSG_HIST 0x1000 From b31cf2bb0be95d106bd8eef93cc07550591c1d0d Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 2 Sep 2017 19:45:19 +0200 Subject: [PATCH 13/26] patch 8.0.1039: cannot change a line in not current buffer Problem: Cannot change a line in a buffer other than the current one. Solution: Add setbufline(). (Yasuhiro Matsumoto, Ozaki Kiichi, closes #1953) --- runtime/doc/eval.txt | 26 ++++- src/Makefile | 1 + src/evalfunc.c | 178 ++++++++++++++++++++++------------- src/testdir/test_alot.vim | 1 + src/testdir/test_bufline.vim | 26 +++++ src/version.c | 2 + 6 files changed, 167 insertions(+), 67 deletions(-) create mode 100644 src/testdir/test_bufline.vim diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index aea1cce3a4..4eb68a0d78 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -2316,6 +2316,9 @@ searchpos({pattern} [, {flags} [, {stopline} [, {timeout}]]]) server2client({clientid}, {string}) Number send reply string serverlist() String get a list of available servers +setbufline( {expr}, {lnum}, {line}) + Number set line {lnum} to {line} in buffer + {expr} setbufvar({expr}, {varname}, {val}) none set {varname} in buffer {expr} to {val} setcharsearch({dict}) Dict set character search from {dict} @@ -6858,6 +6861,19 @@ serverlist() *serverlist()* Example: > :echo serverlist() < +setbufline({expr}, {lnum}, {text}) *setbufline()* + Set line {lnum} to {text} in buffer {expr}. To insert + lines use |append()|. + + For the use of {expr}, see |bufname()| above. + + {lnum} is used like with |setline()|. + This works like |setline()| for the specified buffer. + On success 0 is returned, on failure 1 is returned. + + If {expr} is not a valid buffer or {lnum} is not valid, an + error message is given. + setbufvar({expr}, {varname}, {val}) *setbufvar()* Set option or local variable {varname} in buffer {expr} to {val}. @@ -6926,13 +6942,19 @@ setfperm({fname}, {mode}) *setfperm()* *chmod* setline({lnum}, {text}) *setline()* Set line {lnum} of the current buffer to {text}. To insert - lines use |append()|. + lines use |append()|. To set lines in another buffer use + |setbufline()|. + {lnum} is used like with |getline()|. When {lnum} is just below the last line the {text} will be added as a new line. + If this succeeds, 0 is returned. If this fails (most likely - because {lnum} is invalid) 1 is returned. Example: > + because {lnum} is invalid) 1 is returned. + + Example: > :call setline(5, strftime("%c")) + < When {text} is a |List| then line {lnum} and following lines will be set to the items in the list. Example: > :call setline(5, ['aaa', 'bbb', 'ccc']) diff --git a/src/Makefile b/src/Makefile index 1d1ded80fd..27615fa926 100644 --- a/src/Makefile +++ b/src/Makefile @@ -2122,6 +2122,7 @@ test_arglist \ test_autocmd \ test_backspace_opt \ test_breakindent \ + test_bufline \ test_bufwintabinfo \ test_cd \ test_cdo \ diff --git a/src/evalfunc.c b/src/evalfunc.c index 1cdb6b682a..626af7c500 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -328,6 +328,7 @@ static void f_searchpairpos(typval_T *argvars, typval_T *rettv); static void f_searchpos(typval_T *argvars, typval_T *rettv); static void f_server2client(typval_T *argvars, typval_T *rettv); static void f_serverlist(typval_T *argvars, typval_T *rettv); +static void f_setbufline(typval_T *argvars, typval_T *rettv); static void f_setbufvar(typval_T *argvars, typval_T *rettv); static void f_setcharsearch(typval_T *argvars, typval_T *rettv); static void f_setcmdpos(typval_T *argvars, typval_T *rettv); @@ -764,6 +765,7 @@ static struct fst {"searchpos", 1, 4, f_searchpos}, {"server2client", 2, 2, f_server2client}, {"serverlist", 0, 0, f_serverlist}, + {"setbufline", 3, 3, f_setbufline}, {"setbufvar", 3, 3, f_setbufvar}, {"setcharsearch", 1, 1, f_setcharsearch}, {"setcmdpos", 1, 1, f_setcmdpos}, @@ -9867,6 +9869,115 @@ f_serverlist(typval_T *argvars UNUSED, typval_T *rettv) rettv->vval.v_string = r; } +/* + * Set line or list of lines in buffer "buf". + */ + static void +set_buffer_lines(buf_T *buf, linenr_T lnum, typval_T *lines, typval_T *rettv) +{ + char_u *line = NULL; + list_T *l = NULL; + listitem_T *li = NULL; + long added = 0; + linenr_T lcount; + buf_T *curbuf_save; + int is_curbuf = buf == curbuf; + + if (buf == NULL || buf->b_ml.ml_mfp == NULL || lnum < 1) + { + rettv->vval.v_number = 1; /* FAIL */ + return; + } + + curbuf_save = curbuf; + curbuf = buf; + + lcount = curbuf->b_ml.ml_line_count; + + if (lines->v_type == VAR_LIST) + { + l = lines->vval.v_list; + li = l->lv_first; + } + else + line = get_tv_string_chk(lines); + + /* default result is zero == OK */ + for (;;) + { + if (l != NULL) + { + /* list argument, get next string */ + if (li == NULL) + break; + line = get_tv_string_chk(&li->li_tv); + li = li->li_next; + } + + rettv->vval.v_number = 1; /* FAIL */ + if (line == NULL || lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1) + break; + + /* When coming here from Insert mode, sync undo, so that this can be + * undone separately from what was previously inserted. */ + if (u_sync_once == 2) + { + u_sync_once = 1; /* notify that u_sync() was called */ + u_sync(TRUE); + } + + if (lnum <= curbuf->b_ml.ml_line_count) + { + /* existing line, replace it */ + if (u_savesub(lnum) == OK && ml_replace(lnum, line, TRUE) == OK) + { + changed_bytes(lnum, 0); + if (is_curbuf && lnum == curwin->w_cursor.lnum) + check_cursor_col(); + rettv->vval.v_number = 0; /* OK */ + } + } + else if (added > 0 || u_save(lnum - 1, lnum) == OK) + { + /* lnum is one past the last line, append the line */ + ++added; + if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK) + rettv->vval.v_number = 0; /* OK */ + } + + if (l == NULL) /* only one string argument */ + break; + ++lnum; + } + + if (added > 0) + appended_lines_mark(lcount, added); + + curbuf = curbuf_save; +} + +/* + * "setbufline()" function + */ + static void +f_setbufline(argvars, rettv) + typval_T *argvars; + typval_T *rettv; +{ + linenr_T lnum; + buf_T *buf; + + buf = get_buf_tv(&argvars[0], FALSE); + if (buf == NULL) + rettv->vval.v_number = 1; /* FAIL */ + else + { + lnum = get_tv_lnum_buf(&argvars[1], buf); + + set_buffer_lines(buf, lnum, &argvars[2], rettv); + } +} + /* * "setbufvar()" function */ @@ -10021,72 +10132,9 @@ f_setfperm(typval_T *argvars, typval_T *rettv) static void f_setline(typval_T *argvars, typval_T *rettv) { - linenr_T lnum; - char_u *line = NULL; - list_T *l = NULL; - listitem_T *li = NULL; - long added = 0; - linenr_T lcount = curbuf->b_ml.ml_line_count; + linenr_T lnum = get_tv_lnum(&argvars[0]); - lnum = get_tv_lnum(&argvars[0]); - if (argvars[1].v_type == VAR_LIST) - { - l = argvars[1].vval.v_list; - li = l->lv_first; - } - else - line = get_tv_string_chk(&argvars[1]); - - /* default result is zero == OK */ - for (;;) - { - if (l != NULL) - { - /* list argument, get next string */ - if (li == NULL) - break; - line = get_tv_string_chk(&li->li_tv); - li = li->li_next; - } - - rettv->vval.v_number = 1; /* FAIL */ - if (line == NULL || lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1) - break; - - /* When coming here from Insert mode, sync undo, so that this can be - * undone separately from what was previously inserted. */ - if (u_sync_once == 2) - { - u_sync_once = 1; /* notify that u_sync() was called */ - u_sync(TRUE); - } - - if (lnum <= curbuf->b_ml.ml_line_count) - { - /* existing line, replace it */ - if (u_savesub(lnum) == OK && ml_replace(lnum, line, TRUE) == OK) - { - changed_bytes(lnum, 0); - if (lnum == curwin->w_cursor.lnum) - check_cursor_col(); - rettv->vval.v_number = 0; /* OK */ - } - } - else if (added > 0 || u_save(lnum - 1, lnum) == OK) - { - /* lnum is one past the last line, append the line */ - ++added; - if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK) - rettv->vval.v_number = 0; /* OK */ - } - - if (l == NULL) /* only one string argument */ - break; - ++lnum; - } - - if (added > 0) - appended_lines_mark(lcount, added); + set_buffer_lines(curbuf, lnum, &argvars[1], rettv); } static void set_qf_ll_list(win_T *wp, typval_T *list_arg, typval_T *action_arg, typval_T *what_arg, typval_T *rettv); diff --git a/src/testdir/test_alot.vim b/src/testdir/test_alot.vim index e83256a4d3..189cd82d12 100644 --- a/src/testdir/test_alot.vim +++ b/src/testdir/test_alot.vim @@ -3,6 +3,7 @@ set belloff=all source test_assign.vim +source test_bufline.vim source test_cd.vim source test_changedtick.vim source test_cursor_func.vim diff --git a/src/testdir/test_bufline.vim b/src/testdir/test_bufline.vim new file mode 100644 index 0000000000..7df36aa6a2 --- /dev/null +++ b/src/testdir/test_bufline.vim @@ -0,0 +1,26 @@ +" Tests for setbufline() and getbufline() + +func Test_setbufline_getbufline() + new + let b = bufnr('%') + hide + call assert_equal(0, setbufline(b, 1, ['foo', 'bar'])) + call assert_equal(['foo'], getbufline(b, 1)) + call assert_equal(['bar'], getbufline(b, 2)) + call assert_equal(['foo', 'bar'], getbufline(b, 1, 2)) + exe "bd!" b + call assert_equal([], getbufline(b, 1, 2)) + + split Xtest + call setline(1, ['a', 'b', 'c']) + let b = bufnr('%') + wincmd w + call assert_equal(1, setbufline(b, 5, ['x'])) + call assert_equal(1, setbufline(1234, 1, ['x'])) + call assert_equal(0, setbufline(b, 4, ['d', 'e'])) + call assert_equal(['c'], getbufline(b, 3)) + call assert_equal(['d'], getbufline(b, 4)) + call assert_equal(['e'], getbufline(b, 5)) + call assert_equal([], getbufline(b, 6)) + exe "bwipe! " . b +endfunc diff --git a/src/version.c b/src/version.c index e8e508f8a6..8bc6d72bec 100644 --- a/src/version.c +++ b/src/version.c @@ -769,6 +769,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1039, /**/ 1038, /**/ From 3653822546fb0f1005c32bb5b70dc9bfacdfc954 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 2 Sep 2017 19:51:44 +0200 Subject: [PATCH 14/26] patch 8.0.1040: cannot use another error format in getqflist() Problem: Cannot use another error format in getqflist(). Solution: Add the "efm" argument to getqflist(). (Yegappan Lakshmanan) --- runtime/doc/eval.txt | 16 +++++++++++----- src/quickfix.c | 32 +++++++++++++++++++++++++++----- src/testdir/test_quickfix.vim | 22 ++++++++++++++++++++++ src/version.c | 2 ++ 4 files changed, 62 insertions(+), 10 deletions(-) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 4eb68a0d78..445a6808bd 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -4635,16 +4635,19 @@ getqflist([{what}]) *getqflist()* returns only the items listed in {what} as a dictionary. The following string items are supported in {what}: context get the context stored with |setqflist()| + efm errorformat to use when parsing "lines". If + not present, then the 'erroformat' option + value is used. id get information for the quickfix list with |quickfix-ID|; zero means the id for the - current list or the list specifed by 'nr' + current list or the list specifed by "nr" items quickfix list entries lines use 'errorformat' to extract items from a list of lines and return the resulting entries. Only a |List| type is accepted. The current quickfix list is not modified. nr get information for this quickfix list; zero - means the current quickfix list and '$' means + means the current quickfix list and "$" means the last quickfix list title get the list title winid get the |window-ID| (if opened) @@ -7086,13 +7089,16 @@ setqflist({list} [, {action}[, {what}]]) *setqflist()* is created. The new quickfix list is added after the current quickfix list in the stack and all the following lists are freed. To add a new quickfix list at the end of the stack, - set "nr" in {what} to '$'. + set "nr" in {what} to "$". If the optional {what} dictionary argument is supplied, then only the items listed in {what} are set. The first {list} argument is ignored. The following items can be specified in {what}: context any Vim type can be stored as a context + efm errorformat to use when parsing text from + "lines". If this is not present, then the + 'errorformat' option value is used. id quickfix list identifier |quickfix-ID| items list of quickfix entries. Same as the {list} argument. @@ -7100,7 +7106,7 @@ setqflist({list} [, {action}[, {what}]]) *setqflist()* add the resulting entries to the quickfix list {nr} or {id}. Only a |List| value is supported. nr list number in the quickfix stack; zero - means the current quickfix list and '$' means + means the current quickfix list and "$" means the last quickfix list title quickfix list title text Unsupported keys in {what} are ignored. @@ -7108,7 +7114,7 @@ setqflist({list} [, {action}[, {what}]]) *setqflist()* is modified. When creating a new quickfix list, "nr" can be set to a value one greater than the quickfix stack size. When modifying a quickfix list, to guarantee that the correct - list is modified, 'id' should be used instead of 'nr' to + list is modified, "id" should be used instead of "nr" to specify the list. Examples: > diff --git a/src/quickfix.c b/src/quickfix.c index 5cbb1519ad..ee871fc463 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -4643,16 +4643,29 @@ enum { * Parse text from 'di' and return the quickfix list items */ static int -qf_get_list_from_lines(dictitem_T *di, dict_T *retdict) +qf_get_list_from_lines(dict_T *what, dictitem_T *di, dict_T *retdict) { int status = FAIL; qf_info_T *qi; + char_u *errorformat = p_efm; + dictitem_T *efm_di; + list_T *l; /* Only a List value is supported */ if (di->di_tv.v_type == VAR_LIST && di->di_tv.vval.v_list != NULL) { - list_T *l = list_alloc(); + /* If errorformat is supplied then use it, otherwise use the 'efm' + * option setting + */ + if ((efm_di = dict_find(what, (char_u *)"efm", -1)) != NULL) + { + if (efm_di->di_tv.v_type != VAR_STRING || + efm_di->di_tv.vval.v_string == NULL) + return FAIL; + errorformat = efm_di->di_tv.vval.v_string; + } + l = list_alloc(); if (l == NULL) return FAIL; @@ -4662,7 +4675,7 @@ qf_get_list_from_lines(dictitem_T *di, dict_T *retdict) vim_memset(qi, 0, (size_t)(sizeof(qf_info_T))); qi->qf_refcount++; - if (qf_init_ext(qi, 0, NULL, NULL, &di->di_tv, p_efm, + if (qf_init_ext(qi, 0, NULL, NULL, &di->di_tv, errorformat, TRUE, (linenr_T)0, (linenr_T)0, NULL, NULL) > 0) { (void)get_errorlist(qi, NULL, 0, l); @@ -4692,7 +4705,7 @@ get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict) int flags = QF_GETLIST_NONE; if ((di = dict_find(what, (char_u *)"lines", -1)) != NULL) - return qf_get_list_from_lines(di, retdict); + return qf_get_list_from_lines(what, di, retdict); if (wp != NULL) qi = GET_LOC_LIST(wp); @@ -4962,6 +4975,7 @@ qf_set_properties(qf_info_T *qi, dict_T *what, int action, char_u *title) int retval = FAIL; int qf_idx; int newlist = FALSE; + char_u *errorformat = p_efm; if (action == ' ' || qi->qf_curlist == qi->qf_listcount) newlist = TRUE; @@ -5039,6 +5053,7 @@ qf_set_properties(qf_info_T *qi, dict_T *what, int action, char_u *title) retval = OK; } } + if ((di = dict_find(what, (char_u *)"items", -1)) != NULL) { if (di->di_tv.v_type == VAR_LIST) @@ -5051,6 +5066,13 @@ qf_set_properties(qf_info_T *qi, dict_T *what, int action, char_u *title) } } + if ((di = dict_find(what, (char_u *)"efm", -1)) != NULL) + { + if (di->di_tv.v_type != VAR_STRING || di->di_tv.vval.v_string == NULL) + return FAIL; + errorformat = di->di_tv.vval.v_string; + } + if ((di = dict_find(what, (char_u *)"lines", -1)) != NULL) { /* Only a List value is supported */ @@ -5058,7 +5080,7 @@ qf_set_properties(qf_info_T *qi, dict_T *what, int action, char_u *title) { if (action == 'r') qf_free_items(qi, qf_idx); - if (qf_init_ext(qi, qf_idx, NULL, NULL, &di->di_tv, p_efm, + if (qf_init_ext(qi, qf_idx, NULL, NULL, &di->di_tv, errorformat, FALSE, (linenr_T)0, (linenr_T)0, NULL, NULL) > 0) retval = OK; } diff --git a/src/testdir/test_quickfix.vim b/src/testdir/test_quickfix.vim index 64f1baea2c..6a8d0e7bf2 100644 --- a/src/testdir/test_quickfix.vim +++ b/src/testdir/test_quickfix.vim @@ -2321,6 +2321,17 @@ func Xsetexpr_tests(cchar) call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["File2:25:Line25"]}) call assert_equal('Line15', g:Xgetlist({'nr':1, 'items':1}).items[1].text) call assert_equal('Line25', g:Xgetlist({'nr':2, 'items':1}).items[1].text) + + " Adding entries using a custom efm + set efm& + call g:Xsetlist([], ' ', {'efm' : '%f#%l#%m', + \ 'lines' : ["F1#10#L10", "F2#20#L20"]}) + call assert_equal(20, g:Xgetlist({'items':1}).items[1].lnum) + call g:Xsetlist([], 'a', {'efm' : '%f#%l#%m', 'lines' : ["F3:30:L30"]}) + call assert_equal('F3:30:L30', g:Xgetlist({'items':1}).items[2].text) + call assert_equal(20, g:Xgetlist({'items':1}).items[1].lnum) + call assert_equal(-1, g:Xsetlist([], 'a', {'efm' : [], + \ 'lines' : ['F1:10:L10']})) endfunc func Test_setexpr() @@ -2537,6 +2548,17 @@ func XgetListFromLines(cchar) call assert_equal([], g:Xgetlist({'lines' : []}).items) call assert_equal([], g:Xgetlist({'lines' : [10, 20]}).items) + " Parse text using a custom efm + set efm& + let l = g:Xgetlist({'lines':['File3#30#Line30'], 'efm' : '%f#%l#%m'}).items + call assert_equal('Line30', l[0].text) + let l = g:Xgetlist({'lines':['File3:30:Line30'], 'efm' : '%f-%l-%m'}).items + call assert_equal('File3:30:Line30', l[0].text) + let l = g:Xgetlist({'lines':['File3:30:Line30'], 'efm' : [1,2]}) + call assert_equal({}, l) + call assert_fails("call g:Xgetlist({'lines':['abc'], 'efm':'%2'})", 'E376:') + call assert_fails("call g:Xgetlist({'lines':['abc'], 'efm':''})", 'E378:') + " Make sure that the quickfix stack is not modified call assert_equal(0, g:Xgetlist({'nr' : '$'}).nr) endfunc diff --git a/src/version.c b/src/version.c index 8bc6d72bec..ee6e91ce73 100644 --- a/src/version.c +++ b/src/version.c @@ -769,6 +769,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1040, /**/ 1039, /**/ From e2e69e48134cbfdedea7802810932f8592705024 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 2 Sep 2017 20:30:35 +0200 Subject: [PATCH 15/26] patch 8.0.1041: bogus characters when indenting during visual-block append Problem: Bogus characters appear when indenting kicks in while doing a visual-block append. Solution: Recompute when indenting is done. (Christian Brabandt) --- runtime/doc/visual.txt | 5 +++-- src/charset.c | 16 ++++++++++++++++ src/edit.c | 7 +++---- src/misc1.c | 6 ++---- src/ops.c | 19 +++++++++++++++---- src/proto/charset.pro | 2 ++ src/proto/misc1.pro | 1 + src/screen.c | 2 +- src/spell.c | 6 +++--- src/testdir/test_cindent.vim | 24 ++++++++++++++++++++++-- src/version.c | 2 ++ 11 files changed, 70 insertions(+), 20 deletions(-) diff --git a/runtime/doc/visual.txt b/runtime/doc/visual.txt index 0a91b9f48e..59315019d3 100644 --- a/runtime/doc/visual.txt +++ b/runtime/doc/visual.txt @@ -314,8 +314,8 @@ Visual-block Insert *v_b_I* With a blockwise selection, I{string} will insert {string} at the start of block on every line of the block, provided that the line extends into the block. Thus lines that are short will remain unmodified. TABs are split to -retain visual columns. -See |v_b_I_example|. +retain visual columns. Works only for adding text to a line, not for +deletions. See |v_b_I_example|. Visual-block Append *v_b_A* With a blockwise selection, A{string} will append {string} to the end of @@ -331,6 +331,7 @@ See |v_b_A_example|. Note: "I" and "A" behave differently for lines that don't extend into the selected block. This was done intentionally, so that you can do it the way you want. +Works only for adding text to a line, not for deletions. Visual-block change *v_b_c* All selected text in the block will be replaced by the same text string. When diff --git a/src/charset.c b/src/charset.c index d649179dd7..8b83f68068 100644 --- a/src/charset.c +++ b/src/charset.c @@ -1535,6 +1535,22 @@ skipwhite(char_u *q) return p; } +/* + * getwhitecols: return the number of whitespace + * columns (bytes) at the start of a given line + */ + int +getwhitecols_curline() +{ + return getwhitecols(ml_get_curline()); +} + + int +getwhitecols(char_u *p) +{ + return skipwhite(p) - p; +} + /* * skip over digits */ diff --git a/src/edit.c b/src/edit.c index 33c4c00715..6fd1245390 100644 --- a/src/edit.c +++ b/src/edit.c @@ -5182,7 +5182,7 @@ ins_complete(int c, int enable_pum) * first non_blank in the line, if it is not a wordchar * include it to get a better pattern, but then we don't * want the "\\<" prefix, check it bellow */ - compl_col = (colnr_T)(skipwhite(line) - line); + compl_col = (colnr_T)getwhitecols(line); compl_startpos.col = compl_col; compl_startpos.lnum = curwin->w_cursor.lnum; compl_cont_status &= ~CONT_SOL; /* clear SOL if present */ @@ -5348,7 +5348,7 @@ ins_complete(int c, int enable_pum) } else if (CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode)) { - compl_col = (colnr_T)(skipwhite(line) - line); + compl_col = (colnr_T)getwhitecols(line); compl_length = (int)curs_col - (int)compl_col; if (compl_length < 0) /* cursor in indent: empty pattern */ compl_length = 0; @@ -8208,8 +8208,7 @@ in_cinkeys( { /* "0=word": Check if there are only blanks before the * word. */ - line = ml_get_curline(); - if ((int)(skipwhite(line) - line) != + if (getwhitecols(line) != (int)(curwin->w_cursor.col - (p - look))) match = FALSE; } diff --git a/src/misc1.c b/src/misc1.c index abc455e951..8ae75e6d85 100644 --- a/src/misc1.c +++ b/src/misc1.c @@ -1589,8 +1589,7 @@ open_line( && curbuf->b_p_ai) { fixthisline(get_lisp_indent); - p = ml_get_curline(); - ai_col = (colnr_T)(skipwhite(p) - p); + ai_col = (colnr_T)getwhitecols_curline(); } #endif #ifdef FEAT_CINDENT @@ -1608,8 +1607,7 @@ open_line( : KEY_OPEN_BACK, ' ', linewhite(curwin->w_cursor.lnum))) { do_c_expr_indent(); - p = ml_get_curline(); - ai_col = (colnr_T)(skipwhite(p) - p); + ai_col = (colnr_T)getwhitecols_curline(); } #endif #if defined(FEAT_VREPLACE) && (defined(FEAT_LISP) || defined(FEAT_CINDENT)) diff --git a/src/ops.c b/src/ops.c index 5c58e523f3..9ca5198d27 100644 --- a/src/ops.c +++ b/src/ops.c @@ -2507,6 +2507,7 @@ op_insert(oparg_T *oap, long count1) { long ins_len, pre_textlen = 0; char_u *firstline, *ins_text; + colnr_T ind_pre, ind_post; struct block_def bd; int i; pos_T t1; @@ -2541,7 +2542,10 @@ op_insert(oparg_T *oap, long count1) #endif /* Get the info about the block before entering the text */ block_prep(oap, &bd, oap->start.lnum, TRUE); + /* Get indent information */ + ind_pre = (colnr_T)getwhitecols_curline(); firstline = ml_get(oap->start.lnum) + bd.textcol; + if (oap->op_type == OP_APPEND) firstline += bd.textlen; pre_textlen = (long)STRLEN(firstline); @@ -2593,6 +2597,14 @@ op_insert(oparg_T *oap, long count1) && LT_POS(curbuf->b_op_start_orig, t1)) oap->start = curbuf->b_op_start_orig; + /* if indent kicked in, the firstline might have changed + * but only do that, if the indent actually increased */ + ind_post = (colnr_T)getwhitecols_curline(); + if (curbuf->b_op_start.col > ind_pre && ind_post > ind_pre) + { + bd.textcol += ind_post - ind_pre; + bd.start_vcol += ind_post - ind_pre; + } /* If user has moved off this line, we don't know what to do, so do * nothing. * Also don't repeat the insert when Insert mode ended with CTRL-C. */ @@ -2754,7 +2766,7 @@ op_change(oparg_T *oap) # endif firstline = ml_get(oap->start.lnum); pre_textlen = (long)STRLEN(firstline); - pre_indent = (long)(skipwhite(firstline) - firstline); + pre_indent = (long)getwhitecols(firstline); bd.textcol = curwin->w_cursor.col; } #endif @@ -2779,7 +2791,7 @@ op_change(oparg_T *oap) firstline = ml_get(oap->start.lnum); if (bd.textcol > (colnr_T)pre_indent) { - long new_indent = (long)(skipwhite(firstline) - firstline); + long new_indent = (long)getwhitecols(firstline); pre_textlen += new_indent - pre_indent; bd.textcol += new_indent - pre_indent; @@ -5065,8 +5077,7 @@ format_lines( #endif if (second_indent > 0) /* the "leader" for FO_Q_SECOND */ { - char_u *p = ml_get_curline(); - int indent = (int)(skipwhite(p) - p); + int indent = getwhitecols_curline(); if (indent > 0) { diff --git a/src/proto/charset.pro b/src/proto/charset.pro index 52b741a740..bb4132fe79 100644 --- a/src/proto/charset.pro +++ b/src/proto/charset.pro @@ -35,6 +35,8 @@ colnr_T getvcol_nolist(pos_T *posp); void getvvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *end); void getvcols(win_T *wp, pos_T *pos1, pos_T *pos2, colnr_T *left, colnr_T *right); char_u *skipwhite(char_u *q); +int getwhitecols_curline(void); +int getwhitecols(char_u *p); char_u *skipdigits(char_u *q); char_u *skipbin(char_u *q); char_u *skiphex(char_u *q); diff --git a/src/proto/misc1.pro b/src/proto/misc1.pro index cac644969b..4e299e5f9a 100644 --- a/src/proto/misc1.pro +++ b/src/proto/misc1.pro @@ -1,4 +1,5 @@ /* misc1.c */ +int get_whitespace_line_start(linenr_T lnum); int get_indent(void); int get_indent_lnum(linenr_T lnum); int get_indent_buf(buf_T *buf, linenr_T lnum); diff --git a/src/screen.c b/src/screen.c index ca7b658360..e0d4af8fc6 100644 --- a/src/screen.c +++ b/src/screen.c @@ -3463,7 +3463,7 @@ win_line( { /* For checking first word with a capital skip white space. */ if (cap_col == 0) - cap_col = (int)(skipwhite(line) - line); + cap_col = getwhitecols(line); /* To be able to spell-check over line boundaries copy the end of the * current line into nextline[]. Above the start of the next line was diff --git a/src/spell.c b/src/spell.c index 0eb87638eb..2742997c2c 100644 --- a/src/spell.c +++ b/src/spell.c @@ -1625,11 +1625,11 @@ spell_move_to( /* For checking first word with a capital skip white space. */ if (capcol == 0) - capcol = (int)(skipwhite(line) - line); + capcol = getwhitecols(line); else if (curline && wp == curwin) { /* For spellbadword(): check if first word needs a capital. */ - col = (int)(skipwhite(line) - line); + col = getwhitecols(line); if (check_need_cap(lnum, col)) capcol = col; @@ -3593,7 +3593,7 @@ check_need_cap(linenr_T lnum, colnr_T col) line = ml_get_curline(); endcol = 0; - if ((int)(skipwhite(line) - line) >= (int)col) + if (getwhitecols(line) >= (int)col) { /* At start of line, check if previous line is empty or sentence * ends there. */ diff --git a/src/testdir/test_cindent.vim b/src/testdir/test_cindent.vim index d352e8feff..7c2c5e341c 100644 --- a/src/testdir/test_cindent.vim +++ b/src/testdir/test_cindent.vim @@ -71,7 +71,7 @@ func Test_cino_extern_c() bwipe! endfunc -func! Test_cindent_rawstring() +func Test_cindent_rawstring() new setl cindent call feedkeys("i" . @@ -81,5 +81,25 @@ func! Test_cindent_rawstring() \ "statement;\", "x") call assert_equal("\tstatement;", getline(line('.'))) bw! -endfunction +endfunc + +func Test_cindent_expr() + new + func! MyIndentFunction() + return v:lnum == 1 ? shiftwidth() : 0 + endfunc + setl expandtab sw=8 indentkeys+=; indentexpr=MyIndentFunction() + call setline(1, ['var_a = something()', 'b = something()']) + call cursor(1, 1) + call feedkeys("^\j$A;\", 'tnix') + call assert_equal([' var_a = something();', 'b = something();'], getline(1, '$')) + + %d + call setline(1, [' var_a = something()', ' b = something()']) + call cursor(1, 1) + call feedkeys("^\j$A;\", 'tnix') + call assert_equal([' var_a = something();', ' b = something()'], getline(1, '$')) + bw! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index ee6e91ce73..e59466762a 100644 --- a/src/version.c +++ b/src/version.c @@ -769,6 +769,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1041, /**/ 1040, /**/ From 9f45ccd1bf2d2de979d252fdd7e5c9eb3fa6cceb Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 2 Sep 2017 20:40:35 +0200 Subject: [PATCH 16/26] patch 8.0.1042: without the syntax feature highlighting doesn't work Problem: Without the syntax feature highlighting doesn't work. Solution: Always use unsigned short to store attributes. --- src/version.c | 2 ++ src/vim.h | 7 +------ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/version.c b/src/version.c index e59466762a..77620adc3f 100644 --- a/src/version.c +++ b/src/version.c @@ -769,6 +769,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1042, /**/ 1041, /**/ diff --git a/src/vim.h b/src/vim.h index 77081e202a..93dc951fb3 100644 --- a/src/vim.h +++ b/src/vim.h @@ -435,13 +435,8 @@ typedef off_t off_T; * The characters and attributes cached for the screen. */ typedef char_u schar_T; -#ifdef FEAT_SYN_HL typedef unsigned short sattr_T; -# define MAX_TYPENR 65535 -#else -typedef unsigned char sattr_T; -# define MAX_TYPENR 255 -#endif +#define MAX_TYPENR 65535 /* * The u8char_T can hold one decoded UTF-8 character. From 4ec86ddd77a89766e42bd0a6cfcf10af4c3d03b2 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 2 Sep 2017 23:28:54 +0200 Subject: [PATCH 17/26] patch 8.0.1043: warning for uninitialized variable Problem: Warning for uninitialized variable. (John Marriott) Solution: Move code to check indent inside "if". --- src/ops.c | 17 +++++++++-------- src/version.c | 2 ++ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/ops.c b/src/ops.c index 9ca5198d27..e8308bbcb8 100644 --- a/src/ops.c +++ b/src/ops.c @@ -2597,14 +2597,6 @@ op_insert(oparg_T *oap, long count1) && LT_POS(curbuf->b_op_start_orig, t1)) oap->start = curbuf->b_op_start_orig; - /* if indent kicked in, the firstline might have changed - * but only do that, if the indent actually increased */ - ind_post = (colnr_T)getwhitecols_curline(); - if (curbuf->b_op_start.col > ind_pre && ind_post > ind_pre) - { - bd.textcol += ind_post - ind_pre; - bd.start_vcol += ind_post - ind_pre; - } /* If user has moved off this line, we don't know what to do, so do * nothing. * Also don't repeat the insert when Insert mode ended with CTRL-C. */ @@ -2615,6 +2607,15 @@ op_insert(oparg_T *oap, long count1) { struct block_def bd2; + /* If indent kicked in, the firstline might have changed + * but only do that, if the indent actually increased. */ + ind_post = (colnr_T)getwhitecols_curline(); + if (curbuf->b_op_start.col > ind_pre && ind_post > ind_pre) + { + bd.textcol += ind_post - ind_pre; + bd.start_vcol += ind_post - ind_pre; + } + /* The user may have moved the cursor before inserting something, try * to adjust the block for that. */ if (oap->start.lnum == curbuf->b_op_start_orig.lnum && !bd.is_MAX) diff --git a/src/version.c b/src/version.c index 77620adc3f..2138f0ae95 100644 --- a/src/version.c +++ b/src/version.c @@ -769,6 +769,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1043, /**/ 1042, /**/ From 2254a8ad0cb596a0a0863b1af92353f018c0b355 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 3 Sep 2017 14:03:43 +0200 Subject: [PATCH 18/26] patch 8.0.1044: warning for uninitialized variable Problem: Warning for uninitialized variable. (John Marriott) Solution: Initialize ind_pre. --- src/ops.c | 2 +- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ops.c b/src/ops.c index e8308bbcb8..6fb6947ee2 100644 --- a/src/ops.c +++ b/src/ops.c @@ -2507,7 +2507,7 @@ op_insert(oparg_T *oap, long count1) { long ins_len, pre_textlen = 0; char_u *firstline, *ins_text; - colnr_T ind_pre, ind_post; + colnr_T ind_pre = 0, ind_post; struct block_def bd; int i; pos_T t1; diff --git a/src/version.c b/src/version.c index 2138f0ae95..0d2ca4f47f 100644 --- a/src/version.c +++ b/src/version.c @@ -769,6 +769,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1044, /**/ 1043, /**/ From 6a8691d483914606213a24356a9124fa41c93b69 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 3 Sep 2017 14:31:02 +0200 Subject: [PATCH 19/26] patch 8.0.1045: running tests may pollute shell history Problem: Running tests may pollute shell history. (Manuel Ortega) Solution: Make $HISTFILE empty. --- src/testdir/setup.vim | 3 +++ src/version.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/testdir/setup.vim b/src/testdir/setup.vim index cb8bebb47a..fca5194abf 100644 --- a/src/testdir/setup.vim +++ b/src/testdir/setup.vim @@ -21,6 +21,9 @@ if 1 let $XAUTHORITY = $HOME . '/.Xauthority' endif + " Avoid storing shell history. + let $HISTFILE = "" + " Make sure $HOME does not get read or written. " It must exist, gnome tries to create $HOME/.gnome2 let $HOME = getcwd() . '/XfakeHOME' diff --git a/src/version.c b/src/version.c index 0d2ca4f47f..b1e2d5a7a3 100644 --- a/src/version.c +++ b/src/version.c @@ -769,6 +769,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1045, /**/ 1044, /**/ From ae96b8d058cffd9d07b78cb7a9ccd382185b9dd6 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 3 Sep 2017 15:04:21 +0200 Subject: [PATCH 20/26] patch 8.0.1046: code duplication in diff mode Problem: Code duplication in diff mode. Solution: Use diff_equal_char() also in diff_cmp(). (Rick Howe) --- src/diff.c | 94 ++++++++++++++++++++------------------------------- src/version.c | 2 ++ 2 files changed, 39 insertions(+), 57 deletions(-) diff --git a/src/diff.c b/src/diff.c index cd3ffa48f1..0e352d8938 100644 --- a/src/diff.c +++ b/src/diff.c @@ -1660,6 +1660,40 @@ diff_equal_entry(diff_T *dp, int idx1, int idx2) return TRUE; } +/* + * Compare the characters at "p1" and "p2". If they are equal (possibly + * ignoring case) return TRUE and set "len" to the number of bytes. + */ + static int +diff_equal_char(char_u *p1, char_u *p2, int *len) +{ +#ifdef FEAT_MBYTE + int l = (*mb_ptr2len)(p1); + + if (l != (*mb_ptr2len)(p2)) + return FALSE; + if (l > 1) + { + if (STRNCMP(p1, p2, l) != 0 + && (!enc_utf8 + || !(diff_flags & DIFF_ICASE) + || utf_fold(utf_ptr2char(p1)) + != utf_fold(utf_ptr2char(p2)))) + return FALSE; + *len = l; + } + else +#endif + { + if ((*p1 != *p2) + && (!(diff_flags & DIFF_ICASE) + || TOLOWER_LOC(*p1) != TOLOWER_LOC(*p2))) + return FALSE; + *len = 1; + } + return TRUE; +} + /* * Compare strings "s1" and "s2" according to 'diffopt'. * Return non-zero when they are different. @@ -1689,30 +1723,10 @@ diff_cmp(char_u *s1, char_u *s2) } else { -#ifdef FEAT_MBYTE - l = (*mb_ptr2len)(p1); - if (l != (*mb_ptr2len)(p2)) + if (!diff_equal_char(p1, p2, &l)) break; - if (l > 1) - { - if (STRNCMP(p1, p2, l) != 0 - && (!enc_utf8 - || !(diff_flags & DIFF_ICASE) - || utf_fold(utf_ptr2char(p1)) - != utf_fold(utf_ptr2char(p2)))) - break; - p1 += l; - p2 += l; - } - else -#endif - { - if (*p1 != *p2 && (!(diff_flags & DIFF_ICASE) - || TOLOWER_LOC(*p1) != TOLOWER_LOC(*p2))) - break; - ++p1; - ++p2; - } + p1 += l; + p2 += l; } } @@ -1949,40 +1963,6 @@ diffopt_horizontal(void) return (diff_flags & DIFF_HORIZONTAL) != 0; } -/* - * Compare the characters at "p1" and "p2". If they are equal (possibly - * ignoring case) return TRUE and set "len" to the number of bytes. - */ - static int -diff_equal_char(char_u *p1, char_u *p2, int *len) -{ -#ifdef FEAT_MBYTE - int l = (*mb_ptr2len)(p1); - - if (l != (*mb_ptr2len)(p2)) - return FALSE; - if (l > 1) - { - if (STRNCMP(p1, p2, l) != 0 - && (!enc_utf8 - || !(diff_flags & DIFF_ICASE) - || utf_fold(utf_ptr2char(p1)) - != utf_fold(utf_ptr2char(p2)))) - return FALSE; - *len = l; - } - else -#endif - { - if ((*p1 != *p2) - && (!(diff_flags & DIFF_ICASE) - || TOLOWER_LOC(*p1) != TOLOWER_LOC(*p2))) - return FALSE; - *len = 1; - } - return TRUE; -} - /* * Find the difference within a changed line. * Returns TRUE if the line was added, no other buffer has it. diff --git a/src/version.c b/src/version.c index b1e2d5a7a3..a57e11f5b7 100644 --- a/src/version.c +++ b/src/version.c @@ -769,6 +769,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1046, /**/ 1045, /**/ From 00ccf54630dc68a9b8aedb92b268f3b697081f68 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 3 Sep 2017 15:17:48 +0200 Subject: [PATCH 21/26] patch 8.0.1047: buffer overflow in Ruby Problem: Buffer overflow in Ruby. Solution: Allocate one more byte. (Dominique Pelle) --- src/if_ruby.c | 2 +- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/if_ruby.c b/src/if_ruby.c index 02b59dd14a..d38ed2fbb1 100644 --- a/src/if_ruby.c +++ b/src/if_ruby.c @@ -984,7 +984,7 @@ static VALUE vim_message(VALUE self UNUSED, VALUE str) if (RSTRING_LEN(str) > 0) { /* Only do this when the string isn't empty, alloc(0) causes trouble. */ - buff = ALLOCA_N(char, RSTRING_LEN(str)); + buff = ALLOCA_N(char, RSTRING_LEN(str) + 1); strcpy(buff, RSTRING_PTR(str)); p = strchr(buff, '\n'); if (p) *p = '\0'; diff --git a/src/version.c b/src/version.c index a57e11f5b7..2034504ccc 100644 --- a/src/version.c +++ b/src/version.c @@ -769,6 +769,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1047, /**/ 1046, /**/ From 5e80de3f3e572805fe734b66bc42c13303ad9bdb Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 3 Sep 2017 15:48:12 +0200 Subject: [PATCH 22/26] patch 8.0.1048: no test for what 8.0.1020 fixes Problem: No test for what 8.0.1020 fixes. Solution: Add test_feedinput(). Add a test. (Ozaki Kiichi, closes #2046) --- runtime/doc/eval.txt | 6 ++++++ src/evalfunc.c | 19 +++++++++++++++++++ src/testdir/test_timers.vim | 19 +++++++++++++++++++ src/ui.c | 15 --------------- src/version.c | 2 ++ 5 files changed, 46 insertions(+), 15 deletions(-) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 445a6808bd..f9c6ae3b46 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -2410,6 +2410,7 @@ term_wait({buf} [, {time}]) Number wait for screen to be updated test_alloc_fail({id}, {countdown}, {repeat}) none make memory allocation fail test_autochdir() none enable 'autochdir' during startup +test_feedinput() none add key sequence to input buffer test_garbagecollect_now() none free memory right now for testing test_ignore_error({expr}) none ignore a specific error test_null_channel() Channel null value for testing @@ -8196,6 +8197,11 @@ test_autochdir() *test_autochdir()* Set a flag to enable the effect of 'autochdir' before Vim startup has finished. +test_feedinput({string}) *test_feedinput()* + Characters in {string} are queued for processing as if they + were typed by the user. This uses a low level input buffer. + This function works only when with |+unix| or GUI is running. + test_garbagecollect_now() *test_garbagecollect_now()* Like garbagecollect(), but executed right away. This must only be called directly to avoid any structure to exist diff --git a/src/evalfunc.c b/src/evalfunc.c index 626af7c500..2692de61f4 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -393,6 +393,7 @@ static void f_tagfiles(typval_T *argvars, typval_T *rettv); static void f_tempname(typval_T *argvars, typval_T *rettv); static void f_test_alloc_fail(typval_T *argvars, typval_T *rettv); static void f_test_autochdir(typval_T *argvars, typval_T *rettv); +static void f_test_feedinput(typval_T *argvars, typval_T *rettv); static void f_test_override(typval_T *argvars, typval_T *rettv); static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv); static void f_test_ignore_error(typval_T *argvars, typval_T *rettv); @@ -851,6 +852,7 @@ static struct fst #endif {"test_alloc_fail", 3, 3, f_test_alloc_fail}, {"test_autochdir", 0, 0, f_test_autochdir}, + {"test_feedinput", 1, 1, f_test_feedinput}, {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now}, {"test_ignore_error", 1, 1, f_test_ignore_error}, #ifdef FEAT_JOB_CHANNEL @@ -12517,6 +12519,23 @@ f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED) #endif } +/* + * "test_feedinput()" + */ + static void +f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED) +{ +#ifdef USE_INPUT_BUF + char_u *val = get_tv_string_chk(&argvars[0]); + + if (val != NULL) + { + trash_input_buf(); + add_to_input_buf_csi(val, (int)STRLEN(val)); + } +#endif +} + /* * "test_disable({name}, {val})" function */ diff --git a/src/testdir/test_timers.vim b/src/testdir/test_timers.vim index d30325b7bb..0c6bb8338f 100644 --- a/src/testdir/test_timers.vim +++ b/src/testdir/test_timers.vim @@ -206,5 +206,24 @@ func Test_timer_errors() call assert_equal(3, g:call_count) endfunc +func FeedAndPeek(timer) + call test_feedinput('a') + call getchar(1) +endfunc + +func Interrupt(timer) + call test_feedinput("\") +endfunc + +func Test_peek_and_get_char() + if !has('unix') && !has('gui_running') + return + endif + call timer_start(0, 'FeedAndPeek') + let intr = timer_start(100, 'Interrupt') + let c = getchar() + call assert_equal(char2nr('a'), c) + call timer_stop(intr) +endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/ui.c b/src/ui.c index ddae372664..d8deb6a8de 100644 --- a/src/ui.c +++ b/src/ui.c @@ -1651,11 +1651,6 @@ set_input_buf(char_u *p) } } -#if defined(FEAT_GUI) \ - || defined(FEAT_MOUSE_GPM) || defined(FEAT_SYSMOUSE) \ - || defined(FEAT_XCLIPBOARD) || defined(VMS) \ - || defined(FEAT_CLIENTSERVER) \ - || defined(PROTO) /* * Add the given bytes to the input buffer * Special keys start with CSI. A real CSI must have been translated to @@ -1676,15 +1671,7 @@ add_to_input_buf(char_u *s, int len) while (len--) inbuf[inbufcount++] = *s++; } -#endif -#if ((defined(FEAT_XIM) || defined(FEAT_DND)) && defined(FEAT_GUI_GTK)) \ - || defined(FEAT_GUI_MSWIN) \ - || defined(FEAT_GUI_MAC) \ - || (defined(FEAT_MBYTE) && defined(FEAT_MBYTE_IME)) \ - || (defined(FEAT_GUI) && (!defined(USE_ON_FLY_SCROLL) \ - || defined(FEAT_MENU))) \ - || defined(PROTO) /* * Add "str[len]" to the input buffer while escaping CSI bytes. */ @@ -1706,7 +1693,6 @@ add_to_input_buf_csi(char_u *str, int len) } } } -#endif #if defined(FEAT_HANGULIN) || defined(PROTO) void @@ -1744,7 +1730,6 @@ trash_input_buf(void) /* * Read as much data from the input buffer as possible up to maxlen, and store * it in buf. - * Note: this function used to be Read() in unix.c */ int read_from_input_buf(char_u *buf, long maxlen) diff --git a/src/version.c b/src/version.c index 2034504ccc..ce53bb8150 100644 --- a/src/version.c +++ b/src/version.c @@ -769,6 +769,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1048, /**/ 1047, /**/ From d8d85bfb7d650d2fb584ea48aaaebdbc8a2e3dce Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 3 Sep 2017 18:08:00 +0200 Subject: [PATCH 23/26] patch 8.0.1049: shell on Mac can't handle long text Problem: Shell on Mac can't handle long text, making terminal test fail. Solution: Only write 1000 characters instead of 5000. --- src/testdir/test_terminal.vim | 14 ++++++++------ src/version.c | 2 ++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index c70b612953..a16f3d906e 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -458,14 +458,16 @@ endfunction func Test_terminal_noblock() let g:buf = term_start(&shell) + if has('mac') + " The shell or something else has a problem dealing with more than 1000 + " characters at the same time. + let len = 1000 + else + let len = 5000 + endif for c in ['a','b','c','d','e','f','g','h','i','j','k'] - call term_sendkeys(g:buf, 'echo ' . repeat(c, 5000) . "\") - if has('mac') - " TODO: this should not be needed, but without it sending keys blocks - " after 8000 chars or so. - sleep 100m - endif + call term_sendkeys(g:buf, 'echo ' . repeat(c, len) . "\") endfor call term_sendkeys(g:buf, "echo done\") diff --git a/src/version.c b/src/version.c index ce53bb8150..4a5282fd72 100644 --- a/src/version.c +++ b/src/version.c @@ -769,6 +769,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1049, /**/ 1048, /**/ From 595a40226ea1285689b622042534fd8442402db3 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 3 Sep 2017 19:15:57 +0200 Subject: [PATCH 24/26] patch 8.0.1050: terminal window feature not included by default Problem: Terminal window feature not included by default. Solution: Include the terminal feature for the "huge" build. --- src/auto/configure | 20 +++++++++++++++++--- src/configure.ac | 18 ++++++++++++++---- src/version.c | 2 ++ 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/auto/configure b/src/auto/configure index df4c962bd5..7e46662023 100755 --- a/src/auto/configure +++ b/src/auto/configure @@ -7473,20 +7473,34 @@ $as_echo_n "checking --enable-terminal argument... " >&6; } # Check whether --enable-terminal was given. if test "${enable_terminal+set}" = set; then : enableval=$enable_terminal; enable_terminal="yes" +else + enable_terminal="auto" fi -if test "$enable_terminal" = "yes"; then +if test "$enable_terminal" = "yes" || test "$enable_terminal" = "auto" -a "x$features" = "xhuge" ; then if test "x$features" = "xtiny" -o "x$features" = "xsmall"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: cannot use terminal emulator with tiny or small features" >&5 $as_echo "cannot use terminal emulator with tiny or small features" >&6; } enable_terminal="no" else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 + if test "$enable_terminal" = "auto"; then + enable_terminal="yes" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: defaulting to yes" >&5 +$as_echo "defaulting to yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } + fi fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 + if test "$enable_terminal" = "auto"; then + enable_terminal="no" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: defaulting to no" >&5 +$as_echo "defaulting to no" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } + fi fi if test "$enable_terminal" = "yes"; then $as_echo "#define FEAT_TERMINAL 1" >>confdefs.h diff --git a/src/configure.ac b/src/configure.ac index ea4df8f0ea..918c36c1da 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -2031,16 +2031,26 @@ fi AC_MSG_CHECKING(--enable-terminal argument) AC_ARG_ENABLE(terminal, [ --enable-terminal Enable terminal emulation support.], - [enable_terminal="yes"], ) -if test "$enable_terminal" = "yes"; then + [enable_terminal="yes"], [enable_terminal="auto"]) +if test "$enable_terminal" = "yes" || test "$enable_terminal" = "auto" -a "x$features" = "xhuge" ; then if test "x$features" = "xtiny" -o "x$features" = "xsmall"; then AC_MSG_RESULT([cannot use terminal emulator with tiny or small features]) enable_terminal="no" else - AC_MSG_RESULT(yes) + if test "$enable_terminal" = "auto"; then + enable_terminal="yes" + AC_MSG_RESULT(defaulting to yes) + else + AC_MSG_RESULT(yes) + fi fi else - AC_MSG_RESULT(no) + if test "$enable_terminal" = "auto"; then + enable_terminal="no" + AC_MSG_RESULT(defaulting to no) + else + AC_MSG_RESULT(no) + fi fi if test "$enable_terminal" = "yes"; then AC_DEFINE(FEAT_TERMINAL) diff --git a/src/version.c b/src/version.c index 4a5282fd72..45537fe059 100644 --- a/src/version.c +++ b/src/version.c @@ -769,6 +769,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1050, /**/ 1049, /**/ From 9d654a8d8cd3421307445f111785fb303a38c2a0 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 3 Sep 2017 19:52:17 +0200 Subject: [PATCH 25/26] patch 8.0.1051: cannot run terminal with spaces in argument Problem: Cannot run terminal with spaces in argument. Solution: Accept backslash to escape space and other characters. (closes #1999) --- src/os_unix.c | 11 ++++++++++- src/testdir/test_terminal.vim | 20 +++++++++++++++++++- src/version.c | 2 ++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/os_unix.c b/src/os_unix.c index b34c31645b..57ea4d9451 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -4094,8 +4094,17 @@ mch_parse_cmd(char_u *cmd, int use_shcf, char ***argv, int *argc) ++*argc; while (*p != NUL && (inquote || (*p != ' ' && *p != TAB))) { - if (*p == '"') + if (p[0] == '"') inquote = !inquote; + else if (p[0] == '\\' && p[1] != NUL) + { + /* First pass: skip over "\ " and "\"". + * Second pass: Remove the backslash. */ + if (i == 1) + mch_memmove(p, p + 1, STRLEN(p)); + else + ++p; + } ++p; } if (*p == NUL) diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index a16f3d906e..ce3fab7e5d 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -293,6 +293,8 @@ func Test_terminal_size() let size = term_getsize('') bwipe! call assert_equal([7, 27], size) + + call delete('Xtext') endfunc func Test_terminal_curwin() @@ -325,7 +327,7 @@ func Test_terminal_curwin() split dummy bwipe! - + call delete('Xtext') endfunc func Test_finish_open_close() @@ -555,3 +557,19 @@ func Test_terminal_no_cmd() call assert_equal('look here', term_getline(buf, 1)) bwipe! endfunc + +func Test_terminal_special_chars() + " this file name only works on Unix + if !has('unix') + return + endif + call mkdir('Xdir with spaces') + call writefile(['x'], 'Xdir with spaces/quoted"file') + term ls Xdir\ with\ spaces/quoted\"file + call WaitFor('term_getline("", 1) =~ "quoted"') + call assert_match('quoted"file', term_getline('', 1)) + call term_wait('') + + call delete('Xdir with spaces', 'rf') + bwipe +endfunc diff --git a/src/version.c b/src/version.c index 45537fe059..fe316be097 100644 --- a/src/version.c +++ b/src/version.c @@ -769,6 +769,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1051, /**/ 1050, /**/ From e88fc7a574263fd399c6815378bcd8fd228d8b54 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 3 Sep 2017 20:59:40 +0200 Subject: [PATCH 26/26] patch 8.0.1052: term_start() does not allow in_io, out_io and err_io options Problem: term_start() does not allow in_io, out_io and err_io options. Solution: Add JO_OUT_IO to get_job_options(). --- src/terminal.c | 54 ++++++++++++++++++----------------- src/testdir/test_terminal.vim | 48 ++++++++++++++++++++++++++++--- src/version.c | 2 ++ 3 files changed, 74 insertions(+), 30 deletions(-) diff --git a/src/terminal.c b/src/terminal.c index 05c0fd9169..9660c64ba7 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -39,7 +39,6 @@ * * TODO: * - ":term NONE" does not work in MS-Windows. - * - test for writing lines to terminal job does not work on MS-Windows * - implement term_setsize() * - add test for giving error for invalid 'termsize' value. * - support minimal size when 'termsize' is "rows*cols". @@ -48,16 +47,6 @@ * - GUI: when 'confirm' is set and trying to exit Vim, dialog offers to save * changes to "!shell". * (justrajdeep, 2017 Aug 22) - * - command argument with spaces doesn't work #1999 - * :terminal ls dir\ with\ spaces - * - implement job options when starting a terminal. Allow: - * "in_io", "in_top", "in_bot", "in_name", "in_buf" - "out_io", "out_name", "out_buf", "out_modifiable", "out_msg" - "err_io", "err_name", "err_buf", "err_modifiable", "err_msg" - * Check that something is connected to the terminal. - * Test: "cat" reading from a file or buffer - * "ls" writing stdout to a file or buffer - * shell writing stderr to a file or buffer * - For the GUI fill termios with default values, perhaps like pangoterm: * http://bazaar.launchpad.net/~leonerd/pangoterm/trunk/view/head:/main.c#L134 * - if the job in the terminal does not support the mouse, we can use the @@ -219,16 +208,6 @@ init_job_options(jobopt_T *opt) opt->jo_out_mode = MODE_RAW; opt->jo_err_mode = MODE_RAW; opt->jo_set = JO_MODE | JO_OUT_MODE | JO_ERR_MODE; - - opt->jo_io[PART_OUT] = JIO_BUFFER; - opt->jo_io[PART_ERR] = JIO_BUFFER; - opt->jo_set |= JO_OUT_IO + JO_ERR_IO; - - opt->jo_modifiable[PART_OUT] = 0; - opt->jo_modifiable[PART_ERR] = 0; - opt->jo_set |= JO_OUT_MODIFIABLE + JO_ERR_MODIFIABLE; - - opt->jo_set |= JO_OUT_BUF + JO_ERR_BUF; } /* @@ -237,8 +216,24 @@ init_job_options(jobopt_T *opt) static void setup_job_options(jobopt_T *opt, int rows, int cols) { - opt->jo_io_buf[PART_OUT] = curbuf->b_fnum; - opt->jo_io_buf[PART_ERR] = curbuf->b_fnum; + if (!(opt->jo_set & JO_OUT_IO)) + { + /* Connect stdout to the terminal. */ + opt->jo_io[PART_OUT] = JIO_BUFFER; + opt->jo_io_buf[PART_OUT] = curbuf->b_fnum; + opt->jo_modifiable[PART_OUT] = 0; + opt->jo_set |= JO_OUT_IO + JO_OUT_BUF + JO_OUT_MODIFIABLE; + } + + if (!(opt->jo_set & JO_ERR_IO)) + { + /* Connect stderr to the terminal. */ + opt->jo_io[PART_ERR] = JIO_BUFFER; + opt->jo_io_buf[PART_ERR] = curbuf->b_fnum; + opt->jo_modifiable[PART_ERR] = 0; + opt->jo_set |= JO_ERR_IO + JO_ERR_BUF + JO_ERR_MODIFIABLE; + } + opt->jo_pty = TRUE; if ((opt->jo_set2 & JO2_TERM_ROWS) == 0) opt->jo_term_rows = rows; @@ -258,6 +253,15 @@ term_start(typval_T *argvar, jobopt_T *opt, int forceit) if (check_restricted() || check_secure()) return; + if ((opt->jo_set & (JO_IN_IO + JO_OUT_IO + JO_ERR_IO)) + == (JO_IN_IO + JO_OUT_IO + JO_ERR_IO) + || (!(opt->jo_set & JO_OUT_IO) && (opt->jo_set & JO_OUT_BUF)) + || (!(opt->jo_set & JO_ERR_IO) && (opt->jo_set & JO_ERR_BUF))) + { + EMSG(_(e_invarg)); + return; + } + term = (term_T *)alloc_clear(sizeof(term_T)); if (term == NULL) return; @@ -2833,11 +2837,10 @@ f_term_start(typval_T *argvars, typval_T *rettv) jobopt_T opt; init_job_options(&opt); - /* TODO: allow more job options */ if (argvars[1].v_type != VAR_UNKNOWN && get_job_options(&argvars[1], &opt, JO_TIMEOUT_ALL + JO_STOPONEXIT - + JO_EXIT_CB + JO_CLOSE_CALLBACK, + + JO_EXIT_CB + JO_CLOSE_CALLBACK + JO_OUT_IO, JO2_TERM_NAME + JO2_TERM_FINISH + JO2_HIDDEN + JO2_TERM_OPENCMD + JO2_TERM_COLS + JO2_TERM_ROWS + JO2_VERTICAL + JO2_CURWIN + JO2_CWD + JO2_ENV + JO2_EOF_CHARS) == FAIL) @@ -3254,7 +3257,6 @@ term_and_job_init( { create_vterm(term, term->tl_rows, term->tl_cols); - /* TODO: if the command is "NONE" only create a pty. */ term->tl_job = job_start(argvar, opt); if (term->tl_job != NULL) ++term->tl_job->jv_refcount; diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index ce3fab7e5d..dce5f05cd1 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -164,10 +164,8 @@ func Test_terminal_scrape_123() call term_wait(1234) call term_wait(buf) - if has('win32') - " TODO: this should not be needed - sleep 100m - endif + let g:buf = buf + call WaitFor('len(term_scrape(g:buf, 1)) > 0') call Check_123(buf) " Must still work after the job ended. @@ -573,3 +571,45 @@ func Test_terminal_special_chars() call delete('Xdir with spaces', 'rf') bwipe endfunc + +func Test_terminal_wrong_options() + call assert_fails('call term_start(&shell, { + \ "in_io": "file", + \ "in_name": "xxx", + \ "out_io": "file", + \ "out_name": "xxx", + \ "err_io": "file", + \ "err_name": "xxx" + \ })', 'E474:') + call assert_fails('call term_start(&shell, { + \ "out_buf": bufnr("%") + \ })', 'E474:') + call assert_fails('call term_start(&shell, { + \ "err_buf": bufnr("%") + \ })', 'E474:') +endfunc + +func Test_terminal_redir_file() + let cmd = Get_cat_123_cmd() + let buf = term_start(cmd, {'out_io': 'file', 'out_name': 'Xfile'}) + call term_wait(buf) + call WaitFor('len(readfile("Xfile")) > 0') + call assert_match('123', readfile('Xfile')[0]) + call delete('Xfile') + + if has('unix') + let buf = term_start('xyzabc', {'err_io': 'file', 'err_name': 'Xfile'}) + call term_wait(buf) + call WaitFor('len(readfile("Xfile")) > 0') + call assert_match('executing job failed', readfile('Xfile')[0]) + call delete('Xfile') + + call writefile(['one line'], 'Xfile') + let buf = term_start('cat', {'in_io': 'file', 'in_name': 'Xfile'}) + call term_wait(buf) + call WaitFor('term_getline(' . buf . ', 1) == "one line"') + call assert_equal('one line', term_getline(buf, 1)) + bwipe + call delete('Xfile') + endif +endfunc diff --git a/src/version.c b/src/version.c index fe316be097..2b30a090f1 100644 --- a/src/version.c +++ b/src/version.c @@ -769,6 +769,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1052, /**/ 1051, /**/