# HG changeset patch # User Christian Brabandt # Date 1500832805 -7200 # Node ID 74abb6c84984ec033d52db69afbf757eb45836f2 # Parent e3e89d6460d09c6fe551c16f341c9c62100b7bfe patch 8.0.0761: options not set properly for a terminal buffer commit https://github.com/vim/vim/commit/1f2903c43109b16594d141a730659317b15f388d Author: Bram Moolenaar Date: Sun Jul 23 19:51:01 2017 +0200 patch 8.0.0761: options not set properly for a terminal buffer Problem: Options of a buffer for a terminal window are not set properly. Solution: Add "terminal" value for 'buftype'. Make 'buftype' and 'bufhidden' not depend on the quickfix feature. Also set the buffer name and show "running" or "finished" in the window title. diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1,4 +1,4 @@ -*options.txt* For Vim version 8.0. Last change: 2017 Jul 15 +*options.txt* For Vim version 8.0. Last change: 2017 Jul 23 VIM REFERENCE MANUAL by Bram Moolenaar @@ -1319,8 +1319,6 @@ A jump table for the options with a shor 'bufhidden' 'bh' string (default: "") local to buffer {not in Vi} - {not available when compiled without the |+quickfix| - feature} This option specifies what happens when a buffer is no longer displayed in a window: follow the global 'hidden' option @@ -1355,8 +1353,6 @@ A jump table for the options with a shor 'buftype' 'bt' string (default: "") local to buffer {not in Vi} - {not available when compiled without the |+quickfix| - feature} The value of this option specifies the type of a buffer: normal buffer nofile buffer which is not related to a file and will not be @@ -1369,6 +1365,8 @@ A jump table for the options with a shor or list of locations |:lwindow| help help buffer (you are not supposed to set this manually) + terminal buffer for a |terminal| (you are not supposed to set + this manually) This option is used together with 'bufhidden' and 'swapfile' to specify special kinds of buffers. See |special-buffers|. @@ -7760,19 +7758,26 @@ A jump table for the options with a shor {not in Vi} The key that precedes a Vim command in a terminal window. Other keys are sent to the job running in the window. - The string must be one key stroke. + The string must be one key stroke but can be multiple bytes. NOT IMPLEMENTED YET - *'thesaurus'* *'tsr'* + *'termsize'* *'tms'* 'termsize' 'tms' string (default "") local to window {not in Vi} Size of the |terminal| window. Format: {rows}x{columns}. - When empty the terminal gets the size from the window. - - When set (e.g., "24x80") the terminal size is fixed. If the window - is smaller only the top-left part is displayed. - NOT IMPLEMENTED YET + - When set (e.g., "24x80") the terminal size is not adjusted to the + window size. If the window is smaller only the top-left part is + displayed. + When rows is zero then use the height of the window. + When columns is zero then use the width of the window. + For example: "30x0" uses 30 rows with the current window width. + Using "0x0" is the same as empty. + Note that the command running in the terminal window may still change + the size of the terminal. In that case the Vim window will be + adjusted to that size, if possible. *'terse'* *'noterse'* 'terse' boolean (default off) diff --git a/src/buffer.c b/src/buffer.c --- a/src/buffer.c +++ b/src/buffer.c @@ -468,7 +468,6 @@ close_buffer( int del_buf = (action == DOBUF_DEL || action == DOBUF_WIPE); int wipe_buf = (action == DOBUF_WIPE); -#ifdef FEAT_QUICKFIX /* * Force unloading or deleting when 'bufhidden' says so. * The caller must take care of NOT deleting/freeing when 'bufhidden' is @@ -487,7 +486,6 @@ close_buffer( } else if (buf->b_p_bh[0] == 'u') /* 'bufhidden' == "unload" */ unload_buf = TRUE; -#endif #ifdef FEAT_AUTOCMD /* Disallow deleting the buffer when it is locked (already being closed or @@ -1982,16 +1980,14 @@ buflist_new( return NULL; # endif #endif -#ifdef FEAT_QUICKFIX -# ifdef FEAT_AUTOCMD +#ifdef FEAT_AUTOCMD if (buf == curbuf) -# endif +#endif { /* Make sure 'bufhidden' and 'buftype' are empty */ clear_string_option(&buf->b_p_bh); clear_string_option(&buf->b_p_bt); } -#endif } if (buf != curbuf || curbuf == NULL) { @@ -2165,10 +2161,8 @@ free_buf_options( clear_string_option(&buf->b_p_fenc); #endif clear_string_option(&buf->b_p_ff); -#ifdef FEAT_QUICKFIX clear_string_option(&buf->b_p_bh); clear_string_option(&buf->b_p_bt); -#endif } #ifdef FEAT_FIND_ID clear_string_option(&buf->b_p_def); @@ -3668,9 +3662,21 @@ maketitle(void) /* remove the file name */ p = gettail_sep(buf + off); if (p == buf + off) - /* must be a help buffer */ - vim_strncpy(buf + off, (char_u *)_("help"), + { + char *txt; + +#ifdef FEAT_TERMINAL + if (curbuf->b_term != NULL) + txt = term_job_running(curbuf) + ? _("running") : _("finished"); + else +#endif + txt = _("help"); + + /* must be a help or terminal buffer */ + vim_strncpy(buf + off, (char_u *)txt, (size_t)(SPACE_FOR_DIR - off - 1)); + } else *p = NUL; diff --git a/src/channel.c b/src/channel.c --- a/src/channel.c +++ b/src/channel.c @@ -4696,6 +4696,10 @@ job_cleanup(job_T *job) * not use "job" after this! */ job_free(job); } + +#ifdef FEAT_TERMINAL + term_job_ended(job); +#endif } /* diff --git a/src/ex_docmd.c b/src/ex_docmd.c --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -8548,7 +8548,7 @@ ex_resize(exarg_T *eap) { if (*eap->arg == '-' || *eap->arg == '+') n += curwin->w_height; - else if (n == 0 && eap->arg[0] == NUL) /* default is very wide */ + else if (n == 0 && eap->arg[0] == NUL) /* default is very high */ n = 9999; win_setheight_win((int)n, wp); } @@ -11679,10 +11679,7 @@ put_view( */ if ((*flagp & SSOP_FOLDS) && wp->w_buffer->b_ffname != NULL -# ifdef FEAT_QUICKFIX - && (*wp->w_buffer->b_p_bt == NUL || wp->w_buffer->b_help) -# endif - ) + && (*wp->w_buffer->b_p_bt == NUL || wp->w_buffer->b_help)) { if (put_folds(fd, wp) == FAIL) return FAIL; diff --git a/src/fileio.c b/src/fileio.c --- a/src/fileio.c +++ b/src/fileio.c @@ -6882,9 +6882,7 @@ buf_check_timestamp( * this buffer. */ if (buf->b_ffname == NULL || buf->b_ml.ml_mfp == NULL -#if defined(FEAT_QUICKFIX) || *buf->b_p_bt != NUL -#endif || buf->b_saving #ifdef FEAT_AUTOCMD || busy diff --git a/src/option.c b/src/option.c --- a/src/option.c +++ b/src/option.c @@ -287,10 +287,8 @@ static int p_bin; #ifdef FEAT_MBYTE static int p_bomb; #endif -#if defined(FEAT_QUICKFIX) static char_u *p_bh; static char_u *p_bt; -#endif static int p_bl; static int p_ci; #ifdef FEAT_CINDENT @@ -720,26 +718,16 @@ static struct vimoption options[] = #endif SCRIPTID_INIT}, {"bufhidden", "bh", P_STRING|P_ALLOCED|P_VI_DEF|P_NOGLOB, -#if defined(FEAT_QUICKFIX) (char_u *)&p_bh, PV_BH, {(char_u *)"", (char_u *)0L} -#else - (char_u *)NULL, PV_NONE, - {(char_u *)0L, (char_u *)0L} -#endif SCRIPTID_INIT}, {"buflisted", "bl", P_BOOL|P_VI_DEF|P_NOGLOB, (char_u *)&p_bl, PV_BL, {(char_u *)1L, (char_u *)0L} SCRIPTID_INIT}, {"buftype", "bt", P_STRING|P_ALLOCED|P_VI_DEF|P_NOGLOB, -#if defined(FEAT_QUICKFIX) (char_u *)&p_bt, PV_BT, {(char_u *)"", (char_u *)0L} -#else - (char_u *)NULL, PV_NONE, - {(char_u *)0L, (char_u *)0L} -#endif SCRIPTID_INIT}, {"casemap", "cmp", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP, #ifdef FEAT_MBYTE @@ -3254,14 +3242,12 @@ static char *(p_debug_values[]) = {"msg" #ifdef FEAT_WINDOWS static char *(p_ead_values[]) = {"both", "ver", "hor", NULL}; #endif -#if defined(FEAT_QUICKFIX) -# ifdef FEAT_AUTOCMD -static char *(p_buftype_values[]) = {"nofile", "nowrite", "quickfix", "help", "acwrite", NULL}; -# else -static char *(p_buftype_values[]) = {"nofile", "nowrite", "quickfix", "help", NULL}; -# endif +#ifdef FEAT_AUTOCMD +static char *(p_buftype_values[]) = {"nofile", "nowrite", "quickfix", "help", "terminal", "acwrite", NULL}; +#else +static char *(p_buftype_values[]) = {"nofile", "nowrite", "quickfix", "help", "terminal", NULL}; +#endif static char *(p_bufhidden_values[]) = {"hide", "unload", "delete", "wipe", NULL}; -#endif static char *(p_bs_values[]) = {"indent", "eol", "start", NULL}; #ifdef FEAT_FOLDING static char *(p_fdm_values[]) = {"manual", "expr", "marker", "indent", "syntax", @@ -5649,10 +5635,8 @@ check_options(void) void check_buf_options(buf_T *buf) { -#if defined(FEAT_QUICKFIX) check_string_option(&buf->b_p_bh); check_string_option(&buf->b_p_bt); -#endif #ifdef FEAT_MBYTE check_string_option(&buf->b_p_fenc); #endif @@ -7115,7 +7099,6 @@ did_set_string_option( } #endif -#ifdef FEAT_QUICKFIX /* When 'bufhidden' is set, check for valid value. */ else if (gvarp == &p_bh) { @@ -7130,20 +7113,19 @@ did_set_string_option( errmsg = e_invarg; else { -# ifdef FEAT_WINDOWS +#ifdef FEAT_WINDOWS if (curwin->w_status_height) { curwin->w_redr_status = TRUE; redraw_later(VALID); } -# endif +#endif curbuf->b_help = (curbuf->b_p_bt[0] == 'h'); -# ifdef FEAT_TITLE +#ifdef FEAT_TITLE redraw_titles(); -# endif - } - } -#endif +#endif + } + } #ifdef FEAT_STL_OPT /* 'statusline' or 'rulerformat' */ @@ -10722,10 +10704,8 @@ get_varp(struct vimoption *p) #ifdef FEAT_MBYTE case PV_BOMB: return (char_u *)&(curbuf->b_p_bomb); #endif -#if defined(FEAT_QUICKFIX) case PV_BH: return (char_u *)&(curbuf->b_p_bh); case PV_BT: return (char_u *)&(curbuf->b_p_bt); -#endif case PV_BL: return (char_u *)&(curbuf->b_p_bl); case PV_CI: return (char_u *)&(curbuf->b_p_ci); #ifdef FEAT_CINDENT @@ -11119,10 +11099,8 @@ buf_copy_options(buf_T *buf, int flags) } if (buf->b_p_ff != NULL) buf->b_start_ffc = *buf->b_p_ff; -#if defined(FEAT_QUICKFIX) buf->b_p_bh = empty_option; buf->b_p_bt = empty_option; -#endif } else free_buf_options(buf, FALSE); @@ -11284,10 +11262,8 @@ buf_copy_options(buf_T *buf, int flags) did_isk = TRUE; buf->b_p_ts = p_ts; buf->b_help = FALSE; -#ifdef FEAT_QUICKFIX if (buf->b_p_bt[0] == 'h') clear_string_option(&buf->b_p_bt); -#endif buf->b_p_ma = p_ma; } } diff --git a/src/proto/quickfix.pro b/src/proto/quickfix.pro --- a/src/proto/quickfix.pro +++ b/src/proto/quickfix.pro @@ -12,11 +12,6 @@ void ex_cclose(exarg_T *eap); void ex_copen(exarg_T *eap); void ex_cbottom(exarg_T *eap); linenr_T qf_current_entry(win_T *wp); -int bt_quickfix(buf_T *buf); -int bt_nofile(buf_T *buf); -int bt_dontwrite(buf_T *buf); -int bt_dontwrite_msg(buf_T *buf); -int buf_hide(buf_T *buf); int grep_internal(cmdidx_T cmdidx); void ex_make(exarg_T *eap); int qf_get_size(exarg_T *eap); @@ -33,4 +28,10 @@ int set_ref_in_quickfix(int copyID); void ex_cbuffer(exarg_T *eap); void ex_cexpr(exarg_T *eap); void ex_helpgrep(exarg_T *eap); +int bt_quickfix(buf_T *buf); +int bt_terminal(buf_T *buf); +int bt_nofile(buf_T *buf); +int bt_dontwrite(buf_T *buf); +int bt_dontwrite_msg(buf_T *buf); +int buf_hide(buf_T *buf); /* vim: set ft=c : */ diff --git a/src/proto/terminal.pro b/src/proto/terminal.pro --- a/src/proto/terminal.pro +++ b/src/proto/terminal.pro @@ -2,6 +2,8 @@ void ex_terminal(exarg_T *eap); void free_terminal(term_T *term); void write_to_term(buf_T *buffer, char_u *msg, channel_T *channel); +void terminal_loop(void); +void term_job_ended(job_T *job); +int term_job_running(buf_T *buf); void term_update_window(win_T *wp); -void terminal_loop(void); /* vim: set ft=c : */ diff --git a/src/quickfix.c b/src/quickfix.c --- a/src/quickfix.c +++ b/src/quickfix.c @@ -2169,7 +2169,7 @@ qf_jump( * quickfix window. */ FOR_ALL_WINDOWS(usable_win_ptr) if (usable_win_ptr->w_llist == ll_ref - && usable_win_ptr->w_buffer->b_p_bt[0] != 'q') + && !bt_quickfix(usable_win_ptr->w_buffer)) { usable_win = 1; break; @@ -3450,64 +3450,6 @@ qf_fill_buffer(qf_info_T *qi, buf_T *buf #endif /* FEAT_WINDOWS */ /* - * Return TRUE if "buf" is the quickfix buffer. - */ - int -bt_quickfix(buf_T *buf) -{ - return buf != NULL && buf->b_p_bt[0] == 'q'; -} - -/* - * Return TRUE if "buf" is a "nofile" or "acwrite" buffer. - * This means the buffer name is not a file name. - */ - int -bt_nofile(buf_T *buf) -{ - return buf != NULL && ((buf->b_p_bt[0] == 'n' && buf->b_p_bt[2] == 'f') - || buf->b_p_bt[0] == 'a'); -} - -/* - * Return TRUE if "buf" is a "nowrite" or "nofile" buffer. - */ - int -bt_dontwrite(buf_T *buf) -{ - return buf != NULL && buf->b_p_bt[0] == 'n'; -} - - int -bt_dontwrite_msg(buf_T *buf) -{ - if (bt_dontwrite(buf)) - { - EMSG(_("E382: Cannot write, 'buftype' option is set")); - return TRUE; - } - return FALSE; -} - -/* - * Return TRUE if the buffer should be hidden, according to 'hidden', ":hide" - * and 'bufhidden'. - */ - int -buf_hide(buf_T *buf) -{ - /* 'bufhidden' overrules 'hidden' and ":hide", check it first */ - switch (buf->b_p_bh[0]) - { - case 'u': /* "unload" */ - case 'w': /* "wipe" */ - case 'd': return FALSE; /* "delete" */ - case 'h': return TRUE; /* "hide" */ - } - return (p_hid || cmdmod.hide); -} - -/* * Return TRUE when using ":vimgrep" for ":grep". */ int @@ -5584,3 +5526,72 @@ ex_helpgrep(exarg_T *eap) } #endif /* FEAT_QUICKFIX */ + +/* + * Return TRUE if "buf" is the quickfix buffer. + */ + int +bt_quickfix(buf_T *buf) +{ + return buf != NULL && buf->b_p_bt[0] == 'q'; +} + +/* + * Return TRUE if "buf" is a terminal buffer. + */ + int +bt_terminal(buf_T *buf) +{ + return buf != NULL && buf->b_p_bt[0] == 't'; +} + +/* + * Return TRUE if "buf" is a "nofile", "acwrite" or "terminal" buffer. + * This means the buffer name is not a file name. + */ + int +bt_nofile(buf_T *buf) +{ + return buf != NULL && ((buf->b_p_bt[0] == 'n' && buf->b_p_bt[2] == 'f') + || buf->b_p_bt[0] == 'a' + || buf->b_p_bt[0] == 't'); +} + +/* + * Return TRUE if "buf" is a "nowrite", "nofile" or "terminal" buffer. + */ + int +bt_dontwrite(buf_T *buf) +{ + return buf != NULL && (buf->b_p_bt[0] == 'n' || buf->b_p_bt[0] == 't'); +} + + int +bt_dontwrite_msg(buf_T *buf) +{ + if (bt_dontwrite(buf)) + { + EMSG(_("E382: Cannot write, 'buftype' option is set")); + return TRUE; + } + return FALSE; +} + +/* + * Return TRUE if the buffer should be hidden, according to 'hidden', ":hide" + * and 'bufhidden'. + */ + int +buf_hide(buf_T *buf) +{ + /* 'bufhidden' overrules 'hidden' and ":hide", check it first */ + switch (buf->b_p_bh[0]) + { + case 'u': /* "unload" */ + case 'w': /* "wipe" */ + case 'd': return FALSE; /* "delete" */ + case 'h': return TRUE; /* "hide" */ + } + return (p_hid || cmdmod.hide); +} + diff --git a/src/structs.h b/src/structs.h --- a/src/structs.h +++ b/src/structs.h @@ -2088,9 +2088,9 @@ struct file_buffer #ifdef FEAT_MBYTE int b_p_bomb; /* 'bomb' */ #endif -#ifdef FEAT_QUICKFIX char_u *b_p_bh; /* 'bufhidden' */ char_u *b_p_bt; /* 'buftype' */ +#ifdef FEAT_QUICKFIX #define BUF_HAS_QF_ENTRY 1 #define BUF_HAS_LL_ENTRY 2 int b_has_qf_entry; diff --git a/src/terminal.c b/src/terminal.c --- a/src/terminal.c +++ b/src/terminal.c @@ -33,9 +33,8 @@ * while, if the terminal window is visible, the screen contents is drawn. * * TODO: - * - cursor flickers when moving the cursor - * - set buffer options to be scratch, hidden, nomodifiable, etc. - * - set buffer name to command, add (1) to avoid duplicates. + * - do not store terminal buffer in viminfo + * - put terminal title in the statusline * - Add a scrollback buffer (contains lines to scroll off the top). * Can use the buf_T lines, store attributes somewhere else? * - When the job ends: @@ -53,7 +52,6 @@ * - support minimal size when 'termsize' is empty? * - implement "term" for job_start(): more job options when starting a * terminal. - * - implement ":buf {term-buf-name}" * - implement term_list() list of buffers with a terminal * - implement term_getsize(buf) * - implement term_setsize(buf) @@ -192,7 +190,31 @@ ex_terminal(exarg_T *eap) term->tl_next = first_term; first_term = term; - /* TODO: set buffer type, hidden, etc. */ + if (buflist_findname(cmd) == NULL) + curbuf->b_ffname = vim_strsave(cmd); + else + { + int i; + size_t len = STRLEN(cmd) + 10; + char_u *p = alloc(len); + + for (i = 1; p != NULL; ++i) + { + vim_snprintf((char *)p, len, "%s (%d)", cmd, i); + if (buflist_findname(p) == NULL) + { + curbuf->b_ffname = p; + break; + } + } + } + curbuf->b_fname = curbuf->b_ffname; + + /* Mark the buffer as changed, so that it's not easy to abandon the job. */ + curbuf->b_changed = TRUE; + curbuf->b_p_ma = FALSE; + set_string_option_direct((char_u *)"buftype", -1, + (char_u *)"terminal", OPT_FREE|OPT_LOCAL, 0); set_term_and_win_size(term); @@ -490,6 +512,26 @@ terminal_loop(void) } } +/* + * Called when a job has finished. + */ + void +term_job_ended(job_T *job) +{ + if (curbuf->b_term != NULL && curbuf->b_term->tl_job == job) + maketitle(); +} + +/* + * Return TRUE if the job for "buf" is still running. + */ + int +term_job_running(buf_T *buf) +{ + return buf->b_term != NULL && buf->b_term->tl_job != NULL + && buf->b_term->tl_job->jv_status == JOB_STARTED; +} + static void position_cursor(win_T *wp, VTermPos *pos) { @@ -850,13 +892,20 @@ setup_job_options(jobopt_T *opt, int row opt->jo_out_mode = MODE_RAW; opt->jo_err_mode = MODE_RAW; opt->jo_set = JO_MODE | JO_OUT_MODE | JO_ERR_MODE; + opt->jo_io[PART_OUT] = JIO_BUFFER; opt->jo_io[PART_ERR] = JIO_BUFFER; - opt->jo_set |= JO_OUT_IO + (JO_OUT_IO << (PART_ERR - PART_OUT)); + opt->jo_set |= JO_OUT_IO + JO_ERR_IO; + + opt->jo_modifiable[PART_OUT] = 0; + opt->jo_modifiable[PART_ERR] = 0; + opt->jo_set |= JO_OUT_MODIFIABLE + JO_ERR_MODIFIABLE; + opt->jo_io_buf[PART_OUT] = curbuf->b_fnum; opt->jo_io_buf[PART_ERR] = curbuf->b_fnum; opt->jo_pty = TRUE; - opt->jo_set |= JO_OUT_BUF + (JO_OUT_BUF << (PART_ERR - PART_OUT)); + opt->jo_set |= JO_OUT_BUF + JO_ERR_BUF; + opt->jo_term_rows = rows; opt->jo_term_cols = cols; } diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -770,6 +770,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 761, +/**/ 760, /**/ 759,