From 5ecdf96422af3171cf948865bf057c2a61f042bc Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 13 Jun 2018 20:49:50 +0200 Subject: [PATCH 01/19] patch 8.1.0054: compiler warning for using %ld for "long long" Problem: Compiler warning for using %ld for "long long". Solution: Add a type cast. (closes #3002) --- src/os_unix.c | 4 ++-- src/version.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/os_unix.c b/src/os_unix.c index 71886538e1..05ad6b8dfd 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -4199,7 +4199,7 @@ set_child_environment( # ifdef FEAT_TERMINAL if (is_terminal) { - sprintf((char *)envbuf, "%ld", get_vim_var_nr(VV_VERSION)); + sprintf((char *)envbuf, "%ld", (long)get_vim_var_nr(VV_VERSION)); setenv("VIM_TERMINAL", (char *)envbuf, 1); } # endif @@ -4227,7 +4227,7 @@ set_child_environment( if (is_terminal) { vim_snprintf(envbuf_Version, sizeof(envbuf_Version), - "VIM_TERMINAL=%ld", get_vim_var_nr(VV_VERSION)); + "VIM_TERMINAL=%ld", (long)get_vim_var_nr(VV_VERSION)); putenv(envbuf_Version); } # endif diff --git a/src/version.c b/src/version.c index 2ea298bc3b..90ec0e4141 100644 --- a/src/version.c +++ b/src/version.c @@ -761,6 +761,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 54, /**/ 53, /**/ From 52d3aaeea4c85406f46e2051729e4f007f83b35e Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 13 Jun 2018 21:27:24 +0200 Subject: [PATCH 02/19] patch 8.1.0055: complete test has wrong order of arguments Problem: Complete test has wrong order of arguments. Wrong type for sentinel variable. Solution: Swap arguments, use VAR_UNKNOWN. (Ozaki Kiichi) --- src/mbyte.c | 2 +- src/testdir/test_ins_complete.vim | 8 ++++---- src/version.c | 2 ++ 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/mbyte.c b/src/mbyte.c index 545a40db0f..0443122880 100644 --- a/src/mbyte.c +++ b/src/mbyte.c @@ -4799,7 +4799,7 @@ call_imactivatefunc(int active) argv[0].v_type = VAR_NUMBER; argv[0].vval.v_number = active ? 1 : 0; - argv[1].v_type = VAR_NUMBER; + argv[1].v_type = VAR_UNKNOWN; (void)call_func_retnr(p_imaf, 1, argv, FALSE); } diff --git a/src/testdir/test_ins_complete.vim b/src/testdir/test_ins_complete.vim index 2b4356ea38..2cd29b5757 100644 --- a/src/testdir/test_ins_complete.vim +++ b/src/testdir/test_ins_complete.vim @@ -126,15 +126,15 @@ func Test_completefunc_args() set completefunc=CompleteFunc call feedkeys("i\\\", 'x') - call assert_equal(s:args[0], [1, 1]) - call assert_equal(s:args[1][0], 0) + call assert_equal([1, 1], s:args[0]) + call assert_equal(0, s:args[1][0]) set completefunc= let s:args = [] set omnifunc=CompleteFunc call feedkeys("i\\\", 'x') - call assert_equal(s:args[0], [1, 1]) - call assert_equal(s:args[1][0], 0) + call assert_equal([1, 1], s:args[0]) + call assert_equal(0, s:args[1][0]) set omnifunc= bwipe! diff --git a/src/version.c b/src/version.c index 90ec0e4141..8d58649031 100644 --- a/src/version.c +++ b/src/version.c @@ -761,6 +761,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 55, /**/ 54, /**/ From 43dee181f596c81b99e200b6cdfeb02ecfed42c8 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 16 Jun 2018 14:44:11 +0200 Subject: [PATCH 03/19] patch 8.1.0056: crash when using :hardcopy with illegal byte Problem: Crash when using :hardcopy with illegal byte. Solution: Check for string_convert() returning NULL. (Dominique Pelle) --- src/hardcopy.c | 10 +++++++++- src/testdir/test_hardcopy.vim | 29 ++++++++++++++++++++++------- src/version.c | 2 ++ 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/hardcopy.c b/src/hardcopy.c index 91f62c39f3..420ceb7638 100644 --- a/src/hardcopy.c +++ b/src/hardcopy.c @@ -3372,8 +3372,9 @@ mch_print_start_line(int margin, int page_line) } int -mch_print_text_out(char_u *p, int len UNUSED) +mch_print_text_out(char_u *textp, int len UNUSED) { + char_u *p = textp; int need_break; char_u ch; char_u ch_buff[8]; @@ -3508,8 +3509,15 @@ mch_print_text_out(char_u *p, int len UNUSED) #ifdef FEAT_MBYTE if (prt_do_conv) + { /* Convert from multi-byte to 8-bit encoding */ tofree = p = string_convert(&prt_conv, p, &len); + if (p == NULL) + { + p = (char_u *)""; + len = 0; + } + } if (prt_out_mbyte) { diff --git a/src/testdir/test_hardcopy.vim b/src/testdir/test_hardcopy.vim index f630556bef..ced13b107c 100644 --- a/src/testdir/test_hardcopy.vim +++ b/src/testdir/test_hardcopy.vim @@ -63,12 +63,27 @@ func Test_with_syntax() endfunc func Test_fname_with_spaces() - if has('postscript') - split t\ e\ s\ t.txt - call setline(1, ['just', 'some', 'text']) - hardcopy > %.ps - call assert_true(filereadable('t e s t.txt.ps')) - call delete('t e s t.txt.ps') - bwipe! + if !has('postscript') + return endif + split t\ e\ s\ t.txt + call setline(1, ['just', 'some', 'text']) + hardcopy > %.ps + call assert_true(filereadable('t e s t.txt.ps')) + call delete('t e s t.txt.ps') + bwipe! endfunc + +func Test_illegal_byte() + if !has('postscript') || &enc != 'utf-8' + return + endif + new + " conversion of 0xff will fail, this used to cause a crash + call setline(1, "\xff") + hardcopy >Xpstest + + bwipe! + call delete('Xpstest') +endfunc + diff --git a/src/version.c b/src/version.c index 8d58649031..bd8efafeb3 100644 --- a/src/version.c +++ b/src/version.c @@ -761,6 +761,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 56, /**/ 55, /**/ From 6ba3ec1bace67513a352326864cebc16b3c5bc56 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 16 Jun 2018 15:32:38 +0200 Subject: [PATCH 04/19] patch 8.1.0057: popup menu displayed wrong when using autocmd Problem: Popup menu displayed wrong when using autocmd. Solution: Use aucmd_prepbuf(). Force updating status line if the popup menu is going to be redrawn anyway. (Christian Brabandt, closes #3009) --- src/edit.c | 10 ++++++++++ src/proto/screen.pro | 1 - src/screen.c | 21 ++++++++++++--------- src/version.c | 2 ++ 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/edit.c b/src/edit.c index 92c9d6ad44..326a382b54 100644 --- a/src/edit.c +++ b/src/edit.c @@ -1704,7 +1704,12 @@ ins_redraw( #endif ) { + aco_save_T aco; + + // save and restore curwin and curbuf, in case the autocmd changes them + aucmd_prepbuf(&aco, curbuf); apply_autocmds(EVENT_TEXTCHANGEDI, NULL, NULL, FALSE, curbuf); + aucmd_restbuf(&aco); curbuf->b_last_changedtick = CHANGEDTICK(curbuf); } @@ -1716,7 +1721,12 @@ ins_redraw( && curbuf->b_last_changedtick_pum != CHANGEDTICK(curbuf) && pum_visible()) { + aco_save_T aco; + + // save and restore curwin and curbuf, in case the autocmd changes them + aucmd_prepbuf(&aco, curbuf); apply_autocmds(EVENT_TEXTCHANGEDP, NULL, NULL, FALSE, curbuf); + aucmd_restbuf(&aco); curbuf->b_last_changedtick_pum = CHANGEDTICK(curbuf); } #endif diff --git a/src/proto/screen.pro b/src/proto/screen.pro index 5760dae1b3..2b8a6fd028 100644 --- a/src/proto/screen.pro +++ b/src/proto/screen.pro @@ -25,7 +25,6 @@ void status_redraw_curbuf(void); void redraw_statuslines(void); void win_redraw_last_status(frame_T *frp); void win_redr_status_matches(expand_T *xp, int num_matches, char_u **matches, int match, int showtail); -void win_redr_status(win_T *wp); int stl_connected(win_T *wp); int get_keymap_str(win_T *wp, char_u *fmt, char_u *buf, int len); void screen_putchar(int c, int row, int col, int attr); diff --git a/src/screen.c b/src/screen.c index f2c58bee78..cd29315924 100644 --- a/src/screen.c +++ b/src/screen.c @@ -125,6 +125,7 @@ static int redrawing_for_callback = 0; static schar_T *current_ScreenLine; static void win_update(win_T *wp); +static void win_redr_status(win_T *wp, int ignore_pum); static void win_draw_end(win_T *wp, int c1, int c2, int row, int endrow, hlf_T hl); #ifdef FEAT_FOLDING static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T lnum, int row); @@ -774,7 +775,7 @@ update_screen(int type_arg) if (wp->w_redr_status) { cursor_off(); - win_redr_status(wp); + win_redr_status(wp, TRUE); // any popup menu will be redrawn below } } #if defined(FEAT_SEARCH_EXTRA) @@ -1030,7 +1031,7 @@ update_debug_sign(buf_T *buf, linenr_T lnum) if (wp->w_redr_type != 0) win_update(wp); if (wp->w_redr_status) - win_redr_status(wp); + win_redr_status(wp, FALSE); } update_finish(); @@ -1074,7 +1075,7 @@ updateWindow(win_T *wp) || *p_stl != NUL || *wp->w_p_stl != NUL # endif ) - win_redr_status(wp); + win_redr_status(wp, FALSE); update_finish(); } @@ -6535,7 +6536,7 @@ redraw_statuslines(void) FOR_ALL_WINDOWS(wp) if (wp->w_redr_status) - win_redr_status(wp); + win_redr_status(wp, FALSE); if (redraw_tabline) draw_tabline(); } @@ -6864,9 +6865,11 @@ win_redr_status_matches( * Redraw the status line of window wp. * * If inversion is possible we use it. Else '=' characters are used. + * If "ignore_pum" is TRUE, also redraw statusline when the popup menu is + * displayed. */ - void -win_redr_status(win_T *wp) + static void +win_redr_status(win_T *wp, int ignore_pum) { int row; char_u *p; @@ -6890,9 +6893,9 @@ win_redr_status(win_T *wp) } else if (!redrawing() #ifdef FEAT_INS_EXPAND - /* don't update status line when popup menu is visible and may be - * drawn over it */ - || pum_visible() + // don't update status line when popup menu is visible and may be + // drawn over it, unless it will be redrawn later + || (!ignore_pum && pum_visible()) #endif ) { diff --git a/src/version.c b/src/version.c index bd8efafeb3..f4ecfe7558 100644 --- a/src/version.c +++ b/src/version.c @@ -761,6 +761,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 57, /**/ 56, /**/ From bfa4246768e28335ed9b98f83019ea58b480158e Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 16 Jun 2018 16:20:52 +0200 Subject: [PATCH 05/19] patch 8.1.0058: display problem with margins and scrolling Problem: Display problem with margins and scrolling. Solution: Place the cursor in the right column. (Kouichi Iwamoto, closes #3016) --- src/screen.c | 26 +++++++++++++++++--------- src/version.c | 2 ++ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/screen.c b/src/screen.c index cd29315924..5ffc357d7d 100644 --- a/src/screen.c +++ b/src/screen.c @@ -9797,6 +9797,7 @@ screen_ins_lines( int j; unsigned temp; int cursor_row; + int cursor_col = 0; int type; int result_empty; int can_ce = can_clear(T_CE); @@ -9893,6 +9894,9 @@ screen_ins_lines( gui_dont_update_cursor(row + off <= gui.cursor_row); #endif + if (wp != NULL && wp->w_wincol != 0 && *T_CSV != NUL && *T_CCS == NUL) + cursor_col = wp->w_wincol; + if (*T_CCS != NUL) /* cursor relative to region */ cursor_row = row; else @@ -9939,7 +9943,7 @@ screen_ins_lines( } screen_stop_highlight(); - windgoto(cursor_row, 0); + windgoto(cursor_row, cursor_col); if (clear_attr != 0) screen_start_highlight(clear_attr); @@ -9958,7 +9962,7 @@ screen_ins_lines( if (type == USE_T_AL) { if (i && cursor_row != 0) - windgoto(cursor_row, 0); + windgoto(cursor_row, cursor_col); out_str(T_AL); } else /* type == USE_T_SR */ @@ -9975,7 +9979,7 @@ screen_ins_lines( { for (i = 0; i < line_count; ++i) { - windgoto(off + i, 0); + windgoto(off + i, cursor_col); out_str(T_CE); screen_start(); /* don't know where cursor is now */ } @@ -10011,6 +10015,7 @@ screen_del_lines( int i; unsigned temp; int cursor_row; + int cursor_col = 0; int cursor_end; int result_empty; /* result is empty until end of region */ int can_delete; /* deleting line codes can be used */ @@ -10110,6 +10115,9 @@ screen_del_lines( && gui.cursor_row < end + off); #endif + if (wp != NULL && wp->w_wincol != 0 && *T_CSV != NUL && *T_CCS == NUL) + cursor_col = wp->w_wincol; + if (*T_CCS != NUL) /* cursor relative to region */ { cursor_row = row; @@ -10172,13 +10180,13 @@ screen_del_lines( redraw_block(row, end, wp); else if (type == USE_T_CD) /* delete the lines */ { - windgoto(cursor_row, 0); + windgoto(cursor_row, cursor_col); out_str(T_CD); screen_start(); /* don't know where cursor is now */ } else if (type == USE_T_CDL) { - windgoto(cursor_row, 0); + windgoto(cursor_row, cursor_col); term_delete_lines(line_count); screen_start(); /* don't know where cursor is now */ } @@ -10189,7 +10197,7 @@ screen_del_lines( */ else if (type == USE_NL) { - windgoto(cursor_end - 1, 0); + windgoto(cursor_end - 1, cursor_col); for (i = line_count; --i >= 0; ) out_char('\n'); /* cursor will remain on same line */ } @@ -10199,12 +10207,12 @@ screen_del_lines( { if (type == USE_T_DL) { - windgoto(cursor_row, 0); + windgoto(cursor_row, cursor_col); out_str(T_DL); /* delete a line */ } else /* type == USE_T_CE */ { - windgoto(cursor_row + i, 0); + windgoto(cursor_row + i, cursor_col); out_str(T_CE); /* erase a line */ } screen_start(); /* don't know where cursor is now */ @@ -10219,7 +10227,7 @@ screen_del_lines( { for (i = line_count; i > 0; --i) { - windgoto(cursor_end - i, 0); + windgoto(cursor_end - i, cursor_col); out_str(T_CE); /* erase a line */ screen_start(); /* don't know where cursor is now */ } diff --git a/src/version.c b/src/version.c index f4ecfe7558..f7c5f2efa1 100644 --- a/src/version.c +++ b/src/version.c @@ -761,6 +761,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 58, /**/ 57, /**/ From bc5020aa4d7ef4aea88395eff858f74fc881eab9 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 16 Jun 2018 17:25:22 +0200 Subject: [PATCH 06/19] patch 8.1.0059: displayed digraph for "ga" wrong with 'encoding' "cp1251" Problem: Displayed digraph for "ga" wrong with 'encoding' "cp1251". Solution: Convert from 'encoding' to "utf-8" if needed. (closes #3015) --- src/digraph.c | 27 +++++++++++++++++++++++++-- src/testdir/test_digraph.vim | 12 ++++++++++++ src/version.c | 2 ++ 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/digraph.c b/src/digraph.c index 6f9c46ff71..6909c5b9c7 100644 --- a/src/digraph.c +++ b/src/digraph.c @@ -1979,14 +1979,37 @@ do_digraph(int c) * If not found return NULL. */ char_u * -get_digraph_for_char(val) - int val; +get_digraph_for_char(int val_arg) { + int val = val_arg; int i; int use_defaults; digr_T *dp; static char_u r[3]; +#if defined(FEAT_MBYTE) && defined(USE_UNICODE_DIGRAPHS) + if (!enc_utf8) + { + char_u buf[6], *to; + vimconv_T vc; + + // convert the character from 'encoding' to Unicode + i = mb_char2bytes(val, buf); + vc.vc_type = CONV_NONE; + if (convert_setup(&vc, p_enc, (char_u *)"utf-8") == OK) + { + vc.vc_fail = TRUE; + to = string_convert(&vc, buf, &i); + if (to != NULL) + { + val = utf_ptr2char(to); + vim_free(to); + } + (void)convert_setup(&vc, NULL, NULL); + } + } +#endif + for (use_defaults = 0; use_defaults <= 1; use_defaults++) { if (use_defaults == 0) diff --git a/src/testdir/test_digraph.vim b/src/testdir/test_digraph.vim index 271066df41..d5b0a7b72e 100644 --- a/src/testdir/test_digraph.vim +++ b/src/testdir/test_digraph.vim @@ -465,4 +465,16 @@ func Test_show_digraph() bwipe! endfunc +func Test_show_digraph_cp1251() + if !has('multi_byte') + return + endif + new + set encoding=cp1251 + call Put_Dig("='") + call assert_equal("\n<\xfa> <|z> 250, Hex fa, Oct 372, Digr ='", execute('ascii')) + set encoding=utf-8 + bwipe! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index f7c5f2efa1..68b4c26b86 100644 --- a/src/version.c +++ b/src/version.c @@ -761,6 +761,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 59, /**/ 58, /**/ From 600323b4ef51a58a8e800d8ca469383a3c911db7 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 16 Jun 2018 22:16:47 +0200 Subject: [PATCH 07/19] patch 8.1.0060: crash when autocommands delete the current buffer Problem: Crash when autocommands delete the current buffer. (Dominique Pelle) Solution: Check that autocommands don't change the buffer. --- src/quickfix.c | 8 ++++++++ src/testdir/test_quickfix.vim | 12 ++++++++++++ src/version.c | 2 ++ 3 files changed, 22 insertions(+) diff --git a/src/quickfix.c b/src/quickfix.c index 1b281ceab2..031c6e7a6b 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -6272,8 +6272,16 @@ ex_cbuffer(exarg_T *eap) if (res >= 0) qf_list_changed(qi, qi->qf_curlist); if (au_name != NULL) + { + buf_T *curbuf_old = curbuf; + apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, curbuf->b_fname, TRUE, curbuf); + if (curbuf != curbuf_old) + // Autocommands changed buffer, don't jump now, "qi" may + // be invalid. + res = 0; + } if (res > 0 && (eap->cmdidx == CMD_cbuffer || eap->cmdidx == CMD_lbuffer)) qf_jump(qi, 0, 0, eap->forceit); /* display first error */ diff --git a/src/testdir/test_quickfix.vim b/src/testdir/test_quickfix.vim index c3850ce1f4..eade52f42d 100644 --- a/src/testdir/test_quickfix.vim +++ b/src/testdir/test_quickfix.vim @@ -3350,3 +3350,15 @@ func Test_qftitle() call assert_equal('Errors', w:quickfix_title) cclose endfunc + +func Test_lbuffer_with_bwipe() + new + new + augroup nasty + au * * bwipe + augroup END + lbuffer + augroup nasty + au! + augroup END +endfunc diff --git a/src/version.c b/src/version.c index 68b4c26b86..6406e6cd87 100644 --- a/src/version.c +++ b/src/version.c @@ -761,6 +761,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 60, /**/ 59, /**/ From 84a9308511871d9ff94c91a1c6badb92300ded98 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 16 Jun 2018 22:58:15 +0200 Subject: [PATCH 08/19] patch 8.1.0061: window title is wrong after resetting and setting 'title' Problem: Window title is wrong after resetting and setting 'title'. Solution: Move resetting the title into maketitle(). (Jason Franklin) --- src/buffer.c | 59 +++++++++++++++++++++++++++------------------------ src/option.c | 30 ++++---------------------- src/version.c | 2 ++ 3 files changed, 37 insertions(+), 54 deletions(-) diff --git a/src/buffer.c b/src/buffer.c index 68b4a04575..254aad461d 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -38,7 +38,7 @@ static int buf_same_ino(buf_T *buf, stat_T *stp); static int otherfile_buf(buf_T *buf, char_u *ffname); #endif #ifdef FEAT_TITLE -static int ti_change(char_u *str, char_u **last); +static int value_changed(char_u *str, char_u **last); #endif static int append_arg_number(win_T *wp, char_u *buf, int buflen, int add_file); static void free_buffer(buf_T *); @@ -3545,20 +3545,18 @@ col_print( } #if defined(FEAT_TITLE) || defined(PROTO) -/* - * put file name in title bar of window and in icon title - */ - static char_u *lasttitle = NULL; static char_u *lasticon = NULL; +/* + * Put the file name in the title bar and icon of the window. + */ void maketitle(void) { char_u *p; - char_u *t_str = NULL; - char_u *i_name; - char_u *i_str = NULL; + char_u *title_str = NULL; + char_u *icon_str = NULL; int maxlen = 0; int len; int mustset; @@ -3574,7 +3572,7 @@ maketitle(void) need_maketitle = FALSE; if (!p_title && !p_icon && lasttitle == NULL && lasticon == NULL) - return; + return; // nothing to do if (p_title) { @@ -3585,7 +3583,7 @@ maketitle(void) maxlen = 10; } - t_str = buf; + title_str = buf; if (*p_titlestring != NUL) { #ifdef FEAT_STL_OPT @@ -3598,7 +3596,7 @@ maketitle(void) use_sandbox = was_set_insecurely((char_u *)"titlestring", 0); # endif called_emsg = FALSE; - build_stl_str_hl(curwin, t_str, sizeof(buf), + build_stl_str_hl(curwin, title_str, sizeof(buf), p_titlestring, use_sandbox, 0, maxlen, NULL, NULL); if (called_emsg) @@ -3608,7 +3606,7 @@ maketitle(void) } else #endif - t_str = p_titlestring; + title_str = p_titlestring; } else { @@ -3714,11 +3712,11 @@ maketitle(void) } } } - mustset = ti_change(t_str, &lasttitle); + mustset = value_changed(title_str, &lasttitle); if (p_icon) { - i_str = buf; + icon_str = buf; if (*p_iconstring != NUL) { #ifdef FEAT_STL_OPT @@ -3731,7 +3729,7 @@ maketitle(void) use_sandbox = was_set_insecurely((char_u *)"iconstring", 0); # endif called_emsg = FALSE; - build_stl_str_hl(curwin, i_str, sizeof(buf), + build_stl_str_hl(curwin, icon_str, sizeof(buf), p_iconstring, use_sandbox, 0, 0, NULL, NULL); if (called_emsg) @@ -3741,32 +3739,32 @@ maketitle(void) } else #endif - i_str = p_iconstring; + icon_str = p_iconstring; } else { if (buf_spname(curbuf) != NULL) - i_name = buf_spname(curbuf); + p = buf_spname(curbuf); else /* use file name only in icon */ - i_name = gettail(curbuf->b_ffname); - *i_str = NUL; + p = gettail(curbuf->b_ffname); + *icon_str = NUL; /* Truncate name at 100 bytes. */ - len = (int)STRLEN(i_name); + len = (int)STRLEN(p); if (len > 100) { len -= 100; #ifdef FEAT_MBYTE if (has_mbyte) - len += (*mb_tail_off)(i_name, i_name + len) + 1; + len += (*mb_tail_off)(p, p + len) + 1; #endif - i_name += len; + p += len; } - STRCPY(i_str, i_name); - trans_characters(i_str, IOSIZE); + STRCPY(icon_str, p); + trans_characters(icon_str, IOSIZE); } } - mustset |= ti_change(i_str, &lasticon); + mustset |= value_changed(icon_str, &lasticon); if (mustset) resettitle(); @@ -3775,20 +3773,25 @@ maketitle(void) /* * Used for title and icon: Check if "str" differs from "*last". Set "*last" * from "str" if it does. - * Return TRUE when "*last" changed. + * Return TRUE if resettitle() is to be called. */ static int -ti_change(char_u *str, char_u **last) +value_changed(char_u *str, char_u **last) { if ((str == NULL) != (*last == NULL) || (str != NULL && *last != NULL && STRCMP(str, *last) != 0)) { vim_free(*last); if (str == NULL) + { *last = NULL; + mch_restore_title(last == &lasttitle ? 1 : 2); + } else + { *last = vim_strsave(str); - return TRUE; + return TRUE; + } } return FALSE; } diff --git a/src/option.c b/src/option.c index 0200b207c7..23560798a1 100644 --- a/src/option.c +++ b/src/option.c @@ -3256,9 +3256,6 @@ static char_u *illegal_char(char_u *, int); #ifdef FEAT_CMDWIN static char_u *check_cedit(void); #endif -#ifdef FEAT_TITLE -static void did_set_title(int icon); -#endif static char_u *option_expand(int opt_idx, char_u *val); static void didset_options(void); static void didset_options2(void); @@ -5374,27 +5371,14 @@ check_cedit(void) * the old value back. */ static void -did_set_title( - int icon) /* Did set icon instead of title */ +did_set_title(void) { if (starting != NO_SCREEN #ifdef FEAT_GUI && !gui.starting #endif ) - { maketitle(); - if (icon) - { - if (!p_icon) - mch_restore_title(2); - } - else - { - if (!p_title) - mch_restore_title(1); - } - } } #endif @@ -6949,8 +6933,7 @@ did_set_string_option( else stl_syntax &= ~flagval; # endif - did_set_title(varp == &p_iconstring); - + did_set_title(); } #endif @@ -8401,14 +8384,9 @@ set_bool_option( #ifdef FEAT_TITLE /* when 'title' changed, may need to change the title; same for 'icon' */ - else if ((int *)varp == &p_title) + else if ((int *)varp == &p_title || (int *)varp == &p_icon) { - did_set_title(FALSE); - } - - else if ((int *)varp == &p_icon) - { - did_set_title(TRUE); + did_set_title(); } #endif diff --git a/src/version.c b/src/version.c index 6406e6cd87..c8c4dd15e1 100644 --- a/src/version.c +++ b/src/version.c @@ -761,6 +761,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 61, /**/ 60, /**/ From 491ac28d5f91505519c623ebc1a9ab08834bf367 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 17 Jun 2018 14:47:55 +0200 Subject: [PATCH 09/19] patch 8.1.0062: popup menu broken if a callback changes the window layout Problem: Popup menu broken if a callback changes the window layout. (Qiming Zhao) Solution: Recompute the popup menu position if needed. Redraw the ruler even when the popup menu is displayed. --- src/popupmnu.c | 69 +++++++++++++++++++++++++++++++++++------- src/proto/popupmnu.pro | 1 + src/screen.c | 19 ++++++------ src/version.c | 2 ++ 4 files changed, 71 insertions(+), 20 deletions(-) diff --git a/src/popupmnu.c b/src/popupmnu.c index 9bebceb894..66fd6b9c53 100644 --- a/src/popupmnu.c +++ b/src/popupmnu.c @@ -29,6 +29,12 @@ static int pum_scrollbar; /* TRUE when scrollbar present */ static int pum_row; /* top row of pum */ static int pum_col; /* left column of pum */ +static int pum_win_row; +static int pum_win_height; +static int pum_win_col; +static int pum_win_wcol; +static int pum_win_width; + static int pum_do_redraw = FALSE; /* do redraw anyway */ static int pum_set_selected(int n, int repeat); @@ -81,7 +87,6 @@ pum_display( { int def_width; int max_width; - int row; int context_lines; int cursor_col; int above_row; @@ -103,7 +108,13 @@ pum_display( validate_cursor_col(); pum_array = NULL; - row = curwin->w_wrow + W_WINROW(curwin); + // Remember the essential parts of the window position and size, so we + // can decide when to reposition the popup menu. + pum_win_row = curwin->w_wrow + W_WINROW(curwin); + pum_win_height = curwin->w_height; + pum_win_col = curwin->w_wincol; + pum_win_wcol = curwin->w_wcol; + pum_win_width = curwin->w_width; #if defined(FEAT_QUICKFIX) FOR_ALL_WINDOWS(pvwin) @@ -128,12 +139,12 @@ pum_display( if (p_ph > 0 && pum_height > p_ph) pum_height = p_ph; - /* Put the pum below "row" if possible. If there are few lines decide + /* Put the pum below "pum_win_row" if possible. If there are few lines decide * on where there is more room. */ - if (row + 2 >= below_row - pum_height - && row - above_row > (below_row - above_row) / 2) + if (pum_win_row + 2 >= below_row - pum_height + && pum_win_row - above_row > (below_row - above_row) / 2) { - /* pum above "row" */ + /* pum above "pum_win_row" */ /* Leave two lines of context if possible */ if (curwin->w_wrow - curwin->w_cline_row >= 2) @@ -141,15 +152,15 @@ pum_display( else context_lines = curwin->w_wrow - curwin->w_cline_row; - if (row >= size + context_lines) + if (pum_win_row >= size + context_lines) { - pum_row = row - size - context_lines; + pum_row = pum_win_row - size - context_lines; pum_height = size; } else { pum_row = 0; - pum_height = row - context_lines; + pum_height = pum_win_row - context_lines; } if (p_ph > 0 && pum_height > p_ph) { @@ -159,7 +170,7 @@ pum_display( } else { - /* pum below "row" */ + /* pum below "pum_win_row" */ /* Leave two lines of context if possible */ if (curwin->w_cline_row @@ -169,7 +180,7 @@ pum_display( context_lines = curwin->w_cline_row + curwin->w_cline_height - curwin->w_wrow; - pum_row = row + context_lines; + pum_row = pum_win_row + context_lines; if (size > below_row - pum_row) pum_height = below_row - pum_row; else @@ -822,6 +833,42 @@ pum_visible(void) return !pum_do_redraw && pum_array != NULL; } +/* + * Reposition the popup menu to adjust for window layout changes. + */ + void +pum_may_redraw(void) +{ + pumitem_T *array = pum_array; + int len = pum_size; + int selected = pum_selected; + + if (!pum_visible()) + return; // nothing to do + + if (pum_win_row == curwin->w_wrow + W_WINROW(curwin) + && pum_win_height == curwin->w_height + && pum_win_col == curwin->w_wincol + && pum_win_width == curwin->w_width) + { + // window position didn't change, redraw in the same position + pum_redraw(); + } + else + { + int wcol = curwin->w_wcol; + + // Window layout changed, recompute the position. + // Use the remembered w_wcol value, the cursor may have moved when a + // completion was inserted, but we want the menu in the same position. + pum_undisplay(); + curwin->w_wcol = pum_win_wcol; + curwin->w_valid |= VALID_WCOL; + pum_display(array, len, selected); + curwin->w_wcol = wcol; + } +} + /* * Return the height of the popup menu, the number of entries visible. * Only valid when pum_visible() returns TRUE! diff --git a/src/proto/popupmnu.pro b/src/proto/popupmnu.pro index d5e1bbd235..f553100bb1 100644 --- a/src/proto/popupmnu.pro +++ b/src/proto/popupmnu.pro @@ -4,6 +4,7 @@ void pum_redraw(void); void pum_undisplay(void); void pum_clear(void); int pum_visible(void); +void pum_may_redraw(void); int pum_get_height(void); int split_message(char_u *mesg, pumitem_T **array); void ui_remove_balloon(void); diff --git a/src/screen.c b/src/screen.c index 5ffc357d7d..2fae1805d3 100644 --- a/src/screen.c +++ b/src/screen.c @@ -171,7 +171,7 @@ static void redraw_win_toolbar(win_T *wp); static void win_redr_custom(win_T *wp, int draw_ruler); #endif #ifdef FEAT_CMDL_INFO -static void win_redr_ruler(win_T *wp, int always); +static void win_redr_ruler(win_T *wp, int always, int ignore_pum); #endif /* Ugly global: overrule attribute used by screen_char() */ @@ -783,8 +783,7 @@ update_screen(int type_arg) #endif #ifdef FEAT_INS_EXPAND /* May need to redraw the popup menu. */ - if (pum_visible()) - pum_redraw(); + pum_may_redraw(); #endif /* Reset b_mod_set flags. Going through all windows is probably faster @@ -7002,7 +7001,7 @@ win_redr_status(win_T *wp, int ignore_pum) - 1 + wp->w_wincol), attr); #ifdef FEAT_CMDL_INFO - win_redr_ruler(wp, TRUE); + win_redr_ruler(wp, TRUE, ignore_pum); #endif } @@ -10455,7 +10454,7 @@ showmode(void) /* If the last window has no status line, the ruler is after the mode * message and must be redrawn */ if (redrawing() && lastwin->w_status_height == 0) - win_redr_ruler(lastwin, TRUE); + win_redr_ruler(lastwin, TRUE, FALSE); #endif redraw_cmdline = FALSE; clear_cmdline = FALSE; @@ -10874,6 +10873,7 @@ redraw_win_toolbar(win_T *wp) (int)wp->w_width, FALSE); } #endif + /* * Show current status info in ruler and various other places * If always is FALSE, only show ruler if position has changed. @@ -10899,7 +10899,7 @@ showruler(int always) else #endif #ifdef FEAT_CMDL_INFO - win_redr_ruler(curwin, always); + win_redr_ruler(curwin, always, FALSE); #endif #ifdef FEAT_TITLE @@ -10918,7 +10918,7 @@ showruler(int always) #ifdef FEAT_CMDL_INFO static void -win_redr_ruler(win_T *wp, int always) +win_redr_ruler(win_T *wp, int always, int ignore_pum) { #define RULER_BUF_LEN 70 char_u buffer[RULER_BUF_LEN]; @@ -10951,8 +10951,9 @@ win_redr_ruler(win_T *wp, int always) if (wp == lastwin && lastwin->w_status_height == 0) if (edit_submode != NULL) return; - /* Don't draw the ruler when the popup menu is visible, it may overlap. */ - if (pum_visible()) + // Don't draw the ruler when the popup menu is visible, it may overlap. + // Except when the popup menu will be redrawn anyway. + if (!ignore_pum && pum_visible()) return; #endif diff --git a/src/version.c b/src/version.c index c8c4dd15e1..bcbbe40221 100644 --- a/src/version.c +++ b/src/version.c @@ -761,6 +761,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 62, /**/ 61, /**/ From d595a1910c5672808e44afa028e253e47f03651f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 17 Jun 2018 15:01:04 +0200 Subject: [PATCH 10/19] patch 8.1.0063: Mac: NSStringPboardType is deprecated Problem: Mac: NSStringPboardType is deprecated. Solution: Use NSPasteboardTypeString. (Akshay Hegde, closes #3022) --- src/os_macosx.m | 23 +++++++++++++++++++++-- src/version.c | 2 ++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/os_macosx.m b/src/os_macosx.m index b0d29d9477..752bdae116 100644 --- a/src/os_macosx.m +++ b/src/os_macosx.m @@ -63,8 +63,13 @@ clip_mch_request_selection(VimClipboard *cbd) NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSPasteboard *pb = [NSPasteboard generalPasteboard]; +#ifdef AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER + NSArray *supportedTypes = [NSArray arrayWithObjects:VimPboardType, + NSPasteboardTypeString, nil]; +#else NSArray *supportedTypes = [NSArray arrayWithObjects:VimPboardType, NSStringPboardType, nil]; +#endif NSString *bestType = [pb availableTypeFromArray:supportedTypes]; if (!bestType) goto releasepool; @@ -76,7 +81,7 @@ clip_mch_request_selection(VimClipboard *cbd) /* This type should consist of an array with two objects: * 1. motion type (NSNumber) * 2. text (NSString) - * If this is not the case we fall back on using NSStringPboardType. + * If this is not the case we fall back on using NSPasteboardTypeString. */ id plist = [pb propertyListForType:VimPboardType]; if ([plist isKindOfClass:[NSArray class]] && [plist count] == 2) @@ -92,10 +97,15 @@ clip_mch_request_selection(VimClipboard *cbd) if (!string) { - /* Use NSStringPboardType. The motion type is detected automatically. + /* Use NSPasteboardTypeString. The motion type is detected automatically. */ +#ifdef AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER + NSMutableString *mstring = + [[pb stringForType:NSPasteboardTypeString] mutableCopy]; +#else NSMutableString *mstring = [[pb stringForType:NSStringPboardType] mutableCopy]; +#endif if (!mstring) goto releasepool; /* Replace unrecognized end-of-line sequences with \x0a (line feed). */ @@ -178,15 +188,24 @@ clip_mch_set_selection(VimClipboard *cbd) /* See clip_mch_request_selection() for info on pasteboard types. */ NSPasteboard *pb = [NSPasteboard generalPasteboard]; +#ifdef AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER + NSArray *supportedTypes = [NSArray arrayWithObjects:VimPboardType, + NSPasteboardTypeString, nil]; +#else NSArray *supportedTypes = [NSArray arrayWithObjects:VimPboardType, NSStringPboardType, nil]; +#endif [pb declareTypes:supportedTypes owner:nil]; NSNumber *motion = [NSNumber numberWithInt:motion_type]; NSArray *plist = [NSArray arrayWithObjects:motion, string, nil]; [pb setPropertyList:plist forType:VimPboardType]; +#ifdef AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER + [pb setString:string forType:NSPasteboardTypeString]; +#else [pb setString:string forType:NSStringPboardType]; +#endif [string release]; } diff --git a/src/version.c b/src/version.c index bcbbe40221..9b4e028ba1 100644 --- a/src/version.c +++ b/src/version.c @@ -761,6 +761,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 63, /**/ 62, /**/ From 942b4541a2d8e8df8369ab70e112dbbbe0c7c0aa Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 17 Jun 2018 16:23:34 +0200 Subject: [PATCH 11/19] patch 8.1.0064: typing CTRL-W in a prompt buffer shows mode "-- --" Problem: Typing CTRL-W in a prompt buffer shows mode "-- --". Solution: Set restart_edit to 'A' and check for it. --- src/edit.c | 2 +- src/screen.c | 4 ++-- src/version.c | 2 ++ src/window.c | 2 ++ 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/edit.c b/src/edit.c index 326a382b54..3204ec31a7 100644 --- a/src/edit.c +++ b/src/edit.c @@ -1179,7 +1179,7 @@ doESCkey: // In a prompt window CTRL-W is used for window commands. // Use Shift-CTRL-W to delete a word. stuffcharReadbuff(Ctrl_W); - restart_edit = 'i'; + restart_edit = 'A'; nomove = TRUE; count = 0; goto doESCkey; diff --git a/src/screen.c b/src/screen.c index 2fae1805d3..3dde1b7a1c 100644 --- a/src/screen.c +++ b/src/screen.c @@ -10263,7 +10263,7 @@ showmode(void) do_mode = ((p_smd && msg_silent == 0) && ((State & INSERT) - || restart_edit + || restart_edit != NUL || VIsual_active)); if (do_mode || reg_recording != 0) { @@ -10370,7 +10370,7 @@ showmode(void) #endif MSG_PUTS_ATTR(_(" INSERT"), attr); } - else if (restart_edit == 'I') + else if (restart_edit == 'I' || restart_edit == 'A') MSG_PUTS_ATTR(_(" (insert)"), attr); else if (restart_edit == 'R') MSG_PUTS_ATTR(_(" (replace)"), attr); diff --git a/src/version.c b/src/version.c index 9b4e028ba1..8159e480c8 100644 --- a/src/version.c +++ b/src/version.c @@ -761,6 +761,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 64, /**/ 63, /**/ diff --git a/src/window.c b/src/window.c index 4f4f08b675..f059b37663 100644 --- a/src/window.c +++ b/src/window.c @@ -2114,6 +2114,8 @@ leaving_window(win_T *win) // When leaving a prompt window stop Insert mode and perhaps restart // it when entering that window again. win->w_buffer->b_prompt_insert = restart_edit; + if (restart_edit != 0 && mode_displayed) + clear_cmdline = TRUE; /* unshow mode later */ restart_edit = NUL; // When leaving the window (or closing the window) was done from a From 0e6e179f55b85b9e82e74d3f993928d52f0f4d43 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 17 Jun 2018 17:10:59 +0200 Subject: [PATCH 12/19] patch 8.1.0065: balloon displayed at the wrong position Problem: Balloon displayed at the wrong position. Solution: Do not reposition the popup menu at the cursor position. --- src/popupmnu.c | 14 ++++++++++---- src/version.c | 2 ++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/popupmnu.c b/src/popupmnu.c index 66fd6b9c53..5248217255 100644 --- a/src/popupmnu.c +++ b/src/popupmnu.c @@ -29,6 +29,7 @@ static int pum_scrollbar; /* TRUE when scrollbar present */ static int pum_row; /* top row of pum */ static int pum_col; /* left column of pum */ +static win_T *pum_window = NULL; static int pum_win_row; static int pum_win_height; static int pum_win_col; @@ -110,6 +111,7 @@ pum_display( // Remember the essential parts of the window position and size, so we // can decide when to reposition the popup menu. + pum_window = curwin; pum_win_row = curwin->w_wrow + W_WINROW(curwin); pum_win_height = curwin->w_height; pum_win_col = curwin->w_wincol; @@ -846,10 +848,11 @@ pum_may_redraw(void) if (!pum_visible()) return; // nothing to do - if (pum_win_row == curwin->w_wrow + W_WINROW(curwin) - && pum_win_height == curwin->w_height - && pum_win_col == curwin->w_wincol - && pum_win_width == curwin->w_width) + if (pum_window != curwin + || (pum_win_row == curwin->w_wrow + W_WINROW(curwin) + && pum_win_height == curwin->w_height + && pum_win_col == curwin->w_wincol + && pum_win_width == curwin->w_width)) { // window position didn't change, redraw in the same position pum_redraw(); @@ -912,6 +915,9 @@ pum_position_at_mouse(int min_width) pum_width = Columns - pum_col; if (pum_width > pum_base_width + 1) pum_width = pum_base_width + 1; + + // Do not redraw at cursor position. + pum_window = NULL; } # endif diff --git a/src/version.c b/src/version.c index 8159e480c8..192b6cd2aa 100644 --- a/src/version.c +++ b/src/version.c @@ -761,6 +761,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 65, /**/ 64, /**/ From c3ffc9b8d3015dc5280b297b4e3deb4f34944bd4 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 17 Jun 2018 17:32:58 +0200 Subject: [PATCH 13/19] patch 8.1.0066: nasty autocommand causes using freed memory Problem: Nasty autocommand causes using freed memory. (Dominique Pelle) Solution: Do not force executing autocommands if the value of 'syntax' or 'filetype' did not change. --- src/option.c | 18 ++++++++++++------ src/version.c | 2 ++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/option.c b/src/option.c index 23560798a1..2ecdcea649 100644 --- a/src/option.c +++ b/src/option.c @@ -6029,7 +6029,7 @@ did_set_string_option( /* set when changing an option that only requires a redraw in the GUI */ int redraw_gui_only = FALSE; #endif - int ft_changed = FALSE; + int value_changed = FALSE; #if defined(FEAT_VTP) && defined(FEAT_TERMGUICOLORS) int did_swaptcap = FALSE; #endif @@ -7437,7 +7437,7 @@ did_set_string_option( if (!valid_filetype(*varp)) errmsg = e_invarg; else - ft_changed = STRCMP(oldval, *varp) != 0; + value_changed = STRCMP(oldval, *varp) != 0; } #ifdef FEAT_SYN_HL @@ -7445,6 +7445,8 @@ did_set_string_option( { if (!valid_filetype(*varp)) errmsg = e_invarg; + else + value_changed = STRCMP(oldval, *varp) != 0; } #endif @@ -7565,20 +7567,24 @@ did_set_string_option( /* When 'syntax' is set, load the syntax of that name */ if (varp == &(curbuf->b_p_syn)) { + // Only pass TRUE for "force" when the value changed, to avoid + // endless recurrence. */ apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn, - curbuf->b_fname, TRUE, curbuf); + curbuf->b_fname, value_changed, curbuf); } #endif else if (varp == &(curbuf->b_p_ft)) { /* 'filetype' is set, trigger the FileType autocommand. * Skip this when called from a modeline and the filetype was - * already set to this value. */ - if (!(opt_flags & OPT_MODELINE) || ft_changed) + * already set to this value. + * Only pass TRUE for "force" when the value changed, to avoid + * endless recurrence. */ + if (!(opt_flags & OPT_MODELINE) || value_changed) { did_filetype = TRUE; apply_autocmds(EVENT_FILETYPE, curbuf->b_p_ft, - curbuf->b_fname, TRUE, curbuf); + curbuf->b_fname, value_changed, curbuf); /* Just in case the old "curbuf" is now invalid. */ if (varp != &(curbuf->b_p_ft)) varp = NULL; diff --git a/src/version.c b/src/version.c index 192b6cd2aa..d3c7316c91 100644 --- a/src/version.c +++ b/src/version.c @@ -761,6 +761,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 66, /**/ 65, /**/ From a5616b0136cea2104a475d143a1685d71e9b2d3d Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 17 Jun 2018 19:08:30 +0200 Subject: [PATCH 14/19] patch 8.1.0067: syntax highlighting not working when re-entering a buffer Problem: Syntax highlighting not working when re-entering a buffer. Solution: Do force executing autocommands when not called recursively. --- src/option.c | 26 +++++++++++++++++--------- src/version.c | 2 ++ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/option.c b/src/option.c index 2ecdcea649..cf774ac236 100644 --- a/src/option.c +++ b/src/option.c @@ -7567,24 +7567,32 @@ did_set_string_option( /* When 'syntax' is set, load the syntax of that name */ if (varp == &(curbuf->b_p_syn)) { - // Only pass TRUE for "force" when the value changed, to avoid - // endless recurrence. */ - apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn, - curbuf->b_fname, value_changed, curbuf); + static int syn_recursive = 0; + + ++syn_recursive; + // Only pass TRUE for "force" when the value changed or not used + // recursively, to avoid endless recurrence. + apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn, curbuf->b_fname, + value_changed || syn_recursive == 1, curbuf); + --syn_recursive; } #endif else if (varp == &(curbuf->b_p_ft)) { /* 'filetype' is set, trigger the FileType autocommand. * Skip this when called from a modeline and the filetype was - * already set to this value. - * Only pass TRUE for "force" when the value changed, to avoid - * endless recurrence. */ + * already set to this value. */ if (!(opt_flags & OPT_MODELINE) || value_changed) { + static int ft_recursive = 0; + + ++ft_recursive; did_filetype = TRUE; - apply_autocmds(EVENT_FILETYPE, curbuf->b_p_ft, - curbuf->b_fname, value_changed, curbuf); + // Only pass TRUE for "force" when the value changed or not + // used recursively, to avoid endless recurrence. + apply_autocmds(EVENT_FILETYPE, curbuf->b_p_ft, curbuf->b_fname, + value_changed || ft_recursive == 1, curbuf); + --ft_recursive; /* Just in case the old "curbuf" is now invalid. */ if (varp != &(curbuf->b_p_ft)) varp = NULL; diff --git a/src/version.c b/src/version.c index d3c7316c91..0ecc60c497 100644 --- a/src/version.c +++ b/src/version.c @@ -761,6 +761,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 67, /**/ 66, /**/ From 2f82ca7d79148ae931bf28a747ede06ba8a65de8 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 17 Jun 2018 19:22:52 +0200 Subject: [PATCH 15/19] patch 8.1.0068: nasty autocommands can still cause using freed memory Problem: Nasty autocommands can still cause using freed memory. Solution: Disallow using setloclist() and setqflist() recursively. --- src/evalfunc.c | 8 +++++++- src/version.c | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/evalfunc.c b/src/evalfunc.c index 2bbeb25692..4960203978 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -10621,6 +10621,7 @@ set_qf_ll_list( static char *e_invact = N_("E927: Invalid action: '%s'"); char_u *act; int action = 0; + static int recursive = 0; #endif rettv->vval.v_number = -1; @@ -10628,6 +10629,8 @@ set_qf_ll_list( #ifdef FEAT_QUICKFIX if (list_arg->v_type != VAR_LIST) EMSG(_(e_listreq)); + else if (recursive != 0) + EMSG(_(e_au_recursive)); else { list_T *l = list_arg->vval.v_list; @@ -10662,9 +10665,12 @@ set_qf_ll_list( } } + ++recursive; if (l != NULL && action && valid_dict && set_errorlist(wp, l, action, - (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"), d) == OK) + (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"), + d) == OK) rettv->vval.v_number = 0; + --recursive; } #endif } diff --git a/src/version.c b/src/version.c index 0ecc60c497..e55be5206b 100644 --- a/src/version.c +++ b/src/version.c @@ -761,6 +761,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 68, /**/ 67, /**/ From 0e5979a6d491f68c4a8c86fab489016919329a6b Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 17 Jun 2018 19:36:33 +0200 Subject: [PATCH 16/19] patch 8.1.0069: cannot handle pressing CTRL-C in a prompt buffer Problem: Cannot handle pressing CTRL-C in a prompt buffer. Solution: Add prompt_setinterrupt(). --- runtime/doc/eval.txt | 38 ++++++++++++++++++++++++++------------ src/channel.c | 26 +++++++++++++++++++++++++- src/edit.c | 13 +++++++++++++ src/evalfunc.c | 31 +++++++++++++++++++++++++++++++ src/proto/channel.pro | 1 + src/version.c | 2 ++ 6 files changed, 98 insertions(+), 13 deletions(-) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index ead6b89281..36e4f22bad 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -2297,8 +2297,9 @@ pow({x}, {y}) Float {x} to the power of {y} prevnonblank({lnum}) Number line nr of non-blank line <= {lnum} printf({fmt}, {expr1}...) String format text prompt_addtext({buf}, {expr}) none add text to a prompt buffer -prompt_setprompt({buf}, {text}) none set prompt text prompt_setcallback({buf}, {expr}) none set prompt callback function +prompt_setinterrupt({buf}, {text}) none set prompt interrupt function +prompt_setprompt({buf}, {text}) none set prompt text pumvisible() Number whether popup menu is visible pyeval({expr}) any evaluate |Python| expression py3eval({expr}) any evaluate |python3| expression @@ -6506,17 +6507,11 @@ printf({fmt}, {expr1} ...) *printf()* arguments an error is given. Up to 18 arguments can be used. -prompt_setprompt({buf}, {text}) *prompt_setprompt()* - Set prompt for buffer {buf} to {text}. You most likely want - {text} to end in a space. - The result is only visible if {buf} has 'buftype' set to - "prompt". Example: > - call prompt_setprompt(bufnr(''), 'command: ') - - prompt_setcallback({buf}, {expr}) *prompt_setcallback()* - Set prompt callback for buffer {buf} to {expr}. This has only + Set prompt callback for buffer {buf} to {expr}. When {expr} + is an empty string the callback is removed. This has only effect if {buf} has 'buftype' set to "prompt". + The callback is invoked when pressing Enter. The current buffer will always be the prompt buffer. A new line for a prompt is added before invoking the callback, thus the prompt @@ -6541,6 +6536,22 @@ prompt_setcallback({buf}, {expr}) *prompt_setcallback()* endif endfunc +prompt_setinterrupt({buf}, {expr}) *prompt_setinterrupt()* + Set a callback for buffer {buf} to {expr}. When {expr} is an + empty string the callback is removed. This has only effect if + {buf} has 'buftype' set to "prompt". + + This callback will be invoked when pressing CTRL-C in Insert + mode. Without setting a callback Vim will exit Insert mode, + as in any buffer. + +prompt_setprompt({buf}, {text}) *prompt_setprompt()* + Set prompt for buffer {buf} to {text}. You most likely want + {text} to end in a space. + The result is only visible if {buf} has 'buftype' set to + "prompt". Example: > + call prompt_setprompt(bufnr(''), 'command: ') + pumvisible() *pumvisible()* Returns non-zero when the popup menu is visible, zero @@ -8563,7 +8574,9 @@ term_start({cmd}, {options}) *term_start()* instead of using 'termwinsize' "term_cols" horizontal size to use for the terminal, instead of using 'termwinsize' - "vertical" split the window vertically + "vertical" split the window vertically; note that + other window position can be defined with + command modifiers, such as |:belowright|. "curwin" use the current window, do not split the window; fails if the current buffer cannot be |abandon|ed @@ -9392,11 +9405,12 @@ vtp Compiled for vcon support |+vtp| (check vcon to find out if it works in the current console). wildignore Compiled with 'wildignore' option. wildmenu Compiled with 'wildmenu' option. +win16 old version for MS-Windows 3.1 (always False) win32 Win32 version of Vim (MS-Windows 95 and later, 32 or 64 bits) win32unix Win32 version of Vim, using Unix files (Cygwin) win64 Win64 version of Vim (MS-Windows 64 bit). -win95 Win32 version for MS-Windows 95/98/ME. +win95 Win32 version for MS-Windows 95/98/ME (always False) winaltkeys Compiled with 'winaltkeys' option. windows Compiled with support for more than one window. writebackup Compiled with 'writebackup' default on. diff --git a/src/channel.c b/src/channel.c index d654dc06d3..1363ee9299 100644 --- a/src/channel.c +++ b/src/channel.c @@ -5856,7 +5856,7 @@ invoke_prompt_callback(void) curwin->w_cursor.lnum = lnum + 1; curwin->w_cursor.col = 0; - if (curbuf->b_prompt_callback == NULL) + if (curbuf->b_prompt_callback == NULL || *curbuf->b_prompt_callback == NUL) return; text = ml_get(lnum); prompt = prompt_text(); @@ -5874,4 +5874,28 @@ invoke_prompt_callback(void) clear_tv(&rettv); } +/* + * Return TRUE when the interrupt callback was invoked. + */ + int +invoke_prompt_interrupt(void) +{ + typval_T rettv; + int dummy; + typval_T argv[1]; + + if (curbuf->b_prompt_interrupt == NULL + || *curbuf->b_prompt_interrupt == NUL) + return FALSE; + argv[0].v_type = VAR_UNKNOWN; + + got_int = FALSE; // don't skip executing commands + call_func(curbuf->b_prompt_interrupt, + (int)STRLEN(curbuf->b_prompt_interrupt), + &rettv, 0, argv, NULL, 0L, 0L, &dummy, TRUE, + curbuf->b_prompt_int_partial, NULL); + clear_tv(&rettv); + return TRUE; +} + #endif /* FEAT_JOB_CHANNEL */ diff --git a/src/edit.c b/src/edit.c index 3204ec31a7..6a636b9e12 100644 --- a/src/edit.c +++ b/src/edit.c @@ -1016,6 +1016,19 @@ edit( goto doESCkey; } #endif +#ifdef FEAT_JOB_CHANNEL + if (c == Ctrl_C && bt_prompt(curbuf)) + { + if (invoke_prompt_interrupt()) + { + if (!bt_prompt(curbuf)) + // buffer changed to a non-prompt buffer, get out of + // Insert mode + goto doESCkey; + break; + } + } +#endif #ifdef UNIX do_intr: diff --git a/src/evalfunc.c b/src/evalfunc.c index 4960203978..3cb66f3bbc 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -298,6 +298,7 @@ static void f_prevnonblank(typval_T *argvars, typval_T *rettv); static void f_printf(typval_T *argvars, typval_T *rettv); #ifdef FEAT_JOB_CHANNEL static void f_prompt_setcallback(typval_T *argvars, typval_T *rettv); +static void f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv); static void f_prompt_setprompt(typval_T *argvars, typval_T *rettv); #endif static void f_pumvisible(typval_T *argvars, typval_T *rettv); @@ -754,6 +755,7 @@ static struct fst {"printf", 1, 19, f_printf}, #ifdef FEAT_JOB_CHANNEL {"prompt_setcallback", 2, 2, f_prompt_setcallback}, + {"prompt_setinterrupt", 2, 2, f_prompt_setinterrupt}, {"prompt_setprompt", 2, 2, f_prompt_setprompt}, #endif {"pumvisible", 0, 0, f_pumvisible}, @@ -8621,6 +8623,35 @@ f_prompt_setcallback(typval_T *argvars, typval_T *rettv UNUSED) buf->b_prompt_partial = partial; } +/* + * "prompt_setinterrupt({buffer}, {callback})" function + */ + static void +f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv UNUSED) +{ + buf_T *buf; + char_u *callback; + partial_T *partial; + + if (check_secure()) + return; + buf = get_buf_tv(&argvars[0], FALSE); + if (buf == NULL) + return; + + callback = get_callback(&argvars[1], &partial); + if (callback == NULL) + return; + + free_callback(buf->b_prompt_interrupt, buf->b_prompt_int_partial); + if (partial == NULL) + buf->b_prompt_interrupt = vim_strsave(callback); + else + /* pointer into the partial */ + buf->b_prompt_interrupt = callback; + buf->b_prompt_int_partial = partial; +} + /* * "prompt_setprompt({buffer}, {text})" function */ diff --git a/src/proto/channel.pro b/src/proto/channel.pro index 5326276ef1..57b958ae10 100644 --- a/src/proto/channel.pro +++ b/src/proto/channel.pro @@ -72,4 +72,5 @@ void job_info(job_T *job, dict_T *dict); void job_info_all(list_T *l); int job_stop(job_T *job, typval_T *argvars, char *type); void invoke_prompt_callback(void); +int invoke_prompt_interrupt(void); /* vim: set ft=c : */ diff --git a/src/version.c b/src/version.c index e55be5206b..1f462b31b4 100644 --- a/src/version.c +++ b/src/version.c @@ -761,6 +761,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 69, /**/ 68, /**/ From 222cd20e2662e7478cfe42b78cc4f1c153ca819d Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 17 Jun 2018 20:10:39 +0200 Subject: [PATCH 17/19] patch 8.1.0070: missing part of the changes for prompt_setinterrupt() Problem: Missing part of the changes for prompt_setinterrupt(). Solution: Add the missing changes. --- src/structs.h | 2 ++ src/version.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/structs.h b/src/structs.h index e76acc8323..56fcf674e6 100644 --- a/src/structs.h +++ b/src/structs.h @@ -2360,6 +2360,8 @@ struct file_buffer char_u *b_prompt_text; // set by prompt_setprompt() char_u *b_prompt_callback; // set by prompt_setcallback() partial_T *b_prompt_partial; // set by prompt_setcallback() + char_u *b_prompt_interrupt; // set by prompt_setinterrupt() + partial_T *b_prompt_int_partial; // set by prompt_setinterrupt() int b_prompt_insert; // value for restart_edit when entering // a prompt buffer window. #endif diff --git a/src/version.c b/src/version.c index 1f462b31b4..6a294f7811 100644 --- a/src/version.c +++ b/src/version.c @@ -761,6 +761,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 70, /**/ 69, /**/ From b3307b5e7e7bd3962b0d5c61a94e638564c146b0 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 17 Jun 2018 21:34:11 +0200 Subject: [PATCH 18/19] patch 8.1.0071: terminal debugger only works with the terminal feature Problem: Terminal debugger only works with the terminal feature. Solution: Make it also work with a prompt buffer. Makes it possible to use on MS-Windows. Various other improvements. (closes #3012) --- runtime/doc/terminal.txt | 30 ++ .../dist/opt/termdebug/plugin/termdebug.vim | 373 +++++++++++++++--- src/version.c | 2 + 3 files changed, 358 insertions(+), 47 deletions(-) diff --git a/runtime/doc/terminal.txt b/runtime/doc/terminal.txt index e4cca34438..8f95fc227c 100644 --- a/runtime/doc/terminal.txt +++ b/runtime/doc/terminal.txt @@ -38,6 +38,7 @@ If the result is "1" you have it. Stepping through code |termdebug-stepping| Inspecting variables |termdebug-variables| Other commands |termdebug-commands| + Prompt mode |termdebug-prompt| Communication |termdebug-communication| Customizing |termdebug-customizing| @@ -620,6 +621,10 @@ The Terminal debugging plugin can be used to debug a program with gdb and view the source code in a Vim window. Since this is completely contained inside Vim this also works remotely over an ssh connection. +When the |+terminal| feature is missing, the plugin will use the "prompt" +buffer type, if possible. The running program will then use a newly opened +terminal window. See |termdebug-prompt| below for details. + Starting ~ *termdebug-starting* @@ -799,6 +804,23 @@ Other commands ~ isn't one +Prompt mode ~ + *termdebug-prompt* +When the |+terminal| feature is not supported and on MS-Windows, gdb will run +in a buffer with 'buftype' set to "prompt". This works slightly differently: +- The gdb window will be in Insert mode while typing commands. Go to Normal + mode with , then you can move around in the buffer, copy/paste, etc. + Go back to editing the gdb command with any command that starts Insert mode, + such as `a` or `i`. +- The program being debugged will run in a separate window. On MS-Windows + this is a new console window. On Unix, if the |+terminal| feature is + available a Terminal window will be opened to run the debugged program in. + + *termdebug_use_prompt* +Prompt mode can be used even when the |+terminal| feature is present with: > + let g:termdebug_use_prompt = 1 + + Communication ~ *termdebug-communication* There is another, hidden, buffer, which is used for Vim to communicate with @@ -836,6 +858,14 @@ When 'background' is "dark": hi debugBreakpoint term=reverse ctermbg=red guibg=red +Shorcuts *termdebug_shortcuts* + +You can define your own shortcuts (mappings) to control gdb, that can work in +any window, using the TermDebugSendCommand() function. Example: > + map ,w :call TermDebugSendCommand('where') +The argument is the gdb command. + + Popup menu *termdebug_popup* By default the Termdebug plugin sets 'mousemodel' to "popup_setpos" and adds diff --git a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim index f2f0f0944d..a01f3f1c78 100644 --- a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim +++ b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim @@ -1,27 +1,60 @@ " Debugger plugin using gdb. " -" WORK IN PROGRESS - much doesn't work yet -" -" Open two visible terminal windows: -" 1. run a pty, as with ":term NONE" -" 2. run gdb, passing the pty -" The current window is used to view source code and follows gdb. -" -" A third terminal window is hidden, it is used for communication with gdb. -" -" The communication with gdb uses GDB/MI. See: -" https://sourceware.org/gdb/current/onlinedocs/gdb/GDB_002fMI.html -" " Author: Bram Moolenaar " Copyright: Vim license applies, see ":help license" +" Last Update: 2018 Jun 3 +" +" WORK IN PROGRESS - Only the basics work +" Note: On MS-Windows you need a recent version of gdb. The one included with +" MingW is too old (7.6.1). +" I used version 7.12 from http://www.equation.com/servlet/equation.cmd?fa=gdb +" +" There are two ways to run gdb: +" - In a terminal window; used if possible, does not work on MS-Windows +" Not used when g:termdebug_use_prompt is set to 1. +" - Using a "prompt" buffer; may use a terminal window for the program +" +" For both the current window is used to view source code and shows the +" current statement from gdb. +" +" USING A TERMINAL WINDOW +" +" Opens two visible terminal windows: +" 1. runs a pty for the debugged program, as with ":term NONE" +" 2. runs gdb, passing the pty of the debugged program +" A third terminal window is hidden, it is used for communication with gdb. +" +" USING A PROMPT BUFFER +" +" Opens a window with a prompt buffer to communicate with gdb. +" Gdb is run as a job with callbacks for I/O. +" On Unix another terminal window is opened to run the debugged program +" On MS-Windows a separate console is opened to run the debugged program +" +" The communication with gdb uses GDB/MI. See: +" https://sourceware.org/gdb/current/onlinedocs/gdb/GDB_002fMI.html -" In case this gets loaded twice. +" In case this gets sourced twice. if exists(':Termdebug') finish endif -" Uncomment this line to write logging in "debuglog". -" call ch_logfile('debuglog', 'w') +" Need either the +terminal feature or +channel and the prompt buffer. +" The terminal feature does not work with gdb on win32. +if has('terminal') && !has('win32') + let s:way = 'terminal' +elseif has('channel') && exists('*prompt_setprompt') + let s:way = 'prompt' +else + if has('terminal') + let s:err = 'Cannot debug, missing prompt buffer support' + else + let s:err = 'Cannot debug, +channel feature is not supported' + endif + command -nargs=* -complete=file -bang Termdebug echoerr s:err + command -nargs=+ -complete=file -bang TermdebugCommand echoerr s:err + finish +endif " The command that starts debugging, e.g. ":Termdebug vim". " To end type "quit" in the gdb window. @@ -59,8 +92,12 @@ func s:StartDebug_internal(dict) echoerr 'Terminal debugger already running' return endif + let s:ptywin = 0 - let s:startwin = win_getid(winnr()) + " Uncomment this line to write logging in "debuglog". + " call ch_logfile('debuglog', 'w') + + let s:sourcewin = win_getid(winnr()) let s:startsigncolumn = &signcolumn let s:save_columns = 0 @@ -69,15 +106,31 @@ func s:StartDebug_internal(dict) let s:save_columns = &columns let &columns = g:termdebug_wide endif - let vertical = 1 + let s:vertical = 1 else - let vertical = 0 + let s:vertical = 0 endif - " Open a terminal window without a job, to run the debugged program + " Override using a terminal window by setting g:termdebug_use_prompt to 1. + let use_prompt = exists('g:termdebug_use_prompt') && g:termdebug_use_prompt + if has('terminal') && !has('win32') && !use_prompt + let s:way = 'terminal' + else + let s:way = 'prompt' + endif + + if s:way == 'prompt' + call s:StartDebug_prompt(a:dict) + else + call s:StartDebug_term(a:dict) + endif +endfunc + +func s:StartDebug_term(dict) + " Open a terminal window without a job, to run the debugged program in. let s:ptybuf = term_start('NONE', { - \ 'term_name': 'gdb program', - \ 'vertical': vertical, + \ 'term_name': 'debugged program', + \ 'vertical': s:vertical, \ }) if s:ptybuf == 0 echoerr 'Failed to open the program terminal window' @@ -85,7 +138,7 @@ func s:StartDebug_internal(dict) endif let pty = job_info(term_getjob(s:ptybuf))['tty_out'] let s:ptywin = win_getid(winnr()) - if vertical + if s:vertical " Assuming the source code window will get a signcolumn, use two more " columns for that, thus one less for the terminal window. exe (&columns / 2 - 1) . "wincmd |" @@ -110,9 +163,9 @@ func s:StartDebug_internal(dict) let proc_args = get(a:dict, 'proc_args', []) let cmd = [g:termdebugger, '-quiet', '-tty', pty] + gdb_args - echomsg 'executing "' . join(cmd) . '"' + call ch_log('executing "' . join(cmd) . '"') let s:gdbbuf = term_start(cmd, { - \ 'exit_cb': function('s:EndDebug'), + \ 'exit_cb': function('s:EndTermDebug'), \ 'term_finish': 'close', \ }) if s:gdbbuf == 0 @@ -166,11 +219,108 @@ func s:StartDebug_internal(dict) " exec-interrupt, since many commands don't work properly while the target is " running. call s:SendCommand('-gdb-set mi-async on') + " Older gdb uses a different command. + call s:SendCommand('-gdb-set target-async on') " Disable pagination, it causes everything to stop at the gdb " "Type to continue" prompt. - call s:SendCommand('-gdb-set pagination off') + call s:SendCommand('set pagination off') + call s:StartDebugCommon(a:dict) +endfunc + +func s:StartDebug_prompt(dict) + " Open a window with a prompt buffer to run gdb in. + if s:vertical + vertical new + else + new + endif + let s:gdbwin = win_getid(winnr()) + let s:promptbuf = bufnr('') + call prompt_setprompt(s:promptbuf, 'gdb> ') + set buftype=prompt + file gdb + call prompt_setcallback(s:promptbuf, function('s:PromptCallback')) + call prompt_setinterrupt(s:promptbuf, function('s:PromptInterrupt')) + + if s:vertical + " Assuming the source code window will get a signcolumn, use two more + " columns for that, thus one less for the terminal window. + exe (&columns / 2 - 1) . "wincmd |" + endif + + " Add -quiet to avoid the intro message causing a hit-enter prompt. + let gdb_args = get(a:dict, 'gdb_args', []) + let proc_args = get(a:dict, 'proc_args', []) + + let cmd = [g:termdebugger, '-quiet', '--interpreter=mi2'] + gdb_args + call ch_log('executing "' . join(cmd) . '"') + + let s:gdbjob = job_start(cmd, { + \ 'exit_cb': function('s:EndPromptDebug'), + \ 'out_cb': function('s:GdbOutCallback'), + \ }) + if job_status(s:gdbjob) != "run" + echoerr 'Failed to start gdb' + exe 'bwipe! ' . s:promptbuf + return + endif + let s:gdb_channel = job_getchannel(s:gdbjob) + + " Interpret commands while the target is running. This should usualy only + " be exec-interrupt, since many commands don't work properly while the + " target is running. + call s:SendCommand('-gdb-set mi-async on') + " Older gdb uses a different command. + call s:SendCommand('-gdb-set target-async on') + + let s:ptybuf = 0 + if has('win32') + " MS-Windows: run in a new console window for maximum compatibility + call s:SendCommand('set new-console on') + elseif has('terminal') + " Unix: Run the debugged program in a terminal window. Open it below the + " gdb window. + belowright let s:ptybuf = term_start('NONE', { + \ 'term_name': 'debugged program', + \ }) + if s:ptybuf == 0 + echoerr 'Failed to open the program terminal window' + call job_stop(s:gdbjob) + return + endif + let s:ptywin = win_getid(winnr()) + let pty = job_info(term_getjob(s:ptybuf))['tty_out'] + call s:SendCommand('tty ' . pty) + + " Since GDB runs in a prompt window, the environment has not been set to + " match a terminal window, need to do that now. + call s:SendCommand('set env TERM = xterm-color') + call s:SendCommand('set env ROWS = ' . winheight(s:ptywin)) + call s:SendCommand('set env LINES = ' . winheight(s:ptywin)) + call s:SendCommand('set env COLUMNS = ' . winwidth(s:ptywin)) + call s:SendCommand('set env COLORS = ' . &t_Co) + call s:SendCommand('set env VIM_TERMINAL = ' . v:version) + else + " TODO: open a new terminal get get the tty name, pass on to gdb + call s:SendCommand('show inferior-tty') + endif + call s:SendCommand('set print pretty on') + call s:SendCommand('set breakpoint pending on') + " Disable pagination, it causes everything to stop at the gdb + call s:SendCommand('set pagination off') + + " Set arguments to be run + if len(proc_args) + call s:SendCommand('set args ' . join(proc_args)) + endif + + call s:StartDebugCommon(a:dict) + startinsert +endfunc + +func s:StartDebugCommon(dict) " Sign used to highlight the line where the program has stopped. " There can be only one. sign define debugPC linehl=debugPC @@ -180,7 +330,7 @@ func s:StartDebug_internal(dict) sign define debugBreakpoint text=>> texthl=debugBreakpoint " Install debugger commands in the text window. - call win_gotoid(s:startwin) + call win_gotoid(s:sourcewin) call s:InstallCommands() call win_gotoid(s:gdbwin) @@ -202,27 +352,130 @@ func s:StartDebug_internal(dict) au BufUnload * call s:BufUnloaded() augroup END - " Run the command if the bang attribute was given - " and got to the window + " Run the command if the bang attribute was given and got to the debug + " window. if get(a:dict, 'bang', 0) call s:SendCommand('-exec-run') call win_gotoid(s:ptywin) endif - endfunc -func s:EndDebug(job, status) - exe 'bwipe! ' . s:ptybuf +" Send a command to gdb. "cmd" is the string without line terminator. +func s:SendCommand(cmd) + call ch_log('sending to gdb: ' . a:cmd) + if s:way == 'prompt' + call ch_sendraw(s:gdb_channel, a:cmd . "\n") + else + call term_sendkeys(s:commbuf, a:cmd . "\r") + endif +endfunc + +" This is global so that a user can create their mappings with this. +func TermDebugSendCommand(cmd) + if s:way == 'prompt' + call ch_sendraw(s:gdb_channel, a:cmd . "\n") + else + let do_continue = 0 + if !s:stopped + let do_continue = 1 + call s:SendCommand('-exec-interrupt') + sleep 10m + endif + call term_sendkeys(s:gdbbuf, a:cmd . "\r") + if do_continue + Continue + endif + endif +endfunc + +" Function called when entering a line in the prompt buffer. +func s:PromptCallback(text) + call s:SendCommand(a:text) +endfunc + +" Function called when pressing CTRL-C in the prompt buffer. +func s:PromptInterrupt() + call ch_log('Interrupting gdb') + call job_stop(s:gdbjob, 'int') +endfunc + +" Function called when gdb outputs text. +func s:GdbOutCallback(channel, text) + call ch_log('received from gdb: ' . a:text) + + " Drop the gdb prompt, we have our own. + " Drop status and echo'd commands. + if a:text == '(gdb) ' || a:text == '^done' || a:text[0] == '&' || a:text[0] == '=' + return + endif + if a:text =~ '^^error,msg=' + let text = s:DecodeMessage(a:text[11:]) + if exists('s:evalexpr') && text =~ 'A syntax error in expression, near\|No symbol .* in current context' + " Silently drop evaluation errors. + unlet s:evalexpr + return + endif + elseif a:text[0] == '~' + let text = s:DecodeMessage(a:text[1:]) + else + call s:CommOutput(a:channel, a:text) + return + endif + + let curwinid = win_getid(winnr()) + call win_gotoid(s:gdbwin) + + " Add the output above the current prompt. + call append(line('$') - 1, text) + set nomodified + + call win_gotoid(curwinid) +endfunc + +" Decode a message from gdb. quotedText starts with a ", return the text up +" to the next ", unescaping characters. +func s:DecodeMessage(quotedText) + if a:quotedText[0] != '"' + echoerr 'DecodeMessage(): missing quote' + return + endif + let result = '' + let i = 1 + while a:quotedText[i] != '"' && i < len(a:quotedText) + if a:quotedText[i] == '\' + let i += 1 + if a:quotedText[i] == 'n' + " drop \n + let i += 1 + continue + endif + endif + let result .= a:quotedText[i] + let i += 1 + endwhile + return result +endfunc + +func s:EndTermDebug(job, status) exe 'bwipe! ' . s:commbuf unlet s:gdbwin + call s:EndDebugCommon() +endfunc + +func s:EndDebugCommon() let curwinid = win_getid(winnr()) - call win_gotoid(s:startwin) + if exists('s:ptybuf') && s:ptybuf + exe 'bwipe! ' . s:ptybuf + endif + + call win_gotoid(s:sourcewin) let &signcolumn = s:startsigncolumn call s:DeleteCommands() call win_gotoid(curwinid) + if s:save_columns > 0 let &columns = s:save_columns endif @@ -240,6 +493,19 @@ func s:EndDebug(job, status) au! TermDebug endfunc +func s:EndPromptDebug(job, status) + let curwinid = win_getid(winnr()) + call win_gotoid(s:gdbwin) + close + if curwinid != s:gdbwin + call win_gotoid(curwinid) + endif + + call s:EndDebugCommon() + unlet s:gdbwin + call ch_log("Returning from EndPromptDebug()") +endfunc + " Handle a message received from gdb on the GDB/MI interface. func s:CommOutput(chan, msg) let msgs = split(a:msg, "\r") @@ -275,11 +541,18 @@ func s:InstallCommands() command -nargs=* Run call s:Run() command -nargs=* Arguments call s:SendCommand('-exec-arguments ' . ) command Stop call s:SendCommand('-exec-interrupt') - command Continue call s:SendCommand('-exec-continue') + + " using -exec-continue results in CTRL-C in gdb window not working + if s:way == 'prompt' + command Continue call s:SendCommand('continue') + else + command Continue call term_sendkeys(s:gdbbuf, "continue\r") + endif + command -range -nargs=* Evaluate call s:Evaluate(, ) command Gdb call win_gotoid(s:gdbwin) command Program call win_gotoid(s:ptywin) - command Source call s:GotoStartwinOrCreateIt() + command Source call s:GotoSourcewinOrCreateIt() command Winbar call s:InstallWinbar() " TODO: can the K mapping be restored? @@ -375,7 +648,13 @@ func s:SetBreakpoint() let do_continue = 0 if !s:stopped let do_continue = 1 - call s:SendCommand('-exec-interrupt') + if s:way == 'prompt' + " Need to send a signal to get the UI to listen. Strangely this is only + " needed once. + call job_stop(s:gdbjob, 'int') + else + call s:SendCommand('-exec-interrupt') + endif sleep 10m endif call s:SendCommand('-break-insert --source ' @@ -391,7 +670,7 @@ func s:ClearBreakpoint() let lnum = line('.') for [key, val] in items(s:breakpoints) if val['fname'] == fname && val['lnum'] == lnum - call term_sendkeys(s:commbuf, '-break-delete ' . key . "\r") + call s:SendCommand('-break-delete ' . key) " Assume this always wors, the reply is simply "^done". exe 'sign unplace ' . (s:break_id + key) unlet s:breakpoints[key] @@ -400,11 +679,6 @@ func s:ClearBreakpoint() endfor endfunc -" :Next, :Continue, etc - send a command to gdb -func s:SendCommand(cmd) - call term_sendkeys(s:commbuf, a:cmd . "\r") -endfunc - func s:Run(args) if a:args != '' call s:SendCommand('-exec-arguments ' . a:args) @@ -466,7 +740,12 @@ endfunc " Show a balloon with information of the variable under the mouse pointer, " if there is any. func TermDebugBalloonExpr() - if v:beval_winid != s:startwin + if v:beval_winid != s:sourcewin + return + endif + if !s:stopped + " Only evaluate when stopped, otherwise setting a breakpoint using the + " mouse triggers a balloon. return endif let s:evalFromBalloonExpr = 1 @@ -487,10 +766,10 @@ func s:HandleError(msg) echoerr substitute(a:msg, '.*msg="\(.*\)"', '\1', '') endfunc -func s:GotoStartwinOrCreateIt() - if !win_gotoid(s:startwin) +func s:GotoSourcewinOrCreateIt() + if !win_gotoid(s:sourcewin) new - let s:startwin = win_getid(winnr()) + let s:sourcewin = win_getid(winnr()) call s:InstallWinbar() endif endfunc @@ -506,7 +785,7 @@ func s:HandleCursor(msg) let s:stopped = 0 endif - call s:GotoStartwinOrCreateIt() + call s:GotoSourcewinOrCreateIt() let fname = substitute(a:msg, '.*fullname="\([^"]*\)".*', '\1', '') if a:msg =~ '^\(\*stopped\|=thread-selected\)' && filereadable(fname) @@ -516,7 +795,7 @@ func s:HandleCursor(msg) if &modified " TODO: find existing window exe 'split ' . fnameescape(fname) - let s:startwin = win_getid(winnr()) + let s:sourcewin = win_getid(winnr()) call s:InstallWinbar() else exe 'edit ' . fnameescape(fname) diff --git a/src/version.c b/src/version.c index 6a294f7811..366e845bf9 100644 --- a/src/version.c +++ b/src/version.c @@ -761,6 +761,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 71, /**/ 70, /**/ From dcdeaaf1505b96aa7a31ccd4becc92c32119bdda Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 17 Jun 2018 22:19:12 +0200 Subject: [PATCH 19/19] patch 8.1.0072: use of 'termwinkey' is inconsistent Problem: Use of 'termwinkey' is inconsistent. Solution: Change the documentation and the behavior. (Ken Takata) --- runtime/doc/terminal.txt | 3 ++- src/terminal.c | 11 ++++++++--- src/version.c | 2 ++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/runtime/doc/terminal.txt b/runtime/doc/terminal.txt index 8f95fc227c..a6c40f6ef1 100644 --- a/runtime/doc/terminal.txt +++ b/runtime/doc/terminal.txt @@ -87,7 +87,8 @@ to the job. For example: 'termwinkey' CTRL-W move focus to the next window 'termwinkey' : enter an Ex command 'termwinkey' 'termwinkey' send 'termwinkey' to the job in the terminal - 'termwinkey' . send a CTRL-W to the job in the terminal + 'termwinkey' . send 'termwinkey' to the job in the terminal + 'termwinkey' CTRL-\ send a CTRL-\ to the job in the terminal 'termwinkey' N go to terminal Normal mode, see below 'termwinkey' CTRL-N same as CTRL-W N 'termwinkey' CTRL-C same as |t_CTRL-W_CTRL-C| diff --git a/src/terminal.c b/src/terminal.c index 9b7bc038d2..f4fa551659 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -2107,7 +2107,11 @@ terminal_loop(int blocking) in_terminal_loop = curbuf->b_term; if (*curwin->w_p_twk != NUL) + { termwinkey = string_to_key(curwin->w_p_twk, TRUE); + if (termwinkey == Ctrl_W) + termwinkey = 0; + } position_cursor(curwin, &curbuf->b_term->tl_cursor_pos); may_set_cursor_props(curbuf->b_term); @@ -2203,12 +2207,13 @@ terminal_loop(int blocking) /* "CTRL-W CTRL-C" or 'termwinkey' CTRL-C: end the job */ mch_signal_job(curbuf->b_term->tl_job, (char_u *)"kill"); } - else if (termwinkey == 0 && c == '.') + else if (c == '.') { /* "CTRL-W .": send CTRL-W to the job */ - c = Ctrl_W; + /* "'termwinkey' .": send 'termwinkey' to the job */ + c = termwinkey == 0 ? Ctrl_W : termwinkey; } - else if (termwinkey == 0 && c == Ctrl_BSL) + else if (c == Ctrl_BSL) { /* "CTRL-W CTRL-\": send CTRL-\ to the job */ c = Ctrl_BSL; diff --git a/src/version.c b/src/version.c index 366e845bf9..6ce67802d7 100644 --- a/src/version.c +++ b/src/version.c @@ -761,6 +761,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 72, /**/ 71, /**/