From ce1c32780a7d0ae5110eab627fcbfd4a11e5eb52 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 20 Aug 2017 15:05:15 +0200 Subject: [PATCH 01/11] patch 8.0.0973: initial info about blinking cursor is wrong Problem: initial info about blinking cursor is wrong Solution: Invert the blink flag. Add t_VS to stop a blinking cursor. --- src/option.c | 15 ++++++++------- src/proto/term.pro | 1 - src/term.c | 47 +++++++++++++++++++++++----------------------- src/term.h | 6 ++++-- src/terminal.c | 4 ---- src/version.c | 2 ++ 6 files changed, 37 insertions(+), 38 deletions(-) diff --git a/src/option.c b/src/option.c index a65149785a..48e12736d4 100644 --- a/src/option.c +++ b/src/option.c @@ -3157,6 +3157,8 @@ static struct vimoption options[] = p_term("t_AL", T_CAL) p_term("t_al", T_AL) p_term("t_bc", T_BC) + p_term("t_BE", T_BE) + p_term("t_BD", T_BD) p_term("t_cd", T_CD) p_term("t_ce", T_CE) p_term("t_cl", T_CL) @@ -3173,13 +3175,11 @@ static struct vimoption options[] = p_term("t_db", T_DB) p_term("t_DL", T_CDL) p_term("t_dl", T_DL) + p_term("t_EC", T_CEC) p_term("t_EI", T_CEI) p_term("t_fs", T_FS) + p_term("t_GP", T_CGP) p_term("t_IE", T_CIE) - p_term("t_SC", T_CSC) - p_term("t_EC", T_CEC) - p_term("t_SH", T_CSH) - p_term("t_RS", T_CRS) p_term("t_IS", T_CIS) p_term("t_ke", T_KE) p_term("t_ks", T_KS) @@ -3193,10 +3193,13 @@ static struct vimoption options[] = p_term("t_op", T_OP) p_term("t_RB", T_RBG) p_term("t_RI", T_CRI) + p_term("t_RS", T_CRS) p_term("t_RV", T_CRV) p_term("t_Sb", T_CSB) + p_term("t_SC", T_CSC) p_term("t_se", T_SE) p_term("t_Sf", T_CSF) + p_term("t_SH", T_CSH) p_term("t_SI", T_CSI) p_term("t_so", T_SO) p_term("t_SR", T_CSR) @@ -3211,9 +3214,9 @@ static struct vimoption options[] = p_term("t_vb", T_VB) p_term("t_ve", T_VE) p_term("t_vi", T_VI) + p_term("t_VS", T_CVS) p_term("t_vs", T_VS) p_term("t_WP", T_CWP) - p_term("t_GP", T_CGP) p_term("t_WS", T_CWS) p_term("t_xn", T_XN) p_term("t_xs", T_XS) @@ -3221,8 +3224,6 @@ static struct vimoption options[] = p_term("t_ZR", T_CZR) p_term("t_8f", T_8F) p_term("t_8b", T_8B) - p_term("t_BE", T_BE) - p_term("t_BD", T_BD) /* terminal key codes are not in here */ diff --git a/src/proto/term.pro b/src/proto/term.pro index 63e6448905..392b067334 100644 --- a/src/proto/term.pro +++ b/src/proto/term.pro @@ -53,7 +53,6 @@ void cursor_on(void); void cursor_off(void); void term_cursor_mode(int forced); void term_cursor_color(char_u *color); -void term_cursor_blink(int blink); void term_cursor_shape(int shape, int blink); void scroll_region_set(win_T *wp, int off); void scroll_region_reset(void); diff --git a/src/term.c b/src/term.c index 44b196febf..6de45224c3 100644 --- a/src/term.c +++ b/src/term.c @@ -828,17 +828,13 @@ static struct builtin_term builtin_termcaps[] = {(int)KS_LE, "\b"}, {(int)KS_VI, IF_EB("\033[?25l", ESC_STR "[?25l")}, {(int)KS_VE, IF_EB("\033[?25h", ESC_STR "[?25h")}, -#if 0 - /* This is currently disabled, because we cannot reliably restore the - * cursor style because of what appears to be an xterm bug. */ - {(int)KS_VE, IF_EB("\033[?25h\033[?12l", ESC_STR "[?25h" ESC_STR "[?12l")}, {(int)KS_VS, IF_EB("\033[?12h", ESC_STR "[?12h")}, + {(int)KS_CVS, IF_EB("\033[?12l", ESC_STR "[?12l")}, # ifdef TERMINFO {(int)KS_CSH, IF_EB("\033[%p1%d q", ESC_STR "[%p1%d q")}, # else {(int)KS_CSH, IF_EB("\033[%d q", ESC_STR "[%d q")}, # endif -#endif {(int)KS_CRS, IF_EB("\033P$q q\033\\", ESC_STR "P$q q" ESC_STR "\\")}, # ifdef TERMINFO {(int)KS_CM, IF_EB("\033[%i%p1%d;%p2%dH", @@ -1585,7 +1581,7 @@ set_termname(char_u *term) {KS_DL, "dl"}, {KS_CDL,"DL"}, {KS_CS, "cs"}, {KS_CL, "cl"}, {KS_CD, "cd"}, {KS_VI, "vi"}, {KS_VE, "ve"}, {KS_MB, "mb"}, - {KS_VS, "vs"}, {KS_ME, "me"}, {KS_MR, "mr"}, + {KS_ME, "me"}, {KS_MR, "mr"}, {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"}, @@ -1595,6 +1591,7 @@ set_termname(char_u *term) {KS_BC, "bc"}, {KS_CSB,"Sb"}, {KS_CSF,"Sf"}, {KS_CAB,"AB"}, {KS_CAF,"AF"}, {KS_LE, "le"}, {KS_ND, "nd"}, {KS_OP, "op"}, {KS_CRV, "RV"}, + {KS_VS, "vs"}, {KS_CVS, "VS"}, {KS_CIS, "IS"}, {KS_CIE, "IE"}, {KS_CSC, "SC"}, {KS_CEC, "EC"}, {KS_TS, "ts"}, {KS_FS, "fs"}, @@ -3665,11 +3662,11 @@ mouse_model_popup(void) void scroll_start(void) { - if (*T_VS != NUL) + if (*T_VS != NUL && *T_CVS != NUL) { out_str(T_VS); - out_str(T_VE); - screen_start(); /* don't know where cursor is now */ + out_str(T_CVS); + screen_start(); /* don't know where cursor is now */ } } @@ -3694,10 +3691,9 @@ cursor_on(void) void cursor_off(void) { - if (full_screen) + if (full_screen && !cursor_is_off) { - if (!cursor_is_off) - out_str(T_VI); /* disable cursor */ + out_str(T_VI); /* disable cursor */ cursor_is_off = TRUE; } } @@ -3766,20 +3762,10 @@ term_cursor_color(char_u *color) out_flush(); } } - - void -term_cursor_blink(int blink) -{ - if (blink) - out_str(T_VS); - else - out_str(T_VE); - out_flush(); -} # endif /* - * "shape" == 1: block, "shape" == 2: underline, "shape" == 3: vertical bar + * "shape": 1 = block, 2 = underline, 3 = vertical bar */ void term_cursor_shape(int shape, int blink) @@ -3789,6 +3775,17 @@ term_cursor_shape(int shape, int blink) OUT_STR(tgoto((char *)T_CSH, 0, shape * 2 - blink)); out_flush(); } + /* When t_SH is not set try setting just the blink state. */ + else if (blink && *T_VS != NUL) + { + out_str(T_VS); + out_flush(); + } + else if (!blink && *T_CVS != NUL) + { + out_str(T_CVS); + out_flush(); + } } #endif @@ -4693,7 +4690,9 @@ check_termcode( * 5 = vertical bar blink, 6 = vertical bar */ number = number == 0 ? 1 : number; initial_cursor_shape = (number + 1) / 2; - initial_cursor_blink = (number & 1) ? TRUE : FALSE; + /* The blink flag is actually inverted, compared to + * the value set with T_SH. */ + initial_cursor_blink = (number & 1) ? FALSE : TRUE; rcm_status = STATUS_GOT; LOG_TR("Received cursor shape response"); diff --git a/src/term.h b/src/term.h index 00e3c96aa2..18c1294afa 100644 --- a/src/term.h +++ b/src/term.h @@ -39,7 +39,8 @@ enum SpecialKey KS_DB, /* text may be scrolled up from down */ KS_VI, /* cursor invisible */ KS_VE, /* cursor visible */ - KS_VS, /* cursor very visible */ + KS_VS, /* cursor very visible (blink) */ + KS_CVS, /* cursor normally visible (no blink) */ KS_CSH, /* cursor shape */ KS_CRS, /* request cursor shape */ KS_ME, /* normal mode */ @@ -131,7 +132,8 @@ extern char_u *(term_strings[]); /* current terminal strings */ #define T_DB (TERM_STR(KS_DB)) /* text may be scrolled up from down */ #define T_VI (TERM_STR(KS_VI)) /* cursor invisible */ #define T_VE (TERM_STR(KS_VE)) /* cursor visible */ -#define T_VS (TERM_STR(KS_VS)) /* cursor very visible */ +#define T_VS (TERM_STR(KS_VS)) /* cursor very visible (blink) */ +#define T_CVS (TERM_STR(KS_CVS)) /* cursor normally visible (no blink) */ #define T_CSH (TERM_STR(KS_CSH)) /* cursor shape */ #define T_CRS (TERM_STR(KS_CRS)) /* request cursor shape */ #define T_ME (TERM_STR(KS_ME)) /* normal mode */ diff --git a/src/terminal.c b/src/terminal.c index bb2dba90cd..08e0f9b938 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -38,7 +38,6 @@ * in tl_scrollback are no longer used. * * TODO: - * - help index for winptydll, optwin entry for winptydll * - make [range]terminal pipe [range] lines to the terminal * - implement term_setsize() * - add test for giving error for invalid 'termsize' value. @@ -1271,8 +1270,6 @@ may_set_cursor_props(term_T *term) term_cursor_color(term->tl_cursor_color); else term_cursor_color((char_u *)""); - /* do both blink and shape+blink, in case setting shape does not work */ - term_cursor_blink(term->tl_cursor_blink); term_cursor_shape(term->tl_cursor_shape, term->tl_cursor_blink); } } @@ -1288,7 +1285,6 @@ may_restore_cursor_props(void) { did_change_cursor = FALSE; term_cursor_color((char_u *)""); - term_cursor_blink(FALSE); /* this will restore the initial cursor style, if possible */ ui_cursor_shape_forced(TRUE); } diff --git a/src/version.c b/src/version.c index cf72cb884e..931681567c 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 */ +/**/ + 973, /**/ 972, /**/ From 8efa026a25b95de5598535ef62505282a8584a4b Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 20 Aug 2017 15:47:20 +0200 Subject: [PATCH 02/11] patch 8.0.0974: resetting a string option does not trigger OptionSet Problem: Resetting a string option does not trigger OptionSet. (Rick Howe) Solution: Set the origval. --- src/option.c | 69 ++++++++++++++++++------------------ src/testdir/test_autocmd.vim | 13 +++++++ src/version.c | 2 ++ 3 files changed, 50 insertions(+), 34 deletions(-) diff --git a/src/option.c b/src/option.c index 48e12736d4..48106411f3 100644 --- a/src/option.c +++ b/src/option.c @@ -4351,8 +4351,6 @@ trigger_optionsset_string( (char_u *)options[opt_idx].fullname, NULL, FALSE, NULL); reset_v_option_vars(); } - vim_free(oldval); - vim_free(newval); } #endif @@ -4818,19 +4816,19 @@ do_set( } else if (opt_idx >= 0) /* string */ { - char_u *save_arg = NULL; - char_u *s = NULL; - char_u *oldval = NULL; /* previous value if *varp */ - char_u *newval; - char_u *origval = NULL; + char_u *save_arg = NULL; + char_u *s = NULL; + char_u *oldval = NULL; /* previous value if *varp */ + char_u *newval; + char_u *origval = NULL; #if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL) - char_u *saved_origval = NULL; - char_u *saved_newval = NULL; + char_u *saved_origval = NULL; + char_u *saved_newval = NULL; #endif - unsigned newlen; - int comma; - int bs; - int new_value_alloced; /* new string option + unsigned newlen; + int comma; + int bs; + int new_value_alloced; /* new string option was allocated */ /* When using ":set opt=val" for a global option @@ -4843,6 +4841,16 @@ do_set( /* The old value is kept until we are sure that the * new value is valid. */ oldval = *(char_u **)varp; + + /* When setting the local value of a global + * option, the old value may be the global value. */ + if (((int)options[opt_idx].indir & PV_BOTH) + && (opt_flags & OPT_LOCAL)) + origval = *(char_u **)get_varp( + &options[opt_idx]); + else + origval = oldval; + if (nextchar == '&') /* set to default val */ { newval = options[opt_idx].def_val[ @@ -4957,15 +4965,6 @@ do_set( ++arg; } - /* When setting the local value of a global - * option, the old value may be the global value. */ - if (((int)options[opt_idx].indir & PV_BOTH) - && (opt_flags & OPT_LOCAL)) - origval = *(char_u **)get_varp( - &options[opt_idx]); - else - origval = oldval; - /* * Copy the new string into allocated memory. * Can't use set_string_option_direct(), because @@ -5169,7 +5168,9 @@ do_set( new_value_alloced = TRUE; } - /* Set the new value. */ + /* + * Set the new value. + */ *(char_u **)(varp) = newval; #if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL) @@ -5195,19 +5196,16 @@ do_set( errmsg = did_set_string_option(opt_idx, (char_u **)varp, new_value_alloced, oldval, errbuf, opt_flags); +#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL) + if (errmsg == NULL) + trigger_optionsset_string(opt_idx, opt_flags, + saved_origval, saved_newval); + vim_free(saved_origval); + vim_free(saved_newval); +#endif /* If error detected, print the error message. */ if (errmsg != NULL) - { -#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL) - vim_free(saved_origval); - vim_free(saved_newval); -#endif goto skip; - } -#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL) - trigger_optionsset_string(opt_idx, opt_flags, - saved_origval, saved_newval); -#endif } else /* key code option */ { @@ -6014,8 +6012,11 @@ set_string_option( #if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL) /* call autocommand after handling side effects */ - trigger_optionsset_string(opt_idx, opt_flags, + if (r == NULL) + trigger_optionsset_string(opt_idx, opt_flags, saved_oldval, saved_newval); + vim_free(saved_oldval); + vim_free(saved_newval); #endif } return r; diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim index dede9fa607..e9f407620e 100644 --- a/src/testdir/test_autocmd.vim +++ b/src/testdir/test_autocmd.vim @@ -548,6 +548,19 @@ func Test_OptionSet() call assert_equal([['key', 'invalid', 'invalid1', 'invalid']], g:options) call assert_equal(g:opt[0], g:opt[1]) + " 18: Setting string option" + let oldval = &tags + let g:options=[['tags', oldval, 'tagpath', 'global']] + set tags=tagpath + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + + " 1l: Resetting string option" + let g:options=[['tags', 'tagpath', oldval, 'global']] + set tags& + call assert_equal([], g:options) + call assert_equal(g:opt[0], g:opt[1]) + " Cleanup au! OptionSet for opt in ['nu', 'ai', 'acd', 'ar', 'bs', 'backup', 'cul', 'cp'] diff --git a/src/version.c b/src/version.c index 931681567c..d5df161533 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 */ +/**/ + 974, /**/ 973, /**/ From edbc0d46cffe1766d0b330dc2842212cff644f8e Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 20 Aug 2017 16:11:51 +0200 Subject: [PATCH 03/11] patch 8.0.0975: using freed memory when setting 'backspace' Problem: Using freed memory when setting 'backspace'. Solution: When changing oldval also change origval. --- src/option.c | 2 ++ src/version.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/option.c b/src/option.c index 48106411f3..61d3579834 100644 --- a/src/option.c +++ b/src/option.c @@ -4927,6 +4927,8 @@ do_set( break; } vim_free(oldval); + if (origval == oldval) + origval = *(char_u **)varp; oldval = *(char_u **)varp; } /* diff --git a/src/version.c b/src/version.c index d5df161533..36af209685 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 */ +/**/ + 975, /**/ 974, /**/ From b241208a13d3e9def36d749b1e824ae694aa85f8 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 20 Aug 2017 18:09:14 +0200 Subject: [PATCH 04/11] patch 8.0.0976: cannot send lines to a terminal job Problem: Cannot send lines to a terminal job. Solution: Make [range]terminal send selected lines to the job. Use ++rows and ++cols for the terminal size. --- runtime/doc/terminal.txt | 13 +++--- src/ex_cmds.h | 4 +- src/os_unix.c | 14 ++++-- src/terminal.c | 83 ++++++++++++++++++++++++++++------- src/testdir/test_terminal.vim | 8 ++-- src/version.c | 2 + 6 files changed, 93 insertions(+), 31 deletions(-) diff --git a/runtime/doc/terminal.txt b/runtime/doc/terminal.txt index 1f23deb785..c7c3f856a6 100644 --- a/runtime/doc/terminal.txt +++ b/runtime/doc/terminal.txt @@ -1,4 +1,4 @@ -*terminal.txt* For Vim version 8.0. Last change: 2017 Aug 12 +*terminal.txt* For Vim version 8.0. Last change: 2017 Aug 20 VIM REFERENCE MANUAL by Bram Moolenaar @@ -102,10 +102,9 @@ Syntax ~ parentheses. E.g. if "gdb" exists the second terminal buffer will use "!gdb (1)". - If [range] is given it is used for the terminal size. - One number specifies the number of rows. Unless the - "vertical" modifier is used, then it is the number of - columns. + If [range] is given the specified lines are used as + input for the job. It will not be possible to type + keys in the terminal window. Two comma separated numbers are used as "rows,cols". E.g. `:24,80gdb` opens a terminal with 24 rows and 80 @@ -125,6 +124,10 @@ Syntax ~ cannot be |abandon|ed. ++hidden Open the terminal in a hidden buffer, no window will be used. + ++rows={height} Use {height} for the terminal window + height. + ++cols={width} Use {width} for the terminal window + width. If you want to use more options use the |term_start()| function. diff --git a/src/ex_cmds.h b/src/ex_cmds.h index 6fb528d582..161ba1d117 100644 --- a/src/ex_cmds.h +++ b/src/ex_cmds.h @@ -1484,8 +1484,8 @@ EX(CMD_tearoff, "tearoff", ex_tearoff, NEEDARG|EXTRA|TRLBAR|NOTRLCOM|CMDWIN, ADDR_LINES), EX(CMD_terminal, "terminal", ex_terminal, - RANGE|NOTADR|BANG|FILES|TRLBAR|CMDWIN, - ADDR_OTHER), + RANGE|BANG|FILES|TRLBAR|CMDWIN, + ADDR_LINES), EX(CMD_tfirst, "tfirst", ex_tag, RANGE|NOTADR|BANG|TRLBAR|ZEROR, ADDR_LINES), diff --git a/src/os_unix.c b/src/os_unix.c index 40e0762ead..57b0dcdd9a 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -5238,6 +5238,7 @@ mch_job_start(char **argv, job_T *job, jobopt_T *options) int use_file_for_in = options->jo_io[PART_IN] == JIO_FILE; int use_file_for_out = options->jo_io[PART_OUT] == JIO_FILE; int use_file_for_err = options->jo_io[PART_ERR] == JIO_FILE; + int use_buffer_for_in = options->jo_io[PART_IN] == JIO_BUFFER; int use_out_for_err = options->jo_io[PART_ERR] == JIO_OUT; SIGSET_DECL(curset) @@ -5247,7 +5248,10 @@ mch_job_start(char **argv, job_T *job, jobopt_T *options) /* default is to fail */ job->jv_status = JOB_FAILED; - if (options->jo_pty) + if (options->jo_pty + && (!(use_file_for_in || use_null_for_in) + || !(use_file_for_in || use_null_for_out) + || !(use_out_for_err || use_file_for_err || use_null_for_err))) open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_name); /* TODO: without the channel feature connect the child to /dev/null? */ @@ -5263,8 +5267,12 @@ mch_job_start(char **argv, job_T *job, jobopt_T *options) goto failed; } } - else if (!use_null_for_in && pty_master_fd < 0 && pipe(fd_in) < 0) - goto failed; + else + /* When writing buffer lines to the input don't use the pty, so that + * the pipe can be closed when all lines were written. */ + if (!use_null_for_in && (pty_master_fd < 0 || use_buffer_for_in) + && pipe(fd_in) < 0) + goto failed; if (use_file_for_out) { diff --git a/src/terminal.c b/src/terminal.c index 08e0f9b938..344622a219 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -38,7 +38,7 @@ * in tl_scrollback are no longer used. * * TODO: - * - make [range]terminal pipe [range] lines to the terminal + * - test writing lines to terminal job when implemented for MS-Windows * - implement term_setsize() * - add test for giving error for invalid 'termsize' value. * - support minimal size when 'termsize' is "rows*cols". @@ -447,10 +447,14 @@ ex_terminal(exarg_T *eap) cmd = eap->arg; while (*cmd && *cmd == '+' && *(cmd + 1) == '+') { - char_u *p; + char_u *p, *ep; cmd += 2; p = skiptowhite(cmd); + ep = vim_strchr(cmd, '='); + if (ep != NULL && ep < p) + p = ep; + if ((int)(p - cmd) == 5 && STRNICMP(cmd, "close", 5) == 0) opt.jo_term_finish = 'c'; else if ((int)(p - cmd) == 4 && STRNICMP(cmd, "open", 4) == 0) @@ -459,6 +463,20 @@ ex_terminal(exarg_T *eap) opt.jo_curwin = 1; else if ((int)(p - cmd) == 6 && STRNICMP(cmd, "hidden", 6) == 0) opt.jo_hidden = 1; + else if ((int)(p - cmd) == 4 && STRNICMP(cmd, "rows", 4) == 0 + && ep != NULL && isdigit(ep[1])) + { + opt.jo_set2 |= JO2_TERM_ROWS; + opt.jo_term_rows = atoi((char *)ep + 1); + p = skiptowhite(cmd); + } + else if ((int)(p - cmd) == 4 && STRNICMP(cmd, "cols", 4) == 0 + && ep != NULL && isdigit(ep[1])) + { + opt.jo_set2 |= JO2_TERM_COLS; + opt.jo_term_cols = atoi((char *)ep + 1); + p = skiptowhite(cmd); + } else { if (*p) @@ -472,17 +490,14 @@ ex_terminal(exarg_T *eap) /* Make a copy, an autocommand may set 'shell'. */ tofree = cmd = vim_strsave(p_sh); - if (eap->addr_count == 2) + if (eap->addr_count > 0) { - opt.jo_term_rows = eap->line1; - opt.jo_term_cols = eap->line2; - } - else if (eap->addr_count == 1) - { - if (cmdmod.split & WSP_VERT) - opt.jo_term_cols = eap->line2; - else - opt.jo_term_rows = eap->line2; + /* Write lines from current buffer to the job. */ + opt.jo_set |= JO_IN_IO | JO_IN_BUF | JO_IN_TOP | JO_IN_BOT; + opt.jo_io[PART_IN] = JIO_BUFFER; + opt.jo_io_buf[PART_IN] = curbuf->b_fnum; + opt.jo_in_top = eap->line1; + opt.jo_in_bot = eap->line2; } argvar.v_type = VAR_STRING; @@ -1077,6 +1092,29 @@ term_vgetc() return c; } +/* + * Get the part that is connected to the tty. Normally this is PART_IN, but + * when writing buffer lines to the job it can be another. This makes it + * possible to do "1,5term vim -". + */ + static ch_part_T +get_tty_part(term_T *term) +{ +#ifdef UNIX + ch_part_T parts[3] = {PART_IN, PART_OUT, PART_ERR}; + int i; + + for (i = 0; i < 3; ++i) + { + int fd = term->tl_job->jv_channel->ch_part[parts[i]].ch_fd; + + if (isatty(fd)) + return parts[i]; + } +#endif + return PART_IN; +} + /* * Send keys to terminal. * Return FAIL when the key needs to be handled in Normal mode. @@ -1148,8 +1186,8 @@ send_keys_to_term(term_T *term, int c, int typed) len = term_convert_key(term, c, msg); if (len > 0) /* TODO: if FAIL is returned, stop? */ - channel_send(term->tl_job->jv_channel, PART_IN, - (char_u *)msg, (int)len, NULL); + channel_send(term->tl_job->jv_channel, get_tty_part(term), + (char_u *)msg, (int)len, NULL); return OK; } @@ -1332,7 +1370,8 @@ terminal_loop(void) #ifdef UNIX { - int fd = curbuf->b_term->tl_job->jv_channel->ch_part[PART_IN].ch_fd; + int part = get_tty_part(curbuf->b_term); + int fd = curbuf->b_term->tl_job->jv_channel->ch_part[part].ch_fd; if (isatty(fd)) { @@ -2823,7 +2862,12 @@ dyn_winpty_init(int verbose) * Return OK or FAIL. */ static int -term_and_job_init(term_T *term, int rows, int cols, typval_T *argvar, jobopt_T *opt) +term_and_job_init( + term_T *term, + int rows, + int cols, + typval_T *argvar, + jobopt_T *opt) { WCHAR *p = NULL; channel_T *channel = NULL; @@ -3020,7 +3064,12 @@ terminal_enabled(void) * Return OK or FAIL. */ static int -term_and_job_init(term_T *term, int rows, int cols, typval_T *argvar, jobopt_T *opt) +term_and_job_init( + term_T *term, + int rows, + int cols, + typval_T *argvar, + jobopt_T *opt) { create_vterm(term, rows, cols); diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index e737aead90..a4041d7252 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -251,7 +251,7 @@ endfunc func Test_terminal_size() let cmd = Get_cat_123_cmd() - exe '5terminal ' . cmd + exe 'terminal ++rows=5 ' . cmd let size = term_getsize('') bwipe! call assert_equal(5, size[0]) @@ -262,7 +262,7 @@ func Test_terminal_size() call assert_equal(6, size[0]) vsplit - exe '5,33terminal ' . cmd + exe 'terminal ++rows=5 ++cols=33 ' . cmd let size = term_getsize('') bwipe! call assert_equal([5, 33], size) @@ -272,7 +272,7 @@ func Test_terminal_size() bwipe! call assert_equal([6, 36], size) - exe 'vertical 20terminal ' . cmd + exe 'vertical terminal ++cols=20 ' . cmd let size = term_getsize('') bwipe! call assert_equal(20, size[1]) @@ -283,7 +283,7 @@ func Test_terminal_size() call assert_equal(26, size[1]) split - exe 'vertical 6,20terminal ' . cmd + exe 'vertical terminal ++rows=6 ++cols=20 ' . cmd let size = term_getsize('') bwipe! call assert_equal([6, 20], size) diff --git a/src/version.c b/src/version.c index 36af209685..c191dc77da 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 */ +/**/ + 976, /**/ 975, /**/ From 5983d5024711f078e7261264cb0e7d6e57953968 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 20 Aug 2017 19:22:56 +0200 Subject: [PATCH 05/11] patch 8.0.0977: cannot send lines to a terminal job on MS-Windows Problem: Cannot send lines to a terminal job on MS-Windows. Solution: Set jv_in_buf. Command doesn't get EOF yet though. --- src/terminal.c | 29 ++++++++++++++++++----------- src/version.c | 2 ++ 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/terminal.c b/src/terminal.c index 344622a219..fbc3cf9c98 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -2869,11 +2869,13 @@ term_and_job_init( typval_T *argvar, jobopt_T *opt) { - WCHAR *p = NULL; + WCHAR *cmd_wchar = NULL; channel_T *channel = NULL; job_T *job = NULL; DWORD error; - HANDLE jo = NULL, child_process_handle, child_thread_handle; + HANDLE jo = NULL; + HANDLE child_process_handle; + HANDLE child_thread_handle; void *winpty_err; void *spawn_config = NULL; char buf[MAX_PATH]; @@ -2893,8 +2895,8 @@ term_and_job_init( cmd = ga.ga_data; } - p = enc_to_utf16(cmd, NULL); - if (p == NULL) + cmd_wchar = enc_to_utf16(cmd, NULL); + if (cmd_wchar == NULL) return FAIL; job = job_alloc(); @@ -2919,7 +2921,7 @@ term_and_job_init( WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN | WINPTY_SPAWN_FLAG_EXIT_AFTER_SHUTDOWN, NULL, - p, + cmd_wchar, NULL, NULL, &winpty_err); @@ -2934,20 +2936,25 @@ 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]); + if (!winpty_spawn(term->tl_winpty, spawn_config, &child_process_handle, &child_thread_handle, &error, &winpty_err)) goto failed; channel_set_pipes(channel, - (sock_T) CreateFileW( + (sock_T)CreateFileW( winpty_conin_name(term->tl_winpty), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL), - (sock_T) CreateFileW( + (sock_T)CreateFileW( winpty_conout_name(term->tl_winpty), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL), - (sock_T) CreateFileW( + (sock_T)CreateFileW( winpty_conerr_name(term->tl_winpty), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)); @@ -2964,7 +2971,7 @@ term_and_job_init( } winpty_spawn_config_free(spawn_config); - vim_free(p); + vim_free(cmd_wchar); create_vterm(term, rows, cols); @@ -2987,8 +2994,8 @@ term_and_job_init( failed: if (argvar->v_type == VAR_LIST) vim_free(ga.ga_data); - if (p != NULL) - vim_free(p); + if (cmd_wchar != NULL) + vim_free(cmd_wchar); if (spawn_config != NULL) winpty_spawn_config_free(spawn_config); if (channel != NULL) diff --git a/src/version.c b/src/version.c index c191dc77da..432849f483 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 */ +/**/ + 977, /**/ 976, /**/ From 37819ed54064b949b1f205c9f4084ba32e3db8bc Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 20 Aug 2017 19:33:47 +0200 Subject: [PATCH 06/11] patch 8.0.0978: writing to terminal job is not tested Problem: Writing to terminal job is not tested. Solution: Add a test. --- src/testdir/test_terminal.vim | 23 +++++++++++++++++++++++ src/version.c | 2 ++ 2 files changed, 25 insertions(+) diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index a4041d7252..b3868553e3 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -470,3 +470,26 @@ func Test_terminal_noblock() unlet g:lnum bwipe endfunc + +func Test_terminal_write_stdin() + " Todo: make this work on all systems. + if !has('unix') + return + endif + new + call setline(1, ['one', 'two', 'three']) + %term wc + call WaitFor('getline(1) != ""') + let nrs = split(getline(1)) + 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)) + call assert_equal(['2', '2', '10'], nrs) + bwipe + + bwipe! +endfunc diff --git a/src/version.c b/src/version.c index 432849f483..0488c199d3 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 */ +/**/ + 978, /**/ 977, /**/ From eef0531621c8d4045d669eb815b051d925983df8 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 20 Aug 2017 20:21:23 +0200 Subject: [PATCH 07/11] patch 8.0.0979: terminal noblock test fails on MS-Windows Problem: Terminal noblock test fails on MS-Windows. (Christian Brabandt) Solution: Ignore empty line below "done". --- src/testdir/test_terminal.vim | 11 +++++++++-- src/version.c | 2 ++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index b3868553e3..bdc5655d54 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -458,9 +458,16 @@ func Test_terminal_noblock() call term_sendkeys(g:buf, 'echo ' . repeat(c, 5000) . "\") endfor call term_sendkeys(g:buf, "echo done\") + + " On MS-Windows there is an extra empty line below "done". Find "done" in + " the last-but-one or the last-but-two line. let g:lnum = term_getsize(g:buf)[0] - 1 - call WaitFor('term_getline(g:buf, g:lnum) =~ "done"', 3000) - call assert_match('done', term_getline(g:buf, g:lnum)) + call WaitFor('term_getline(g:buf, g:lnum) =~ "done" || term_getline(g:buf, g:lnum - 1) =~ "done"', 3000) + let line = term_getline(g:buf, g:lnum) + if line !~ 'done' + let line = term_getline(g:buf, g:lnum - 1) + endif + call assert_match('done', line) let g:job = term_getjob(g:buf) call Stop_shell_in_terminal(g:buf) diff --git a/src/version.c b/src/version.c index 0488c199d3..5d97014c01 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 */ +/**/ + 979, /**/ 978, /**/ From b109bb4e1208753cb286b39992b58126d5aa4ce6 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 21 Aug 2017 21:07:29 +0200 Subject: [PATCH 08/11] patch 8.0.0980: Coverity warning for failing to open /dev/null Problem: Coverity warning for failing to open /dev/null. Solution: When /dev/null can't be opened exit the child. --- src/os_unix.c | 8 ++++++++ src/version.c | 2 ++ 2 files changed, 10 insertions(+) diff --git a/src/os_unix.c b/src/os_unix.c index 57b0dcdd9a..de0bb311dc 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -4340,6 +4340,7 @@ mch_call_shell( # define EXEC_FAILED 122 /* Exit code when shell didn't execute. Don't use 127, some shells use that already */ +# define OPEN_NULL_FAILED 123 /* Exit code if /dev/null can't be opened */ char_u *newcmd; pid_t pid; @@ -5369,7 +5370,14 @@ mch_job_start(char **argv, job_T *job, jobopt_T *options) } if (use_null_for_in || use_null_for_out || use_null_for_err) + { null_fd = open("/dev/null", O_RDWR | O_EXTRA, 0); + if (null_fd < 0) + { + perror("opening /dev/null failed"); + _exit(OPEN_NULL_FAILED); + } + } if (pty_slave_fd >= 0) { diff --git a/src/version.c b/src/version.c index 5d97014c01..c8ae29752c 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 */ +/**/ + 980, /**/ 979, /**/ From 0cbba82359ff9f061aa65632cec7b6b57ae6d6e7 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 21 Aug 2017 21:39:28 +0200 Subject: [PATCH 09/11] patch 8.0.0981: cursor in terminal window blinks by default Problem: Cursor in terminal window blinks by default, while in a real xterm it does not blink, unless the -bc argument is used. Solution: Do not use a blinking cursor by default. --- src/terminal.c | 8 +++++++- src/version.c | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/terminal.c b/src/terminal.c index fbc3cf9c98..a2f57a4bcd 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -38,7 +38,7 @@ * in tl_scrollback are no longer used. * * TODO: - * - test writing lines to terminal job when implemented for 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". @@ -2186,6 +2186,7 @@ create_vterm(term_T *term, int rows, int cols) { VTerm *vterm; VTermScreen *screen; + VTermValue value; vterm = vterm_new(rows, cols); term->tl_vterm = vterm; @@ -2210,6 +2211,11 @@ create_vterm(term_T *term, int rows, int cols) /* Allow using alternate screen. */ vterm_screen_enable_altscreen(screen, 1); + + /* We do not want a blinking cursor by default. */ + value.boolean = 0; + vterm_state_set_termprop(vterm_obtain_state(vterm), + VTERM_PROP_CURSORBLINK, &value); } /* diff --git a/src/version.c b/src/version.c index c8ae29752c..25ec8cbfc3 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 */ +/**/ + 981, /**/ 980, /**/ From 740c433c5909e3118dc4a7c42028f8a8b78a353b Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 21 Aug 2017 22:01:27 +0200 Subject: [PATCH 10/11] patch 8.0.0982: cannot use a terminal when 'encoding' is non-utf8 multi-byte Problem: When 'encoding' is set to a multi-byte encoding other than utf-8 the characters from ther terminal are messed up. Solution: Convert displayed text from utf-8 to 'encoding' for MS-Windows. (Yasuhiro Matsumoto, close #2000) --- src/terminal.c | 83 ++++++++++++++++++++++++++++++++++++++++---------- src/version.c | 2 ++ 2 files changed, 69 insertions(+), 16 deletions(-) diff --git a/src/terminal.c b/src/terminal.c index a2f57a4bcd..2cf4525ae4 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -49,8 +49,8 @@ "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 + * "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 * - support ":term NONE" to open a terminal with a pty but not running a job @@ -845,7 +845,26 @@ add_scrollback_line_to_buffer(term_T *term, char_u *text, int len) int empty = (buf->b_ml.ml_flags & ML_EMPTY); linenr_T lnum = buf->b_ml.ml_line_count; - ml_append_buf(term->tl_buffer, lnum, text, len + 1, FALSE); +#ifdef _WIN32 + if (!enc_utf8 && enc_codepage > 0) + { + WCHAR *ret = NULL; + int length = 0; + + MultiByteToWideChar_alloc(CP_UTF8, 0, (char*)text, len + 1, + &ret, &length); + if (ret != NULL) + { + WideCharToMultiByte_alloc(enc_codepage, 0, + ret, length, (char **)&text, &len, 0, 0); + vim_free(ret); + ml_append_buf(term->tl_buffer, lnum, text, len, FALSE); + vim_free(text); + } + } + else +#endif + ml_append_buf(term->tl_buffer, lnum, text, len + 1, FALSE); if (empty) { /* Delete the empty line that was in the empty buffer. */ @@ -936,7 +955,7 @@ move_terminal_to_buffer(term_T *term) int c; for (i = 0; (c = cell.chars[i]) > 0 || i == 0; ++i) - ga.ga_len += mb_char2bytes(c == NUL ? ' ' : c, + ga.ga_len += utf_char2bytes(c == NUL ? ' ' : c, (char_u *)ga.ga_data + ga.ga_len); } } @@ -1468,6 +1487,18 @@ terminal_loop(void) goto theend; } } +# ifdef _WIN32 + if (!enc_utf8 && has_mbyte && c >= 0x80) + { + WCHAR wc; + char_u mb[3]; + + mb[0] = (unsigned)c >> 8; + mb[1] = c; + if (MultiByteToWideChar(GetACP(), 0, (char*)mb, 2, &wc, 1) > 0) + c = wc; + } +# endif if (send_keys_to_term(curbuf->b_term, c, TRUE) != OK) { ret = OK; @@ -1627,7 +1658,7 @@ color2index(VTermColor *color, int fg, int *boldp) /* 216-color cube */ return 17 + ((red + 25) / 0x33) * 36 - + ((green + 25) / 0x33) * 6 + + ((green + 25) / 0x33) * 6 + (blue + 25) / 0x33; } return 0; @@ -2076,20 +2107,39 @@ term_update_window(win_T *wp) else { #if defined(FEAT_MBYTE) - if (enc_utf8 && c >= 0x80) + if (enc_utf8) { - ScreenLines[off] = ' '; - ScreenLinesUC[off] = c; - } - else - { - ScreenLines[off] = c; - if (enc_utf8) + if (c >= 0x80) + { + ScreenLines[off] = ' '; + ScreenLinesUC[off] = c; + } + else + { + ScreenLines[off] = c; ScreenLinesUC[off] = NUL; + } } -#else - ScreenLines[off] = c; +# ifdef _WIN32 + else if (has_mbyte && c >= 0x80) + { + char_u mb[MB_MAXBYTES+1]; + WCHAR wc = c; + + if (WideCharToMultiByte(GetACP(), 0, &wc, 1, + (char*)mb, 2, 0, 0) > 1) + { + ScreenLines[off] = mb[0]; + ScreenLines[off+1] = mb[1]; + cell.width = mb_ptr2cells(mb); + } + else + ScreenLines[off] = c; + } +# endif + else #endif + ScreenLines[off] = c; } ScreenAttrs[off] = cell2attr(cell.attrs, cell.fg, cell.bg); @@ -2097,11 +2147,12 @@ term_update_window(win_T *wp) ++off; if (cell.width == 2) { - ScreenLines[off] = NUL; #if defined(FEAT_MBYTE) if (enc_utf8) ScreenLinesUC[off] = NUL; + else if (!has_mbyte) #endif + ScreenLines[off] = NUL; ++pos.col; ++off; } diff --git a/src/version.c b/src/version.c index 25ec8cbfc3..ad013a1e4a 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 */ +/**/ + 982, /**/ 981, /**/ From 3f9a1ff141412e9e85f7dff47d02946cb9be9228 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 21 Aug 2017 22:06:02 +0200 Subject: [PATCH 11/11] patch 8.0.0983: unnecessary check for NULL pointer Problem: Unnecessary check for NULL pointer. Solution: Remove the NULL check in dialog_changed(), it already happens in dialog_msg(). (Ken Takata) --- src/ex_cmds2.c | 4 +--- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ex_cmds2.c b/src/ex_cmds2.c index 8ca11f0663..3682e797ab 100644 --- a/src/ex_cmds2.c +++ b/src/ex_cmds2.c @@ -1981,9 +1981,7 @@ dialog_changed( buf_T *buf2; exarg_T ea; - dialog_msg(buff, _("Save changes to \"%s\"?"), - (buf->b_fname != NULL) ? - buf->b_fname : (char_u *)_("Untitled")); + dialog_msg(buff, _("Save changes to \"%s\"?"), buf->b_fname); if (checkall) ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1); else diff --git a/src/version.c b/src/version.c index ad013a1e4a..a5cb078f0d 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 */ +/**/ + 983, /**/ 982, /**/