Patch 7.4.1380
Problem:    The job exit callback is not implemented.
Solution:   Add the "exit-cb" option.
Files:      src/structs.h, src/eval.c, src/channel.c, src/proto/eval.pro,
            src/misc2.c, src/macros.h, src/testdir/test_channel.vim


*** ../vim-7.4.1379/src/structs.h       2016-02-21 16:40:07.084383820 +0100
--- src/structs.h       2016-02-21 18:13:31.002125745 +0100
***************
*** 1265,1270 ****
--- 1265,1271 ----
  #endif
      jobstatus_T       jv_status;
      char_u    *jv_stoponexit; /* allocated */
+     char_u    *jv_exit_cb;    /* allocated */
  
      int               jv_refcount;    /* reference count */
      channel_T *jv_channel;    /* channel for I/O, reference counted */
***************
*** 1390,1395 ****
--- 1391,1397 ----
  #define JO_PART               0x0800  /* "part" */
  #define JO_ID         0x1000  /* "id" */
  #define JO_STOPONEXIT 0x2000  /* "stoponexit" */
+ #define JO_EXIT_CB    0x4000  /* "exit-cb" */
  #define JO_ALL                0xffffff
  
  #define JO_MODE_ALL   (JO_MODE + JO_IN_MODE + JO_OUT_MODE + JO_ERR_MODE)
***************
*** 1418,1423 ****
--- 1420,1427 ----
      int               jo_id;
      char_u    jo_soe_buf[NUMBUFLEN];
      char_u    *jo_stoponexit;
+     char_u    jo_ecb_buf[NUMBUFLEN];
+     char_u    *jo_exit_cb;
  } jobopt_T;
  
  
*** ../vim-7.4.1379/src/eval.c  2016-02-21 16:40:07.084383820 +0100
--- src/eval.c  2016-02-21 19:07:47.668211225 +0100
***************
*** 7774,7779 ****
--- 7774,7780 ----
        job->jv_prev->jv_next = job->jv_next;
  
      vim_free(job->jv_stoponexit);
+     vim_free(job->jv_exit_cb);
      vim_free(job);
  }
  
***************
*** 7781,7787 ****
  job_unref(job_T *job)
  {
      if (job != NULL && --job->jv_refcount <= 0)
!       job_free(job);
  }
  
  /*
--- 7782,7794 ----
  job_unref(job_T *job)
  {
      if (job != NULL && --job->jv_refcount <= 0)
!     {
!       /* Do not free the job when it has not ended yet and there is a
!        * "stoponexit" flag or an exit callback. */
!       if (job->jv_status != JOB_STARTED
!               || (job->jv_stoponexit == NULL && job->jv_exit_cb == NULL))
!           job_free(job);
!     }
  }
  
  /*
***************
*** 7819,7824 ****
--- 7826,7839 ----
        else
            job->jv_stoponexit = vim_strsave(opt->jo_stoponexit);
      }
+     if (opt->jo_set & JO_EXIT_CB)
+     {
+       vim_free(job->jv_exit_cb);
+       if (opt->jo_exit_cb == NULL || *opt->jo_exit_cb == NUL)
+           job->jv_exit_cb = NULL;
+       else
+           job->jv_exit_cb = vim_strsave(opt->jo_exit_cb);
+     }
  }
  
  /*
***************
*** 7830,7836 ****
      job_T     *job;
  
      for (job = first_job; job != NULL; job = job->jv_next)
!       if (job->jv_stoponexit != NULL && *job->jv_stoponexit != NUL)
            mch_stop_job(job, job->jv_stoponexit);
  }
  #endif
--- 7845,7851 ----
      job_T     *job;
  
      for (job = first_job; job != NULL; job = job->jv_next)
!       if (job->jv_status == JOB_STARTED && job->jv_stoponexit != NULL)
            mch_stop_job(job, job->jv_stoponexit);
  }
  #endif
***************
*** 10030,10036 ****
                opt->jo_out_cb = get_callback(item);
                if (opt->jo_out_cb == NULL)
                {
!                   EMSG2(_(e_invarg2), "out-db");
                    return FAIL;
                }
            }
--- 10045,10051 ----
                opt->jo_out_cb = get_callback(item);
                if (opt->jo_out_cb == NULL)
                {
!                   EMSG2(_(e_invarg2), "out-cb");
                    return FAIL;
                }
            }
***************
*** 10108,10113 ****
--- 10123,10140 ----
                    return FAIL;
                }
            }
+           else if (STRCMP(hi->hi_key, "exit-cb") == 0)
+           {
+               if (!(supported & JO_EXIT_CB))
+                   break;
+               opt->jo_set |= JO_EXIT_CB;
+               opt->jo_exit_cb = get_tv_string_buf_chk(item, opt->jo_ecb_buf);
+               if (opt->jo_ecb_buf == NULL)
+               {
+                   EMSG2(_(e_invarg2), "exit-cb");
+                   return FAIL;
+               }
+           }
            else
                break;
            --todo;
***************
*** 14771,14777 ****
      dict_list(argvars, rettv, 2);
  }
  
! #ifdef FEAT_JOB
  /*
   * Get the job from the argument.
   * Returns NULL if the job is invalid.
--- 14798,14804 ----
      dict_list(argvars, rettv, 2);
  }
  
! #if defined(FEAT_JOB) || defined(PROTO)
  /*
   * Get the job from the argument.
   * Returns NULL if the job is invalid.
***************
*** 14824,14830 ****
      if (job == NULL)
        return;
      clear_job_options(&opt);
!     if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT) == FAIL)
        return;
      job_set_options(job, &opt);
  }
--- 14851,14857 ----
      if (job == NULL)
        return;
      clear_job_options(&opt);
!     if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB) == 
FAIL)
        return;
      job_set_options(job, &opt);
  }
***************
*** 14858,14864 ****
      clear_job_options(&opt);
      opt.jo_mode = MODE_NL;
      if (get_job_options(&argvars[1], &opt,
!           JO_MODE_ALL + JO_CB_ALL + JO_TIMEOUT_ALL + JO_STOPONEXIT) == FAIL)
        return;
      job_set_options(job, &opt);
  
--- 14885,14892 ----
      clear_job_options(&opt);
      opt.jo_mode = MODE_NL;
      if (get_job_options(&argvars[1], &opt,
!           JO_MODE_ALL + JO_CB_ALL + JO_TIMEOUT_ALL
!                                       + JO_STOPONEXIT + JO_EXIT_CB) == FAIL)
        return;
      job_set_options(job, &opt);
  
***************
*** 14959,14964 ****
--- 14987,15063 ----
  }
  
  /*
+  * Get the status of "job" and invoke the exit callback when needed.
+  * The returned string is not allocated.
+  */
+     static char *
+ job_status(job_T *job)
+ {
+     char      *result;
+ 
+     if (job->jv_status == JOB_ENDED)
+       /* No need to check, dead is dead. */
+       result = "dead";
+     else if (job->jv_status == JOB_FAILED)
+       result = "fail";
+     else
+     {
+       result = mch_job_status(job);
+ # ifdef FEAT_CHANNEL
+       if (job->jv_status == JOB_ENDED)
+           ch_log(job->jv_channel, "Job ended");
+ # endif
+       if (job->jv_status == JOB_ENDED && job->jv_exit_cb != NULL)
+       {
+           typval_T    argv[3];
+           typval_T    rettv;
+           int         dummy;
+ 
+           /* invoke the exit callback */
+           argv[0].v_type = VAR_JOB;
+           argv[0].vval.v_job = job;
+           argv[1].v_type = VAR_NUMBER;
+           argv[1].vval.v_number = job->jv_exitval;
+           call_func(job->jv_exit_cb, (int)STRLEN(job->jv_exit_cb),
+                                &rettv, 2, argv, 0L, 0L, &dummy, TRUE, NULL);
+           clear_tv(&rettv);
+       }
+       if (job->jv_status == JOB_ENDED && job->jv_refcount == 0)
+       {
+           /* The job already was unreferenced, now that it ended it can be
+            * freed. Careful: caller must not use "job" after this! */
+           job_free(job);
+       }
+     }
+     return result;
+ }
+ 
+ /*
+  * Called once in a while: check if any jobs with an "exit-cb" have ended.
+  */
+     void
+ job_check_ended()
+ {
+     static time_t   last_check = 0;
+     time_t        now;
+     job_T         *job;
+     job_T         *next;
+ 
+     /* Only do this once in 10 seconds. */
+     now = time(NULL);
+     if (last_check + 10 < now)
+     {
+       last_check = now;
+       for (job = first_job; job != NULL; job = next)
+       {
+           next = job->jv_next;
+           if (job->jv_status == JOB_STARTED && job->jv_exit_cb != NULL)
+               job_status(job); /* may free "job" */
+       }
+     }
+ }
+ 
+ /*
   * "job_status()" function
   */
      static void
***************
*** 14969,14981 ****
  
      if (job != NULL)
      {
!       if (job->jv_status == JOB_ENDED)
!           /* No need to check, dead is dead. */
!           result = "dead";
!       else if (job->jv_status == JOB_FAILED)
!           result = "fail";
!       else
!           result = mch_job_status(job);
        rettv->v_type = VAR_STRING;
        rettv->vval.v_string = vim_strsave((char_u *)result);
      }
--- 15068,15074 ----
  
      if (job != NULL)
      {
!       result = job_status(job);
        rettv->v_type = VAR_STRING;
        rettv->vval.v_string = vim_strsave((char_u *)result);
      }
***************
*** 22857,22863 ****
        case VAR_JOB:
  #ifdef FEAT_JOB
            to->vval.v_job = from->vval.v_job;
!           ++to->vval.v_job->jv_refcount;
            break;
  #endif
        case VAR_CHANNEL:
--- 22950,22957 ----
        case VAR_JOB:
  #ifdef FEAT_JOB
            to->vval.v_job = from->vval.v_job;
!           if (to->vval.v_job != NULL)
!               ++to->vval.v_job->jv_refcount;
            break;
  #endif
        case VAR_CHANNEL:
*** ../vim-7.4.1379/src/channel.c       2016-02-21 17:20:51.175001604 +0100
--- src/channel.c       2016-02-21 18:08:31.777248426 +0100
***************
*** 833,838 ****
--- 833,840 ----
  
      call_func(callback, (int)STRLEN(callback),
                             &rettv, 2, argv, 0L, 0L, &dummy, TRUE, NULL);
+     clear_tv(&rettv);
+ 
      /* If an echo command was used the cursor needs to be put back where
       * it belongs. */
      setcursor();
*** ../vim-7.4.1379/src/proto/eval.pro  2016-02-21 16:40:07.088383778 +0100
--- src/proto/eval.pro  2016-02-21 18:40:11.457437953 +0100
***************
*** 87,92 ****
--- 87,93 ----
  int call_func(char_u *funcname, int len, typval_T *rettv, int argcount, 
typval_T *argvars, linenr_T firstline, linenr_T lastline, int *doesrange, int 
evaluate, dict_T *selfdict);
  int func_call(char_u *name, typval_T *args, dict_T *selfdict, typval_T 
*rettv);
  void dict_extend(dict_T *d1, dict_T *d2, char_u *action);
+ void job_check_ended(void);
  void mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv);
  float_T vim_round(float_T f);
  long do_searchpair(char_u *spat, char_u *mpat, char_u *epat, int dir, char_u 
*skip, int flags, pos_T *match_pos, linenr_T lnum_stop, long time_limit);
*** ../vim-7.4.1379/src/misc2.c 2016-02-21 17:20:51.179001562 +0100
--- src/misc2.c 2016-02-21 18:39:22.401949173 +0100
***************
*** 6256,6260 ****
--- 6256,6264 ----
      /* Process the queued clientserver messages. */
      server_parse_messages();
  # endif
+ # ifdef FEAT_JOB
+     /* Check if any jobs have ended. */
+     job_check_ended();
+ # endif
  }
  #endif
*** ../vim-7.4.1379/src/macros.h        2016-01-24 20:36:18.862082391 +0100
--- src/macros.h        2016-02-21 18:40:04.989505356 +0100
***************
*** 317,322 ****
  # define PLINES_NOFILL(x) plines(x)
  #endif
  
! #if defined(FEAT_CHANNEL) || defined(FEAT_CLIENTSERVER)
  # define MESSAGE_QUEUE
  #endif
--- 317,322 ----
  # define PLINES_NOFILL(x) plines(x)
  #endif
  
! #if defined(FEAT_CHANNEL) || defined(FEAT_JOB) || defined(FEAT_CLIENTSERVER)
  # define MESSAGE_QUEUE
  #endif
*** ../vim-7.4.1379/src/testdir/test_channel.vim        2016-02-21 
16:40:07.088383778 +0100
--- src/testdir/test_channel.vim        2016-02-21 19:02:15.463664885 +0100
***************
*** 468,470 ****
--- 468,495 ----
    call ch_log('Test_call()')
    call s:run_server('s:test_call')
  endfunc
+ 
+ """""""""
+ 
+ let s:job_ret = 'not yet'
+ function MyExitCb(job, status)
+   let s:job_ret = 'done'
+ endfunc
+ 
+ function s:test_exit_callback(port)
+   call job_setoptions(s:job, {'exit-cb': 'MyExitCb'})
+   let s:exit_job = s:job
+ endfunc
+ 
+ func Test_exit_callback()
+   if has('job')
+     call s:run_server('s:test_exit_callback')
+ 
+     " the job may take a little while to exit
+     sleep 50m
+ 
+     " calling job_status() triggers the callback
+     call job_status(s:exit_job)
+     call assert_equal('done', s:job_ret)
+   endif
+ endfunc
*** ../vim-7.4.1379/src/version.c       2016-02-21 17:20:51.179001562 +0100
--- src/version.c       2016-02-21 18:10:41.599893524 +0100
***************
*** 749,750 ****
--- 749,752 ----
  {   /* Add new patch number below this line */
+ /**/
+     1380,
  /**/

-- 
WOMAN:   King of the who?
ARTHUR:  The Britons.
WOMAN:   Who are the Britons?
ARTHUR:  Well, we all are. we're all Britons and I am your king.
                                  The Quest for the Holy Grail (Monty Python)

 /// Bram Moolenaar -- [email protected] -- 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 [email protected].
For more options, visit https://groups.google.com/d/optout.

Raspunde prin e-mail lui