Patch 8.0.1592
Problem:    Terminal windows in a session are not properly restored.
Solution:   Add "terminal" in 'sessionoptions'.  When possible restore the
            command running in a terminal.
Files:      src/option.c, src/option.h, src/ex_docmd.c, src/terminal.c,
            src/proto/terminal.pro, src/evalfunc.c, src/structs.h,
            src/channel.c, src/testdir/test_terminal.vim,
            src/testdir/shared.vim, src/testdir/test_mksession.vim


*** ../vim-8.0.1591/src/option.c        2018-03-07 23:02:29.594336432 +0100
--- src/option.c        2018-03-08 22:09:44.716834176 +0100
***************
*** 2403,2409 ****
      {"sessionoptions", "ssop", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
  #ifdef FEAT_SESSION
                            (char_u *)&p_ssop, PV_NONE,
!        {(char_u *)"blank,buffers,curdir,folds,help,options,tabpages,winsize",
                                                               (char_u *)0L}
  #else
                            (char_u *)NULL, PV_NONE,
--- 2403,2409 ----
      {"sessionoptions", "ssop", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
  #ifdef FEAT_SESSION
                            (char_u *)&p_ssop, PV_NONE,
!        {(char_u 
*)"blank,buffers,curdir,folds,help,options,tabpages,winsize,terminal",
                                                               (char_u *)0L}
  #else
                            (char_u *)NULL, PV_NONE,
*** ../vim-8.0.1591/src/option.h        2018-03-04 20:14:08.252064314 +0100
--- src/option.h        2018-03-08 22:11:16.736211708 +0100
***************
*** 751,757 ****
  /* Also used for 'viewoptions'! */
  static char *(p_ssop_values[]) = {"buffers", "winpos", "resize", "winsize",
      "localoptions", "options", "help", "blank", "globals", "slash", "unix",
!     "sesdir", "curdir", "folds", "cursor", "tabpages", NULL};
  # endif
  # define SSOP_BUFFERS         0x001
  # define SSOP_WINPOS          0x002
--- 751,757 ----
  /* Also used for 'viewoptions'! */
  static char *(p_ssop_values[]) = {"buffers", "winpos", "resize", "winsize",
      "localoptions", "options", "help", "blank", "globals", "slash", "unix",
!     "sesdir", "curdir", "folds", "cursor", "tabpages", "terminal", NULL};
  # endif
  # define SSOP_BUFFERS         0x001
  # define SSOP_WINPOS          0x002
***************
*** 769,774 ****
--- 769,775 ----
  # define SSOP_FOLDS           0x2000
  # define SSOP_CURSOR          0x4000
  # define SSOP_TABPAGES                0x8000
+ # define SSOP_TERMINAL                0x10000
  #endif
  EXTERN char_u *p_sh;          /* 'shell' */
  EXTERN char_u *p_shcf;        /* 'shellcmdflag' */
*** ../vim-8.0.1591/src/ex_docmd.c      2018-03-05 21:06:19.763252514 +0100
--- src/ex_docmd.c      2018-03-09 20:38:43.573014028 +0100
***************
*** 11095,11100 ****
--- 11095,11105 ----
      {
        if (!(only_save_windows && buf->b_nwindows == 0)
                && !(buf->b_help && !(ssop_flags & SSOP_HELP))
+ #ifdef FEAT_TERMINAL
+               /* skip terminal buffers: finished ones are not useful, others
+                * will be resurrected and result in a new buffer */
+               && !bt_terminal(buf)
+ #endif
                && buf->b_fname != NULL
                && buf->b_p_bl)
        {
***************
*** 11305,11311 ****
      /*
       * Wipe out an empty unnamed buffer we started in.
       */
!     if (put_line(fd, "if exists('s:wipebuf')") == FAIL)
        return FAIL;
      if (put_line(fd, "  silent exe 'bwipe ' . s:wipebuf") == FAIL)
        return FAIL;
--- 11310,11317 ----
      /*
       * Wipe out an empty unnamed buffer we started in.
       */
!     if (put_line(fd, "if exists('s:wipebuf') && s:wipebuf != bufnr('%')")
!                                                                      == FAIL)
        return FAIL;
      if (put_line(fd, "  silent exe 'bwipe ' . s:wipebuf") == FAIL)
        return FAIL;
***************
*** 11465,11470 ****
--- 11471,11482 ----
      static int
  ses_do_win(win_T *wp)
  {
+ #ifdef FEAT_TERMINAL
+     if (bt_terminal(wp->w_buffer))
+       return !term_is_finished(wp->w_buffer)
+           && (ssop_flags & SSOP_TERMINAL)
+           && term_should_restore(wp->w_buffer);
+ #endif
      if (wp->w_buffer->b_fname == NULL
  #ifdef FEAT_QUICKFIX
            /* When 'buftype' is "nofile" can't restore the window contents. */
***************
*** 11530,11542 ****
      /* Edit the file.  Skip this when ":next" already did it. */
      if (add_edit && (!did_next || wp->w_arg_idx_invalid))
      {
        /*
         * Load the file.
         */
        if (wp->w_buffer->b_ffname != NULL
! #ifdef FEAT_QUICKFIX
                && !bt_nofile(wp->w_buffer)
! #endif
                )
        {
            /*
--- 11542,11562 ----
      /* Edit the file.  Skip this when ":next" already did it. */
      if (add_edit && (!did_next || wp->w_arg_idx_invalid))
      {
+ # ifdef FEAT_TERMINAL
+       if (bt_terminal(wp->w_buffer))
+       {
+           if (term_write_session(fd, wp) == FAIL)
+               return FAIL;
+       }
+       else
+ # endif
        /*
         * Load the file.
         */
        if (wp->w_buffer->b_ffname != NULL
! # ifdef FEAT_QUICKFIX
                && !bt_nofile(wp->w_buffer)
! # endif
                )
        {
            /*
***************
*** 11554,11561 ****
                    || fputs(" | else | edit ", fd) < 0
                    || ses_fname(fd, wp->w_buffer, flagp, FALSE) == FAIL
                    || fputs(" | endif", fd) < 0
!                   ||
!               put_eol(fd) == FAIL)
                return FAIL;
        }
        else
--- 11574,11580 ----
                    || fputs(" | else | edit ", fd) < 0
                    || ses_fname(fd, wp->w_buffer, flagp, FALSE) == FAIL
                    || fputs(" | endif", fd) < 0
!                   || put_eol(fd) == FAIL)
                return FAIL;
        }
        else
*** ../vim-8.0.1591/src/terminal.c      2018-03-04 18:07:04.284592244 +0100
--- src/terminal.c      2018-03-09 21:27:59.970681174 +0100
***************
*** 38,48 ****
   * in tl_scrollback are no longer used.
   *
   * TODO:
!  * - What to store in a session file?  Shell at the prompt would be OK to
!  *   restore, but others may not.  Open the window and let the user start the
!  *   command?  Also see #2650.
!  * - Adding WinBar to terminal window doesn't display, text isn't shifted 
down.
   * - When using 'termguicolors' still use the 16 ANSI colors as-is.  Helps for
   *   a job that uses 16 colors while Vim is using > 256.
   * - in GUI vertical split causes problems.  Cursor is flickering. (Hirohito
   *   Higashi, 2017 Sep 19)
--- 38,47 ----
   * in tl_scrollback are no longer used.
   *
   * TODO:
!  * - Add a flag to kill the job when Vim is exiting.  Useful when it's showing
!  *   a logfile.  Or send keys there to make it quit: "exit\r" for a shell.
   * - When using 'termguicolors' still use the 16 ANSI colors as-is.  Helps for
+  * - Adding WinBar to terminal window doesn't display, text isn't shifted 
down.
   *   a job that uses 16 colors while Vim is using > 256.
   * - in GUI vertical split causes problems.  Cursor is flickering. (Hirohito
   *   Higashi, 2017 Sep 19)
***************
*** 135,140 ****
--- 134,142 ----
      void      *tl_winpty_config;
      void      *tl_winpty;
  #endif
+ #if defined(FEAT_SESSION)
+     char_u    *tl_command;
+ #endif
  
      /* last known vterm size */
      int               tl_rows;
***************
*** 487,492 ****
--- 489,540 ----
      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");
+     }
+     else if (argvar->v_type == VAR_STRING)
+     {
+       char_u  *cmd = argvar->vval.v_string;
+ 
+       if (cmd != NULL && STRCMP(cmd, p_sh) != 0)
+           term->tl_command = vim_strsave(cmd);
+     }
+     else if (argvar->v_type == VAR_LIST
+           && argvar->vval.v_list != NULL
+           && argvar->vval.v_list->lv_len > 0)
+     {
+       garray_T        ga;
+       listitem_T      *item;
+ 
+       ga_init2(&ga, 1, 100);
+       for (item = argvar->vval.v_list->lv_first;
+                                       item != NULL; item = item->li_next)
+       {
+           char_u *s = get_tv_string_chk(&item->li_tv);
+           char_u *p;
+ 
+           if (s == NULL)
+               break;
+           p = vim_strsave_fnameescape(s, FALSE);
+           if (p == NULL)
+               break;
+           ga_concat(&ga, p);
+           vim_free(p);
+           ga_append(&ga, ' ');
+       }
+       if (item == NULL)
+       {
+           ga_append(&ga, NUL);
+           term->tl_command = ga.ga_data;
+       }
+       else
+           ga_clear(&ga);
+     }
+ #endif
+ 
      /* System dependent: setup the vterm and maybe start the job in it. */
      if (argvar->v_type == VAR_STRING
            && argvar->vval.v_string != NULL
***************
*** 561,566 ****
--- 609,616 ----
            opt.jo_curwin = 1;
        else if ((int)(p - cmd) == 6 && STRNICMP(cmd, "hidden", 6) == 0)
            opt.jo_hidden = 1;
+       else if ((int)(p - cmd) == 9 && STRNICMP(cmd, "norestore", 9) == 0)
+           opt.jo_term_norestore = 1;
        else if ((int)(p - cmd) == 4 && STRNICMP(cmd, "rows", 4) == 0
                && ep != NULL && isdigit(ep[1]))
        {
***************
*** 620,625 ****
--- 670,711 ----
      vim_free(opt.jo_eof_chars);
  }
  
+ #if defined(FEAT_SESSION) || defined(PROTO)
+ /*
+  * Write a :terminal command to the session file to restore the terminal in
+  * window "wp".
+  * Return FAIL if writing fails.
+  */
+     int
+ term_write_session(FILE *fd, win_T *wp)
+ {
+     term_T *term = wp->w_buffer->b_term;
+ 
+     /* Create the terminal and run the command.  This is not without
+      * risk, but let's assume the user only creates a session when this
+      * will be OK. */
+     if (fprintf(fd, "terminal ++curwin ++cols=%d ++rows=%d ",
+               term->tl_cols, term->tl_rows) < 0)
+       return FAIL;
+     if (term->tl_command != NULL && fputs((char *)term->tl_command, fd) < 0)
+       return FAIL;
+ 
+     return put_eol(fd);
+ }
+ 
+ /*
+  * Return TRUE if "buf" has a terminal that should be restored.
+  */
+     int
+ term_should_restore(buf_T *buf)
+ {
+     term_T    *term = buf->b_term;
+ 
+     return term != NULL && (term->tl_command == NULL
+                                    || STRCMP(term->tl_command, "NONE") != 0);
+ }
+ #endif
+ 
  /*
   * Free the scrollback buffer for "term".
   */
***************
*** 669,674 ****
--- 755,763 ----
  
      term_free_vterm(term);
      vim_free(term->tl_title);
+ #ifdef FEAT_SESSION
+     vim_free(term->tl_command);
+ #endif
      vim_free(term->tl_status_text);
      vim_free(term->tl_opencmd);
      vim_free(term->tl_eof_chars);
***************
*** 4048,4053 ****
--- 4137,4165 ----
  }
  
  /*
+  * "term_setrestore(buf, command)" function
+  */
+     void
+ f_term_setrestore(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+ {
+ #if defined(FEAT_SESSION)
+     buf_T     *buf = term_get_buf(argvars);
+     term_T    *term;
+     char_u    *cmd;
+ 
+     if (buf == NULL)
+       return;
+     term = buf->b_term;
+     vim_free(term->tl_command);
+     cmd = get_tv_string_chk(&argvars[1]);
+     if (cmd != NULL)
+       term->tl_command = vim_strsave(cmd);
+     else
+       term->tl_command = NULL;
+ #endif
+ }
+ 
+ /*
   * "term_start(command, options)" function
   */
      void
***************
*** 4064,4070 ****
                    + JO_EXIT_CB + JO_CLOSE_CALLBACK + JO_OUT_IO,
                JO2_TERM_NAME + JO2_TERM_FINISH + JO2_HIDDEN + JO2_TERM_OPENCMD
                    + JO2_TERM_COLS + JO2_TERM_ROWS + JO2_VERTICAL + JO2_CURWIN
!                   + JO2_CWD + JO2_ENV + JO2_EOF_CHARS) == FAIL)
        return;
  
      if (opt.jo_vertical)
--- 4176,4183 ----
                    + JO_EXIT_CB + JO_CLOSE_CALLBACK + JO_OUT_IO,
                JO2_TERM_NAME + JO2_TERM_FINISH + JO2_HIDDEN + JO2_TERM_OPENCMD
                    + JO2_TERM_COLS + JO2_TERM_ROWS + JO2_VERTICAL + JO2_CURWIN
!                   + JO2_CWD + JO2_ENV + JO2_EOF_CHARS
!                   + JO2_NORESTORE) == FAIL)
        return;
  
      if (opt.jo_vertical)
***************
*** 4566,4571 ****
--- 4679,4685 ----
  {
      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;
*** ../vim-8.0.1591/src/proto/terminal.pro      2018-02-18 22:13:06.261057963 
+0100
--- src/proto/terminal.pro      2018-03-09 19:52:14.374022298 +0100
***************
*** 1,5 ****
--- 1,8 ----
  /* terminal.c */
  void ex_terminal(exarg_T *eap);
+ int term_write_session(FILE *fd, win_T *wp);
+ int term_should_restore(buf_T *buf);
+ void f_term_setrestore(typval_T *argvars, typval_T *rettv);
  void free_terminal(buf_T *buf);
  void write_to_term(buf_T *buffer, char_u *msg, channel_T *channel);
  int term_job_running(term_T *term);
*** ../vim-8.0.1591/src/evalfunc.c      2018-03-04 20:14:08.240064393 +0100
--- src/evalfunc.c      2018-03-09 19:52:07.566063527 +0100
***************
*** 867,872 ****
--- 867,873 ----
      {"term_list",     0, 0, f_term_list},
      {"term_scrape",   2, 2, f_term_scrape},
      {"term_sendkeys", 2, 2, f_term_sendkeys},
+     {"term_setrestore",       2, 2, f_term_setrestore},
      {"term_start",    1, 2, f_term_start},
      {"term_wait",     1, 2, f_term_wait},
  #endif
*** ../vim-8.0.1591/src/structs.h       2018-03-08 21:46:38.878732713 +0100
--- src/structs.h       2018-03-09 21:24:03.572169369 +0100
***************
*** 1706,1712 ****
  #define JO2_HIDDEN        0x0400      /* "hidden" */
  #define JO2_TERM_OPENCMD    0x0800    /* "term_opencmd" */
  #define JO2_EOF_CHARS     0x1000      /* "eof_chars" */
! #define JO2_ALL                   0x1FFF
  
  #define JO_MODE_ALL   (JO_MODE + JO_IN_MODE + JO_OUT_MODE + JO_ERR_MODE)
  #define JO_CB_ALL \
--- 1706,1713 ----
  #define JO2_HIDDEN        0x0400      /* "hidden" */
  #define JO2_TERM_OPENCMD    0x0800    /* "term_opencmd" */
  #define JO2_EOF_CHARS     0x1000      /* "eof_chars" */
! #define JO2_NORESTORE     0x2000      /* "norestore" */
! #define JO2_ALL                   0x2FFF
  
  #define JO_MODE_ALL   (JO_MODE + JO_IN_MODE + JO_OUT_MODE + JO_ERR_MODE)
  #define JO_CB_ALL \
***************
*** 1769,1774 ****
--- 1770,1776 ----
      int               jo_vertical;
      int               jo_curwin;
      int               jo_hidden;
+     int               jo_term_norestore;
      char_u    *jo_term_name;
      char_u    *jo_term_opencmd;
      int               jo_term_finish;
*** ../vim-8.0.1591/src/channel.c       2018-02-13 15:17:49.074578201 +0100
--- src/channel.c       2018-03-09 21:23:25.436407822 +0100
***************
*** 4777,4782 ****
--- 4777,4789 ----
                opt->jo_set |= JO2_HIDDEN;
                opt->jo_hidden = get_tv_number(item);
            }
+           else if (STRCMP(hi->hi_key, "norestore") == 0)
+           {
+               if (!(supported2 & JO2_NORESTORE))
+                   break;
+               opt->jo_set |= JO2_NORESTORE;
+               opt->jo_term_norestore = get_tv_number(item);
+           }
  #endif
            else if (STRCMP(hi->hi_key, "env") == 0)
            {
***************
*** 5470,5475 ****
--- 5477,5483 ----
            goto theend;
        }
  #ifdef USE_ARGV
+       /* This will modify "cmd". */
        if (mch_parse_cmd(cmd, FALSE, &argv, &argc) == FAIL)
            goto theend;
        argv[argc] = NULL;
*** ../vim-8.0.1591/src/testdir/test_terminal.vim       2018-02-19 
23:09:57.385619337 +0100
--- src/testdir/test_terminal.vim       2018-03-09 20:11:04.703195807 +0100
***************
*** 30,42 ****
    return buf
  endfunc
  
- " Stops the shell started by Run_shell_in_terminal().
- func Stop_shell_in_terminal(buf)
-   call term_sendkeys(a:buf, "exit\r")
-   call WaitFor('job_status(g:job) == "dead"')
-   call assert_equal('dead', job_status(g:job))
- endfunc
- 
  func Test_terminal_basic()
    au BufWinEnter * if &buftype == 'terminal' | let b:done = 'yes' | endif
    let buf = Run_shell_in_terminal({})
--- 30,35 ----
*** ../vim-8.0.1591/src/testdir/shared.vim      2018-02-27 21:08:48.272513006 
+0100
--- src/testdir/shared.vim      2018-03-09 20:12:00.362860532 +0100
***************
*** 270,272 ****
--- 270,279 ----
    let line = join(chars, '')
    return matchstr(line, '^.\{-}\ze\s*$')
  endfunc
+ 
+ " Stops the shell running in terminal "buf".
+ func Stop_shell_in_terminal(buf)
+   call term_sendkeys(a:buf, "exit\r")
+   let job = term_getjob(a:buf)
+   call WaitFor({-> job_status(job) == "dead"})
+ endfunc
*** ../vim-8.0.1591/src/testdir/test_mksession.vim      2017-08-30 
21:57:58.003077451 +0200
--- src/testdir/test_mksession.vim      2018-03-09 21:25:55.359468409 +0100
***************
*** 7,12 ****
--- 7,14 ----
    finish
  endif
  
+ source shared.vim
+ 
  func Test_mksession()
    tabnew
    let wrap_save = &wrap
***************
*** 99,104 ****
--- 101,107 ----
    call delete('Xtest_mks.out')
    call delete(tmpfile)
    let &wrap = wrap_save
+   set sessionoptions&
  endfunc
  
  func Test_mksession_winheight()
***************
*** 150,155 ****
--- 153,259 ----
    call delete('Xtest_mks.out')
  endfunc
  
+ if has('terminal')
+ 
+ func Test_mksession_terminal_shell()
+   terminal
+   mksession! Xtest_mks.out
+   let lines = readfile('Xtest_mks.out')
+   let term_cmd = ''
+   for line in lines
+     if line =~ '^terminal'
+       let term_cmd = line
+     elseif line =~ 'badd.*' . &shell
+       call assert_report('unexpected shell line: ' . line)
+     endif
+   endfor
+   call assert_match('terminal ++curwin ++cols=\d\+ ++rows=\d\+\s*$', term_cmd)
+ 
+   call Stop_shell_in_terminal(bufnr('%'))
+   call delete('Xtest_mks.out')
+ endfunc
+ 
+ func Test_mksession_terminal_no_restore_cmdarg()
+   terminal ++norestore
+   mksession! Xtest_mks.out
+   let lines = readfile('Xtest_mks.out')
+   let term_cmd = ''
+   for line in lines
+     if line =~ '^terminal'
+       call assert_report('session must not restore teminal')
+     endif
+   endfor
+ 
+   call Stop_shell_in_terminal(bufnr('%'))
+   call delete('Xtest_mks.out')
+ endfunc
+ 
+ func Test_mksession_terminal_no_restore_funcarg()
+   call term_start(&shell, {'norestore': 1})
+   mksession! Xtest_mks.out
+   let lines = readfile('Xtest_mks.out')
+   let term_cmd = ''
+   for line in lines
+     if line =~ '^terminal'
+       call assert_report('session must not restore teminal')
+     endif
+   endfor
+ 
+   call Stop_shell_in_terminal(bufnr('%'))
+   call delete('Xtest_mks.out')
+ endfunc
+ 
+ func Test_mksession_terminal_no_restore_func()
+   terminal
+   call term_setrestore(bufnr('%'), 'NONE')
+   mksession! Xtest_mks.out
+   let lines = readfile('Xtest_mks.out')
+   let term_cmd = ''
+   for line in lines
+     if line =~ '^terminal'
+       call assert_report('session must not restore teminal')
+     endif
+   endfor
+ 
+   call Stop_shell_in_terminal(bufnr('%'))
+   call delete('Xtest_mks.out')
+ endfunc
+ 
+ func Test_mksession_terminal_no_ssop()
+   terminal
+   set sessionoptions-=terminal
+   mksession! Xtest_mks.out
+   let lines = readfile('Xtest_mks.out')
+   let term_cmd = ''
+   for line in lines
+     if line =~ '^terminal'
+       call assert_report('session must not restore teminal')
+     endif
+   endfor
+ 
+   call Stop_shell_in_terminal(bufnr('%'))
+   call delete('Xtest_mks.out')
+   set sessionoptions&
+ endfunc
+ 
+ func Test_mksession_terminal_restore_other()
+   terminal
+   call term_setrestore(bufnr('%'), 'other')
+   mksession! Xtest_mks.out
+   let lines = readfile('Xtest_mks.out')
+   let term_cmd = ''
+   for line in lines
+     if line =~ '^terminal'
+       let term_cmd = line
+     endif
+   endfor
+   call assert_match('terminal ++curwin ++cols=\d\+ ++rows=\d\+ other', 
term_cmd)
+ 
+   call Stop_shell_in_terminal(bufnr('%'))
+   call delete('Xtest_mks.out')
+ endfunc
+ 
+ endif " has('terminal')
  
  
  " vim: shiftwidth=2 sts=2 expandtab
*** ../vim-8.0.1591/src/version.c       2018-03-08 22:03:09.867578790 +0100
--- src/version.c       2018-03-08 23:25:57.694883335 +0100
***************
*** 768,769 ****
--- 768,771 ----
  {   /* Add new patch number below this line */
+ /**/
+     1592,
  /**/

-- 
I recommend ordering large cargo containers of paper towels to make up
whatever budget underruns you have.  Paper products are always useful and they
have the advantage of being completely flushable if you need to make room in
the storage area later.
                                (Scott Adams - The Dilbert principle)

 /// Bram Moolenaar -- b...@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    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Raspunde prin e-mail lui