To: vim_dev@googlegroups.com Subject: Patch 8.0.1609 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Note: this isn't completely finished, but wanted to send it out now. Add the "!" flag to 'guioptions' to try it out. Try: :!cat testdir/color_ramp.txt Report problems if you see them (or send a patch! :-). Patch 8.0.1609 Problem: Shell commands in the GUI use a dumb terminal. Solution: Add the "!" flag to 'guioptions' to execute system commands in a special terminal window. Only for Unix now. Files: src/os_unix.c, src/option.h, src/evalfunc.c, src/terminal.c, src/proto/terminal.pro, src/channel.c, src/proto/channel.pro, src/vim.h, runtime/doc/options.txt *** ../vim-8.0.1608/src/os_unix.c 2018-03-05 21:59:33.214889934 +0100 --- src/os_unix.c 2018-03-16 20:42:01.367637679 +0100 *************** *** 4154,4163 **** return wait_pid; } ! #if defined(FEAT_JOB_CHANNEL) || !defined(USE_SYSTEM) || defined(PROTO) /* * Parse "cmd" and put the white-separated parts in "argv". ! * "argv" is an allocated array with "argc" entries. * Returns FAIL when out of memory. */ int --- 4154,4166 ---- return wait_pid; } ! #if defined(FEAT_JOB_CHANNEL) \ ! || !defined(USE_SYSTEM) \ ! || (defined(FEAT_GUI) && defined(FEAT_TERMINAL)) \ ! || defined(PROTO) /* * Parse "cmd" and put the white-separated parts in "argv". ! * "argv" is an allocated array with "argc" entries and room for 4 more. * Returns FAIL when out of memory. */ int *************** *** 4359,4366 **** # endif } ! int ! mch_call_shell( char_u *cmd, int options) /* SHELL_*, see vim.h */ { --- 4362,4482 ---- # endif } ! #if !defined(USE_SYSTEM) || (defined(FEAT_GUI) && defined(FEAT_TERMINAL)) ! ! static int ! build_argv( ! char_u *cmd, ! char ***argvp, ! char_u **sh_tofree, ! char_u **shcf_tofree) ! { ! char **argv = NULL; ! int argc; ! ! *sh_tofree = vim_strsave(p_sh); ! if (*sh_tofree == NULL) /* out of memory */ ! return FAIL; ! ! if (mch_parse_cmd(*sh_tofree, TRUE, &argv, &argc) == FAIL) ! return FAIL; ! *argvp = argv; ! ! if (cmd != NULL) ! { ! char_u *s; ! char_u *p; ! ! if (extra_shell_arg != NULL) ! argv[argc++] = (char *)extra_shell_arg; ! ! /* Break 'shellcmdflag' into white separated parts. This doesn't ! * handle quoted strings, they are very unlikely to appear. */ ! *shcf_tofree = alloc((unsigned)STRLEN(p_shcf) + 1); ! if (*shcf_tofree == NULL) /* out of memory */ ! return FAIL; ! s = *shcf_tofree; ! p = p_shcf; ! while (*p != NUL) ! { ! argv[argc++] = (char *)s; ! while (*p && *p != ' ' && *p != TAB) ! *s++ = *p++; ! *s++ = NUL; ! p = skipwhite(p); ! } ! ! argv[argc++] = (char *)cmd; ! } ! argv[argc] = NULL; ! return OK; ! } ! #endif ! ! #if defined(FEAT_GUI) && defined(FEAT_TERMINAL) ! /* ! * Use a terminal window to run a shell command in. ! */ ! static int ! mch_call_shell_terminal( ! char_u *cmd, ! int options UNUSED) /* SHELL_*, see vim.h */ ! { ! jobopt_T opt; ! char **argv = NULL; ! char_u *tofree1 = NULL; ! char_u *tofree2 = NULL; ! int retval = -1; ! buf_T *buf; ! aco_save_T aco; ! oparg_T oa; /* operator arguments */ ! ! if (build_argv(cmd, &argv, &tofree1, &tofree2) == FAIL) ! goto theend; ! ! init_job_options(&opt); ! ch_log(NULL, "starting terminal for system command '%s'", cmd); ! buf = term_start(NULL, argv, &opt, TERM_START_SYSTEM); ! ! /* Find a window to make "buf" curbuf. */ ! aucmd_prepbuf(&aco, buf); ! ! clear_oparg(&oa); ! while (term_use_loop()) ! { ! if (oa.op_type == OP_NOP && oa.regname == NUL && !VIsual_active) ! { ! /* If terminal_loop() returns OK we got a key that is handled ! * in Normal model. We don't do redrawing anyway. */ ! if (terminal_loop(TRUE) == OK) ! normal_cmd(&oa, TRUE); ! } ! else ! normal_cmd(&oa, TRUE); ! } ! retval = 0; ! ch_log(NULL, "system command finished"); ! ! /* restore curwin/curbuf and a few other things */ ! aucmd_restbuf(&aco); ! ! wait_return(TRUE); ! do_buffer(DOBUF_WIPE, DOBUF_FIRST, FORWARD, buf->b_fnum, TRUE); ! ! theend: ! vim_free(argv); ! vim_free(tofree1); ! vim_free(tofree2); ! return retval; ! } ! #endif ! ! #ifdef USE_SYSTEM ! /* ! * Use system() to start the shell: simple but slow. ! */ ! static int ! mch_call_shell_system( char_u *cmd, int options) /* SHELL_*, see vim.h */ { *************** *** 4369,4375 **** char *ofn = NULL; #endif int tmode = cur_tmode; - #ifdef USE_SYSTEM /* use system() to start the shell: simple but slow */ char_u *newcmd; /* only needed for unix */ int x; --- 4485,4490 ---- *************** *** 4443,4456 **** restore_clipboard(); # endif return x; ! #else /* USE_SYSTEM */ /* don't use system(), use fork()/exec() */ # 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; pid_t wpid = 0; pid_t wait_pid = 0; --- 4558,4580 ---- restore_clipboard(); # endif return x; + } ! #else /* USE_SYSTEM */ # 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 */ ! /* ! * Don't use system(), use fork()/exec(). ! */ ! static int ! mch_call_shell_fork( ! char_u *cmd, ! int options) /* SHELL_*, see vim.h */ ! { ! int tmode = cur_tmode; pid_t pid; pid_t wpid = 0; pid_t wait_pid = 0; *************** *** 4461,4468 **** # endif int retval = -1; char **argv = NULL; ! int argc; ! char_u *p_shcf_copy = NULL; int i; char_u *p; int pty_master_fd = -1; /* for pty's */ --- 4585,4592 ---- # endif int retval = -1; char **argv = NULL; ! char_u *tofree1 = NULL; ! char_u *tofree2 = NULL; int i; char_u *p; int pty_master_fd = -1; /* for pty's */ *************** *** 4474,4517 **** int pipe_error = FALSE; int did_settmode = FALSE; /* settmode(TMODE_RAW) called */ - newcmd = vim_strsave(p_sh); - if (newcmd == NULL) /* out of memory */ - goto error; - out_flush(); if (options & SHELL_COOKED) settmode(TMODE_COOK); /* set to normal mode */ ! if (mch_parse_cmd(newcmd, TRUE, &argv, &argc) == FAIL) goto error; - if (cmd != NULL) - { - char_u *s; - - if (extra_shell_arg != NULL) - argv[argc++] = (char *)extra_shell_arg; - - /* Break 'shellcmdflag' into white separated parts. This doesn't - * handle quoted strings, they are very unlikely to appear. */ - p_shcf_copy = alloc((unsigned)STRLEN(p_shcf) + 1); - if (p_shcf_copy == NULL) /* out of memory */ - goto error; - s = p_shcf_copy; - p = p_shcf; - while (*p != NUL) - { - argv[argc++] = (char *)s; - while (*p && *p != ' ' && *p != TAB) - *s++ = *p++; - *s++ = NUL; - p = skipwhite(p); - } - - argv[argc++] = (char *)cmd; - } - argv[argc] = NULL; - /* * For the GUI, when writing the output into the buffer and when reading * input from the buffer: Try using a pseudo-tty to get the stdin/stdout --- 4598,4610 ---- int pipe_error = FALSE; int did_settmode = FALSE; /* settmode(TMODE_RAW) called */ out_flush(); if (options & SHELL_COOKED) settmode(TMODE_COOK); /* set to normal mode */ ! if (build_argv(cmd, &argv, &tofree1, &tofree2) == FAIL) goto error; /* * For the GUI, when writing the output into the buffer and when reading * input from the buffer: Try using a pseudo-tty to get the stdin/stdout *************** *** 5319,5326 **** MSG_PUTS(_("\nCommand terminated\n")); } } - vim_free(argv); - vim_free(p_shcf_copy); error: if (!did_settmode) --- 5412,5417 ---- *************** *** 5329,5339 **** # ifdef FEAT_TITLE resettitle(); # endif ! vim_free(newcmd); return retval; ! #endif /* USE_SYSTEM */ } #if defined(FEAT_JOB_CHANNEL) || defined(PROTO) --- 5420,5447 ---- # ifdef FEAT_TITLE resettitle(); # endif ! vim_free(argv); ! vim_free(tofree1); ! vim_free(tofree2); return retval; ! } #endif /* USE_SYSTEM */ + + int + mch_call_shell( + char_u *cmd, + int options) /* SHELL_*, see vim.h */ + { + #if defined(FEAT_GUI) && defined(FEAT_TERMINAL) + if (gui.in_use && vim_strchr(p_go, GO_TERMINAL) != NULL) + return mch_call_shell_terminal(cmd, options); + #endif + #ifdef USE_SYSTEM + return mch_call_shell_system(cmd, options); + #else + return mch_call_shell_fork(cmd, options); + #endif } #if defined(FEAT_JOB_CHANNEL) || defined(PROTO) *** ../vim-8.0.1608/src/option.h 2018-03-09 21:33:29.244607400 +0100 --- src/option.h 2018-03-13 21:25:36.660819811 +0100 *************** *** 214,219 **** --- 214,220 ---- #define SHM_ALL "rmfixlnwaWtToOsAIcqF" /* all possible flags for 'shm' */ /* characters for p_go: */ + #define GO_TERMINAL '!' /* use terminal for system commands */ #define GO_ASEL 'a' /* autoselect */ #define GO_ASELML 'A' /* autoselect modeless selection */ #define GO_BOT 'b' /* use bottom scrollbar */ *************** *** 236,242 **** #define GO_FOOTER 'F' /* add footer */ #define GO_VERTICAL 'v' /* arrange dialog buttons vertically */ #define GO_KEEPWINSIZE 'k' /* keep GUI window size */ ! #define GO_ALL "aAbcefFghilmMprtTvk" /* all possible flags for 'go' */ /* flags for 'comments' option */ #define COM_NEST 'n' /* comments strings nest */ --- 237,243 ---- #define GO_FOOTER 'F' /* add footer */ #define GO_VERTICAL 'v' /* arrange dialog buttons vertically */ #define GO_KEEPWINSIZE 'k' /* keep GUI window size */ ! #define GO_ALL "!aAbcefFghilmMprtTvk" /* all possible flags for 'go' */ /* flags for 'comments' option */ #define COM_NEST 'n' /* comments strings nest */ *** ../vim-8.0.1608/src/evalfunc.c 2018-03-12 22:16:33.261746681 +0100 --- src/evalfunc.c 2018-03-13 21:44:12.065740473 +0100 *************** *** 7032,7038 **** rettv->v_type = VAR_JOB; if (check_restricted() || check_secure()) return; ! rettv->vval.v_job = job_start(argvars, NULL); } /* --- 7032,7038 ---- rettv->v_type = VAR_JOB; if (check_restricted() || check_secure()) return; ! rettv->vval.v_job = job_start(argvars, NULL, NULL); } /* *** ../vim-8.0.1608/src/terminal.c 2018-03-13 13:13:56.715070346 +0100 --- src/terminal.c 2018-03-16 20:40:09.108192020 +0100 *************** *** 38,47 **** * in tl_scrollback are no longer used. * * TODO: ! * - When using 'termguicolors' still use the 16 ANSI colors as-is. Helps for ! * - In the GUI use a terminal emulator for :!cmd. Make the height the same as ! * the window and position it higher up when it gets filled, so it looks like ! * the text scrolls up. * - implement term_setsize() * - Copy text in the vterm to the Vim buffer once in a while, so that * completion works. --- 38,51 ---- * in tl_scrollback are no longer used. * * TODO: ! * - Make terminal close by default when started without a command. Add ! * ++noclose argument. ! * - Win32: In the GUI use a terminal emulator for :!cmd. ! * - Add a way to set the 16 ANSI colors, to be used for 'termguicolors' and in ! * the GUI. ! * - Some way for the job running in the terminal to send a :drop command back ! * to the Vim running the terminal. Should be usable by a simple shell or ! * python script. * - implement term_setsize() * - Copy text in the vterm to the Vim buffer once in a while, so that * completion works. *************** *** 104,109 **** --- 108,117 ---- VTerm *tl_vterm; job_T *tl_job; buf_T *tl_buffer; + #if defined(FEAT_GUI) + int tl_system; /* when non-zero used for :!cmd output */ + int tl_toprow; /* row with first line of system terminal */ + #endif /* Set when setting the size of a vterm, reset after redrawing. */ int tl_vterm_size_changed; *************** *** 175,184 **** /* * Functions with separate implementation for MS-Windows and Unix-like systems. */ ! static int term_and_job_init(term_T *term, typval_T *argvar, jobopt_T *opt); static int create_pty_only(term_T *term, jobopt_T *opt); static void term_report_winsize(term_T *term, int rows, int cols); static void term_free_vterm(term_T *term); /* The character that we know (or assume) that the terminal expects for the * backspace key. */ --- 183,195 ---- /* * Functions with separate implementation for MS-Windows and Unix-like systems. */ ! static int term_and_job_init(term_T *term, typval_T *argvar, char **argv, jobopt_T *opt); static int create_pty_only(term_T *term, jobopt_T *opt); static void term_report_winsize(term_T *term, int rows, int cols); static void term_free_vterm(term_T *term); + #ifdef FEAT_GUI + static void update_system_term(term_T *term); + #endif /* The character that we know (or assume) that the terminal expects for the * backspace key. */ *************** *** 209,214 **** --- 220,235 ---- static void set_term_and_win_size(term_T *term) { + #ifdef FEAT_GUI + if (term->tl_system) + { + /* Use the whole screen for the system command. However, it will start + * at the command line and scroll up as needed, using tl_toprow. */ + term->tl_rows = Rows; + term->tl_cols = Columns; + } + else + #endif if (*curwin->w_p_tms != NUL) { char_u *p = vim_strchr(curwin->w_p_tms, 'x') + 1; *************** *** 236,242 **** * Initialize job options for a terminal job. * Caller may overrule some of them. */ ! static void init_job_options(jobopt_T *opt) { clear_job_options(opt); --- 257,263 ---- * Initialize job options for a terminal job. * Caller may overrule some of them. */ ! void init_job_options(jobopt_T *opt) { clear_job_options(opt); *************** *** 301,312 **** /* * Start a terminal window and return its buffer. ! * When "without_job" is TRUE only create the buffer, b_term and open the ! * window. * Returns NULL when failed. */ ! static buf_T * ! term_start(typval_T *argvar, jobopt_T *opt, int without_job, int forceit) { exarg_T split_ea; win_T *old_curwin = curwin; --- 322,338 ---- /* * Start a terminal window and return its buffer. ! * Use either "argvar" or "argv", the other must be NULL. ! * When "flags" has TERM_START_NOJOB only create the buffer, b_term and open ! * the window. * Returns NULL when failed. */ ! buf_T * ! term_start( ! typval_T *argvar, ! char **argv, ! jobopt_T *opt, ! int flags) { exarg_T split_ea; win_T *old_curwin = curwin; *************** *** 334,359 **** term->tl_cursor_visible = TRUE; term->tl_cursor_shape = VTERM_PROP_CURSORSHAPE_BLOCK; term->tl_finish = opt->jo_term_finish; ga_init2(&term->tl_scrollback, sizeof(sb_line_T), 300); vim_memset(&split_ea, 0, sizeof(split_ea)); if (opt->jo_curwin) { /* Create a new buffer in the current window. */ ! if (!can_abandon(curbuf, forceit)) { no_write_message(); vim_free(term); return NULL; } if (do_ecmd(0, NULL, NULL, &split_ea, ECMD_ONE, ! ECMD_HIDE + (forceit ? ECMD_FORCEIT : 0), curwin) == FAIL) { vim_free(term); return NULL; } } ! else if (opt->jo_hidden) { buf_T *buf; --- 360,390 ---- term->tl_cursor_visible = TRUE; term->tl_cursor_shape = VTERM_PROP_CURSORSHAPE_BLOCK; term->tl_finish = opt->jo_term_finish; + #ifdef FEAT_GUI + term->tl_system = (flags & TERM_START_SYSTEM); + #endif ga_init2(&term->tl_scrollback, sizeof(sb_line_T), 300); vim_memset(&split_ea, 0, sizeof(split_ea)); if (opt->jo_curwin) { /* Create a new buffer in the current window. */ ! if (!can_abandon(curbuf, flags & TERM_START_FORCEIT)) { no_write_message(); vim_free(term); return NULL; } if (do_ecmd(0, NULL, NULL, &split_ea, ECMD_ONE, ! ECMD_HIDE ! + ((flags & TERM_START_FORCEIT) ? ECMD_FORCEIT : 0), ! curwin) == FAIL) { vim_free(term); return NULL; } } ! else if (opt->jo_hidden || (flags & TERM_START_SYSTEM)) { buf_T *buf; *************** *** 418,423 **** --- 449,456 ---- if (opt->jo_term_name != NULL) curbuf->b_ffname = vim_strsave(opt->jo_term_name); + else if (argv != NULL) + curbuf->b_ffname = vim_strsave((char_u *)"!system"); else { int i; *************** *** 476,487 **** set_term_and_win_size(term); setup_job_options(opt, term->tl_rows, term->tl_cols); ! if (without_job) return curbuf; #if defined(FEAT_SESSION) /* Remember the command for the session file. */ ! if (opt->jo_term_norestore) { term->tl_command = vim_strsave((char_u *)"NONE"); } --- 509,520 ---- set_term_and_win_size(term); setup_job_options(opt, term->tl_rows, term->tl_cols); ! if (flags & TERM_START_NOJOB) return curbuf; #if defined(FEAT_SESSION) /* Remember the command for the session file. */ ! if (opt->jo_term_norestore || argv != NULL) { term->tl_command = vim_strsave((char_u *)"NONE"); } *************** *** 533,544 **** } /* System dependent: setup the vterm and maybe start the job in it. */ ! if (argvar->v_type == VAR_STRING && argvar->vval.v_string != NULL && STRCMP(argvar->vval.v_string, "NONE") == 0) res = create_pty_only(term, opt); else ! res = term_and_job_init(term, argvar, opt); newbuf = curbuf; if (res == OK) --- 566,578 ---- } /* System dependent: setup the vterm and maybe start the job in it. */ ! if (argv == NULL ! && argvar->v_type == VAR_STRING && argvar->vval.v_string != NULL && STRCMP(argvar->vval.v_string, "NONE") == 0) res = create_pty_only(term, opt); else ! res = term_and_job_init(term, argvar, argv, opt); newbuf = curbuf; if (res == OK) *************** *** 546,564 **** /* Get and remember the size we ended up with. Update the pty. */ vterm_get_size(term->tl_vterm, &term->tl_rows, &term->tl_cols); term_report_winsize(term, term->tl_rows, term->tl_cols); /* Make sure we don't get stuck on sending keys to the job, it leads to * a deadlock if the job is waiting for Vim to read. */ channel_set_nonblock(term->tl_job->jv_channel, PART_IN); ! if (!opt->jo_hidden) { ++curbuf->b_locked; apply_autocmds(EVENT_BUFWINENTER, NULL, NULL, FALSE, curbuf); --curbuf->b_locked; } ! ! if (old_curbuf != NULL) { --curbuf->b_nwindows; curbuf = old_curbuf; --- 580,605 ---- /* Get and remember the size we ended up with. Update the pty. */ vterm_get_size(term->tl_vterm, &term->tl_rows, &term->tl_cols); term_report_winsize(term, term->tl_rows, term->tl_cols); + #ifdef FEAT_GUI + if (term->tl_system) + { + /* display first line below typed command */ + term->tl_toprow = msg_row + 1; + term->tl_dirty_row_end = 0; + } + #endif /* Make sure we don't get stuck on sending keys to the job, it leads to * a deadlock if the job is waiting for Vim to read. */ channel_set_nonblock(term->tl_job->jv_channel, PART_IN); ! if (old_curbuf == NULL) { ++curbuf->b_locked; apply_autocmds(EVENT_BUFWINENTER, NULL, NULL, FALSE, curbuf); --curbuf->b_locked; } ! else { --curbuf->b_nwindows; curbuf = old_curbuf; *************** *** 572,578 **** return NULL; } ! apply_autocmds(EVENT_TERMINALOPEN, NULL, NULL, FALSE, curbuf); return newbuf; } --- 613,619 ---- return NULL; } ! apply_autocmds(EVENT_TERMINALOPEN, NULL, NULL, FALSE, newbuf); return newbuf; } *************** *** 671,677 **** argvar[0].v_type = VAR_STRING; argvar[0].vval.v_string = cmd; argvar[1].v_type = VAR_UNKNOWN; ! term_start(argvar, &opt, FALSE, eap->forceit); vim_free(tofree); theend: --- 712,718 ---- argvar[0].v_type = VAR_STRING; argvar[0].vval.v_string = cmd; argvar[1].v_type = VAR_UNKNOWN; ! term_start(argvar, NULL, &opt, eap->forceit ? TERM_START_FORCEIT : 0); vim_free(tofree); theend: *************** *** 833,839 **** { if (term->tl_normal_mode) return; ! setcursor(); if (redraw) { if (term->tl_buffer == curbuf && term->tl_cursor_visible) --- 874,886 ---- { if (term->tl_normal_mode) return; ! #ifdef FEAT_GUI ! if (term->tl_system) ! windgoto(term->tl_cursor_pos.row + term->tl_toprow, ! term->tl_cursor_pos.col); ! else ! #endif ! setcursor(); if (redraw) { if (term->tl_buffer == curbuf && term->tl_cursor_visible) *************** *** 867,872 **** --- 914,928 ---- ch_log(channel, "writing %d bytes to terminal", (int)len); term_write_job_output(term, msg, len); + #ifdef FEAT_GUI + if (term->tl_system) + { + /* show system output, scrolling up the screen as needed */ + update_system_term(term); + update_cursor(term, TRUE); + } + else + #endif /* In Terminal-Normal mode we are displaying the buffer, not the terminal * contents, thus no screen update is needed. */ if (!term->tl_normal_mode) *************** *** 1905,1915 **** while (blocking || vpeekc_nomap() != NUL) { ! /* TODO: skip screen update when handling a sequence of keys. */ ! /* Repeat redrawing in case a message is received while redrawing. */ ! while (must_redraw != 0) ! if (update_screen(0) == FAIL) ! break; update_cursor(curbuf->b_term, FALSE); restore_cursor = TRUE; --- 1961,1975 ---- while (blocking || vpeekc_nomap() != NUL) { ! #ifdef FEAT_GUI ! if (!curbuf->b_term->tl_system) ! #endif ! /* TODO: skip screen update when handling a sequence of keys. */ ! /* Repeat redrawing in case a message is received while redrawing. ! */ ! while (must_redraw != 0) ! if (update_screen(0) == FAIL) ! break; update_cursor(curbuf->b_term, FALSE); restore_cursor = TRUE; *************** *** 2586,2591 **** --- 2646,2784 ---- } /* + * Fill one screen line from a line of the terminal. + * Advances "pos" to past the last column. + */ + static void + term_line2screenline(VTermScreen *screen, VTermPos *pos, int max_col) + { + int off = screen_get_current_line_off(); + + for (pos->col = 0; pos->col < max_col; ) + { + VTermScreenCell cell; + int c; + + if (vterm_screen_get_cell(screen, *pos, &cell) == 0) + vim_memset(&cell, 0, sizeof(cell)); + + c = cell.chars[0]; + if (c == NUL) + { + ScreenLines[off] = ' '; + if (enc_utf8) + ScreenLinesUC[off] = NUL; + } + else + { + if (enc_utf8) + { + int i; + + /* composing chars */ + for (i = 0; i < Screen_mco + && i + 1 < VTERM_MAX_CHARS_PER_CELL; ++i) + { + ScreenLinesC[i][off] = cell.chars[i + 1]; + if (cell.chars[i + 1] == 0) + break; + } + if (c >= 0x80 || (Screen_mco > 0 + && ScreenLinesC[0][off] != 0)) + { + ScreenLines[off] = ' '; + ScreenLinesUC[off] = c; + } + else + { + ScreenLines[off] = c; + ScreenLinesUC[off] = NUL; + } + } + #ifdef WIN3264 + 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 + ScreenLines[off] = c; + } + ScreenAttrs[off] = cell2attr(cell.attrs, cell.fg, cell.bg); + + ++pos->col; + ++off; + if (cell.width == 2) + { + if (enc_utf8) + ScreenLinesUC[off] = NUL; + + /* don't set the second byte to NUL for a DBCS encoding, it + * has been set above */ + if (enc_utf8 || !has_mbyte) + ScreenLines[off] = NUL; + + ++pos->col; + ++off; + } + } + } + + static void + update_system_term(term_T *term) + { + VTermPos pos; + VTermScreen *screen; + + if (term->tl_vterm == NULL) + return; + screen = vterm_obtain_screen(term->tl_vterm); + + /* Scroll up to make more room for terminal lines if needed. */ + while (term->tl_toprow > 0 + && (Rows - term->tl_toprow) < term->tl_dirty_row_end) + { + int save_p_more = p_more; + + p_more = FALSE; + msg_row = Rows - 1; + msg_puts((char_u *)"\n"); + p_more = save_p_more; + --term->tl_toprow; + } + + for (pos.row = term->tl_dirty_row_start; pos.row < term->tl_dirty_row_end + && pos.row < Rows; ++pos.row) + { + if (pos.row < term->tl_rows) + { + int max_col = MIN(Columns, term->tl_cols); + + term_line2screenline(screen, &pos, max_col); + } + else + pos.col = 0; + + screen_line(term->tl_toprow + pos.row, 0, pos.col, Columns, FALSE); + } + + term->tl_dirty_row_start = MAX_ROW; + term->tl_dirty_row_end = 0; + update_cursor(term, TRUE); + } + + /* * Called to update a window that contains an active terminal. * Returns FAIL when there is no terminal running in this window or in * Terminal-Normal mode. *************** *** 2650,2739 **** for (pos.row = term->tl_dirty_row_start; pos.row < term->tl_dirty_row_end && pos.row < wp->w_height; ++pos.row) { - int off = screen_get_current_line_off(); - int max_col = MIN(wp->w_width, term->tl_cols); - if (pos.row < term->tl_rows) { ! for (pos.col = 0; pos.col < max_col; ) ! { ! VTermScreenCell cell; ! int c; ! ! if (vterm_screen_get_cell(screen, pos, &cell) == 0) ! vim_memset(&cell, 0, sizeof(cell)); ! ! c = cell.chars[0]; ! if (c == NUL) ! { ! ScreenLines[off] = ' '; ! if (enc_utf8) ! ScreenLinesUC[off] = NUL; ! } ! else ! { ! if (enc_utf8) ! { ! int i; ! ! /* composing chars */ ! for (i = 0; i < Screen_mco ! && i + 1 < VTERM_MAX_CHARS_PER_CELL; ++i) ! { ! ScreenLinesC[i][off] = cell.chars[i + 1]; ! if (cell.chars[i + 1] == 0) ! break; ! } ! if (c >= 0x80 || (Screen_mco > 0 ! && ScreenLinesC[0][off] != 0)) ! { ! ScreenLines[off] = ' '; ! ScreenLinesUC[off] = c; ! } ! else ! { ! ScreenLines[off] = c; ! ScreenLinesUC[off] = NUL; ! } ! } ! #ifdef WIN3264 ! 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 ! ScreenLines[off] = c; ! } ! ScreenAttrs[off] = cell2attr(cell.attrs, cell.fg, cell.bg); ! ! ++pos.col; ! ++off; ! if (cell.width == 2) ! { ! if (enc_utf8) ! ScreenLinesUC[off] = NUL; ! ! /* don't set the second byte to NUL for a DBCS encoding, it ! * has been set above */ ! if (enc_utf8 || !has_mbyte) ! ScreenLines[off] = NUL; ! ! ++pos.col; ! ++off; ! } ! } } else pos.col = 0; --- 2843,2853 ---- for (pos.row = term->tl_dirty_row_start; pos.row < term->tl_dirty_row_end && pos.row < wp->w_height; ++pos.row) { if (pos.row < term->tl_rows) { ! int max_col = MIN(wp->w_width, term->tl_cols); ! term_line2screenline(screen, &pos, max_col); } else pos.col = 0; *************** *** 3623,3629 **** /* TODO: use the file name arguments for the buffer name */ opt.jo_term_name = (char_u *)"dump diff"; ! buf = term_start(&argvars[0], &opt, TRUE, FALSE); if (buf != NULL && buf->b_term != NULL) { int i; --- 3737,3743 ---- /* TODO: use the file name arguments for the buffer name */ opt.jo_term_name = (char_u *)"dump diff"; ! buf = term_start(&argvars[0], NULL, &opt, TERM_START_NOJOB); if (buf != NULL && buf->b_term != NULL) { int i; *************** *** 4396,4402 **** if (opt.jo_vertical) cmdmod.split = WSP_VERT; ! buf = term_start(&argvars[0], &opt, FALSE, FALSE); if (buf != NULL && buf->b_term != NULL) rettv->vval.v_number = buf->b_fnum; --- 4510,4516 ---- if (opt.jo_vertical) cmdmod.split = WSP_VERT; ! buf = term_start(&argvars[0], NULL, &opt, 0); if (buf != NULL && buf->b_term != NULL) rettv->vval.v_number = buf->b_fnum; *************** *** 4592,4597 **** --- 4706,4712 ---- term_and_job_init( term_T *term, typval_T *argvar, + char **argv UNUSED, jobopt_T *opt) { WCHAR *cmd_wchar = NULL; *************** *** 4880,4897 **** * Create a new terminal of "rows" by "cols" cells. * Start job for "cmd". * Store the pointers in "term". * Return OK or FAIL. */ static int term_and_job_init( term_T *term, typval_T *argvar, jobopt_T *opt) { create_vterm(term, term->tl_rows, term->tl_cols); ! /* This will change a string in "argvar". */ ! term->tl_job = job_start(argvar, opt); if (term->tl_job != NULL) ++term->tl_job->jv_refcount; --- 4995,5014 ---- * Create a new terminal of "rows" by "cols" cells. * Start job for "cmd". * Store the pointers in "term". + * When "argv" is not NULL then "argvar" is not used. * Return OK or FAIL. */ static int term_and_job_init( term_T *term, typval_T *argvar, + char **argv, jobopt_T *opt) { create_vterm(term, term->tl_rows, term->tl_cols); ! /* This may change a string in "argvar". */ ! term->tl_job = job_start(argvar, argv, opt); if (term->tl_job != NULL) ++term->tl_job->jv_refcount; *** ../vim-8.0.1608/src/proto/terminal.pro 2018-03-11 19:30:40.128142740 +0100 --- src/proto/terminal.pro 2018-03-14 22:48:26.777762521 +0100 *************** *** 1,4 **** --- 1,6 ---- /* terminal.c */ + void init_job_options(jobopt_T *opt); + buf_T *term_start(typval_T *argvar, char **argv, jobopt_T *opt, int flags); void ex_terminal(exarg_T *eap); int term_write_session(FILE *fd, win_T *wp); int term_should_restore(buf_T *buf); *** ../vim-8.0.1608/src/channel.c 2018-03-10 20:27:32.071757661 +0100 --- src/channel.c 2018-03-13 21:43:30.738004891 +0100 *************** *** 5383,5393 **** /* * Create a job and return it. Implements job_start(). * The returned job has a refcount of one. * Returns NULL when out of memory. */ job_T * ! job_start(typval_T *argvars, jobopt_T *opt_arg) { job_T *job; char_u *cmd = NULL; --- 5383,5395 ---- /* * Create a job and return it. Implements job_start(). + * "argv_arg" is only for Unix. + * When "argv_arg" is NULL then "argvars" is used. * The returned job has a refcount of one. * Returns NULL when out of memory. */ job_T * ! job_start(typval_T *argvars, char **argv_arg, jobopt_T *opt_arg) { job_T *job; char_u *cmd = NULL; *************** *** 5474,5479 **** --- 5476,5488 ---- job_set_options(job, &opt); + #ifdef USE_ARGV + if (argv_arg != NULL) + { + argv = argv_arg; + } + else + #endif if (argvars[0].v_type == VAR_STRING) { /* Command is a string. */ *************** *** 5551,5557 **** theend: #ifdef USE_ARGV ! vim_free(argv); #else vim_free(ga.ga_data); #endif --- 5560,5567 ---- theend: #ifdef USE_ARGV ! if (argv != argv_arg) ! vim_free(argv); #else vim_free(ga.ga_data); #endif *** ../vim-8.0.1608/src/proto/channel.pro 2017-12-09 19:13:08.579678220 +0100 --- src/proto/channel.pro 2018-03-13 22:27:20.877173011 +0100 *************** *** 66,72 **** void job_stop_on_exit(void); int has_pending_job(void); void job_check_ended(void); ! job_T *job_start(typval_T *argvars, jobopt_T *opt_arg); char *job_status(job_T *job); void job_info(job_T *job, dict_T *dict); int job_stop(job_T *job, typval_T *argvars, char *type); --- 66,72 ---- void job_stop_on_exit(void); int has_pending_job(void); void job_check_ended(void); ! job_T *job_start(typval_T *argvars, char **argv_arg, jobopt_T *opt_arg); char *job_status(job_T *job); void job_info(job_T *job, dict_T *dict); int job_stop(job_T *job, typval_T *argvars, char *type); *** ../vim-8.0.1608/src/vim.h 2018-03-11 17:02:07.310194396 +0100 --- src/vim.h 2018-03-13 22:18:13.232722972 +0100 *************** *** 2543,2546 **** --- 2543,2551 ---- #define REPLACE_CR_NCHAR -1 #define REPLACE_NL_NCHAR -2 + /* flags for term_start() */ + #define TERM_START_NOJOB 1 + #define TERM_START_FORCEIT 2 + #define TERM_START_SYSTEM 4 + #endif /* VIM__H */ *** ../vim-8.0.1608/runtime/doc/options.txt 2018-02-22 21:06:44.550819285 +0100 --- runtime/doc/options.txt 2018-03-13 21:22:21.450057261 +0100 *************** *** 3760,3766 **** To avoid problems with flags that are added in the future, use the "+=" and "-=" feature of ":set" |add-option-flags|. ! Valid letters are as follows: *guioptions_a* *'go-a'* 'a' Autoselect: If present, then whenever VISUAL mode is started, or the Visual area extended, Vim tries to become the owner of --- 3845,3858 ---- To avoid problems with flags that are added in the future, use the "+=" and "-=" feature of ":set" |add-option-flags|. ! Valid characters are as follows: ! *'go-!'* ! '!' External commands are executed in a terminal window. Without ! this flag the MS-Windows GUI will open a console window to ! execute the command. The Unix GUI will simulate a dumb ! terminal to list the command output. ! The terminal window will be positioned at the bottom, and grow ! upwards as needed. *guioptions_a* *'go-a'* 'a' Autoselect: If present, then whenever VISUAL mode is started, or the Visual area extended, Vim tries to become the owner of *** ../vim-8.0.1608/src/version.c 2018-03-14 21:38:57.912996023 +0100 --- src/version.c 2018-03-16 20:44:10.622996708 +0100 *************** *** 768,769 **** --- 768,771 ---- { /* Add new patch number below this line */ + /**/ + 1609, /**/ -- Don't Panic! -- The Hitchhiker's Guide to the Galaxy /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///