Patch 7.4.1262
Problem:    The channel callback is not invoked.
Solution:   Make a list of pending callbacks.
Files:      src/eval.c, src/channel.c, src/proto/channel.pro,
            src/testdir/test_channel.vim


*** ../vim-7.4.1261/src/eval.c  2016-02-04 22:49:45.691504756 +0100
--- src/eval.c  2016-02-04 23:02:24.519676094 +0100
***************
*** 9800,9806 ****
   * Otherwise returns -1.
   */
      static int
! send_common(typval_T *argvars, char_u *text, char *fun)
  {
      int               ch_idx;
      char_u    *callback = NULL;
--- 9800,9806 ----
   * Otherwise returns -1.
   */
      static int
! send_common(typval_T *argvars, char_u *text, int id, char *fun)
  {
      int               ch_idx;
      char_u    *callback = NULL;
***************
*** 9815,9824 ****
        if (callback == NULL)
            return -1;
      }
!     /* Set the callback or clear it. An empty callback means no callback and
!      * not reading the response. */
!     channel_set_req_callback(ch_idx,
!           callback != NULL && *callback == NUL ? NULL : callback);
  
      if (channel_send(ch_idx, text, fun) == OK && callback == NULL)
        return ch_idx;
--- 9815,9824 ----
        if (callback == NULL)
            return -1;
      }
!     /* Set the callback. An empty callback means no callback and not reading
!      * the response. */
!     if (callback != NULL && *callback != NUL)
!       channel_set_req_callback(ch_idx, callback, id);
  
      if (channel_send(ch_idx, text, fun) == OK && callback == NULL)
        return ch_idx;
***************
*** 9845,9851 ****
      if (text == NULL)
        return;
  
!     ch_idx = send_common(argvars, text, "sendexpr");
      vim_free(text);
      if (ch_idx >= 0)
      {
--- 9845,9851 ----
      if (text == NULL)
        return;
  
!     ch_idx = send_common(argvars, text, id, "sendexpr");
      vim_free(text);
      if (ch_idx >= 0)
      {
***************
*** 9883,9889 ****
      rettv->vval.v_string = NULL;
  
      text = get_tv_string_buf(&argvars[1], buf);
!     ch_idx = send_common(argvars, text, "sendraw");
      if (ch_idx >= 0)
        rettv->vval.v_string = channel_read_block(ch_idx);
  }
--- 9883,9889 ----
      rettv->vval.v_string = NULL;
  
      text = get_tv_string_buf(&argvars[1], buf);
!     ch_idx = send_common(argvars, text, 0, "sendraw");
      if (ch_idx >= 0)
        rettv->vval.v_string = channel_read_block(ch_idx);
  }
*** ../vim-7.4.1261/src/channel.c       2016-02-04 22:49:45.691504756 +0100
--- src/channel.c       2016-02-05 20:40:09.851242051 +0100
***************
*** 84,89 ****
--- 84,98 ----
  };
  typedef struct jsonqueue jsonq_T;
  
+ struct cbqueue
+ {
+     char_u            *callback;
+     int                       seq_nr;
+     struct cbqueue    *next;
+     struct cbqueue    *prev;
+ };
+ typedef struct cbqueue cbq_T;
+ 
  typedef struct {
      sock_T    ch_fd;  /* the socket, -1 for a closed channel */
      int             ch_idx;   /* used by channel_poll_setup() */
***************
*** 106,112 ****
      void      (*ch_close_cb)(void); /* callback for when channel is closed */
  
      char_u    *ch_callback;   /* function to call when a msg is not handled */
!     char_u    *ch_req_callback;       /* function to call for current request 
*/
  
      int             ch_json_mode;     /* TRUE for a json channel */
      jsonq_T   ch_json_head;   /* dummy node, header for circular queue */
--- 115,121 ----
      void      (*ch_close_cb)(void); /* callback for when channel is closed */
  
      char_u    *ch_callback;   /* function to call when a msg is not handled */
!     cbq_T     ch_cb_head;     /* dummy node for pre-request callbacks */
  
      int             ch_json_mode;     /* TRUE for a json channel */
      jsonq_T   ch_json_head;   /* dummy node, header for circular queue */
***************
*** 168,173 ****
--- 177,184 ----
      /* initialize circular queues */
      ch->ch_head.next = &ch->ch_head;
      ch->ch_head.prev = &ch->ch_head;
+     ch->ch_cb_head.next = &ch->ch_cb_head;
+     ch->ch_cb_head.prev = &ch->ch_cb_head;
      ch->ch_json_head.next = &ch->ch_json_head;
      ch->ch_json_head.prev = &ch->ch_json_head;
  
***************
*** 426,440 ****
  }
  
  /*
!  * Set the callback for channel "idx" for the next response.
   */
      void
! channel_set_req_callback(int idx, char_u *callback)
  {
!     /* TODO: make a list of callbacks */
!     vim_free(channels[idx].ch_req_callback);
!     channels[idx].ch_req_callback = callback == NULL
!                                              ? NULL : vim_strsave(callback);
  }
  
  /*
--- 437,459 ----
  }
  
  /*
!  * Set the callback for channel "idx" for the response with "id".
   */
      void
! channel_set_req_callback(int idx, char_u *callback, int id)
  {
!     cbq_T *cbhead = &channels[idx].ch_cb_head;
!     cbq_T *item = (cbq_T *)alloc((int)sizeof(cbq_T));
! 
!     if (item != NULL)
!     {
!       item->callback = vim_strsave(callback);
!       item->seq_nr = id;
!       item->prev = cbhead->prev;
!       cbhead->prev = item;
!       item->next = cbhead;
!       item->prev->next = item;
!     }
  }
  
  /*
***************
*** 599,604 ****
--- 618,636 ----
  
  /*
   * Remove "node" from the queue that it is in and free it.
+  * Also frees the contained callback name.
+  */
+     static void
+ remove_cb_node(cbq_T *node)
+ {
+     node->prev->next = node->next;
+     node->next->prev = node->prev;
+     vim_free(node->callback);
+     vim_free(node);
+ }
+ 
+ /*
+  * Remove "node" from the queue that it is in and free it.
   * Caller should have freed or used node->value.
   */
      static void
***************
*** 628,635 ****
        typval_T    *tv = &l->lv_first->li_tv;
  
        if ((id > 0 && tv->v_type == VAR_NUMBER && tv->vval.v_number == id)
!             || (id <= 0
!                     && (tv->v_type != VAR_NUMBER || tv->vval.v_number < 0)))
        {
            *rettv = item->value;
            remove_json_node(item);
--- 660,666 ----
        typval_T    *tv = &l->lv_first->li_tv;
  
        if ((id > 0 && tv->v_type == VAR_NUMBER && tv->vval.v_number == id)
!             || id <= 0)
        {
            *rettv = item->value;
            remove_json_node(item);
***************
*** 742,750 ****
      typval_T  *typetv;
      typval_T  argv[3];
      int               seq_nr = -1;
!     int               json_mode = channels[idx].ch_json_mode;
  
!     if (channels[idx].ch_close_cb != NULL)
        /* this channel is handled elsewhere (netbeans) */
        return FALSE;
  
--- 773,782 ----
      typval_T  *typetv;
      typval_T  argv[3];
      int               seq_nr = -1;
!     channel_T *channel = &channels[idx];
!     int               json_mode = channel->ch_json_mode;
  
!     if (channel->ch_close_cb != NULL)
        /* this channel is handled elsewhere (netbeans) */
        return FALSE;
  
***************
*** 804,820 ****
        argv[1].vval.v_string = msg;
      }
  
!     if (channels[idx].ch_req_callback != NULL && seq_nr != 0)
      {
!       /* TODO: check the sequence number */
!       /* invoke the one-time callback */
!       invoke_callback(idx, channels[idx].ch_req_callback, argv);
!       channels[idx].ch_req_callback = NULL;
      }
!     else if (channels[idx].ch_callback != NULL)
      {
        /* invoke the channel callback */
!       invoke_callback(idx, channels[idx].ch_callback, argv);
      }
      /* else: drop the message TODO: give error */
  
--- 836,862 ----
        argv[1].vval.v_string = msg;
      }
  
!     if (seq_nr > 0)
      {
!       cbq_T *cbhead = &channel->ch_cb_head;
!       cbq_T *cbitem = cbhead->next;
! 
!       /* invoke the one-time callback with the matching nr */
!       while (cbitem != cbhead)
!       {
!           if (cbitem->seq_nr == seq_nr)
!           {
!               invoke_callback(idx, cbitem->callback, argv);
!               remove_cb_node(cbitem);
!               break;
!           }
!           cbitem = cbitem->next;
!       }
      }
!     else if (channel->ch_callback != NULL)
      {
        /* invoke the channel callback */
!       invoke_callback(idx, channel->ch_callback, argv);
      }
      /* else: drop the message TODO: give error */
  
***************
*** 844,849 ****
--- 886,892 ----
  {
      channel_T *channel = &channels[idx];
      jsonq_T   *jhead;
+     cbq_T     *cbhead;
  
      if (channel->ch_fd >= 0)
      {
***************
*** 859,864 ****
--- 902,911 ----
        while (channel_peek(idx) != NULL)
            vim_free(channel_get(idx));
  
+       cbhead = &channel->ch_cb_head;
+       while (cbhead->next != cbhead)
+           remove_cb_node(cbhead->next);
+ 
        jhead = &channel->ch_json_head;
        while (jhead->next != jhead)
        {
*** ../vim-7.4.1261/src/proto/channel.pro       2016-02-04 22:49:45.691504756 
+0100
--- src/proto/channel.pro       2016-02-04 23:06:50.669504187 +0100
***************
*** 3,9 ****
  int channel_open(char *hostname, int port_in, void (*close_cb)(void));
  void channel_set_json_mode(int idx, int json_mode);
  void channel_set_callback(int idx, char_u *callback);
! void channel_set_req_callback(int idx, char_u *callback);
  char_u *channel_get(int idx);
  int channel_collapse(int idx);
  int channel_is_open(int idx);
--- 3,9 ----
  int channel_open(char *hostname, int port_in, void (*close_cb)(void));
  void channel_set_json_mode(int idx, int json_mode);
  void channel_set_callback(int idx, char_u *callback);
! void channel_set_req_callback(int idx, char_u *callback, int id);
  char_u *channel_get(int idx);
  int channel_collapse(int idx);
  int channel_is_open(int idx);
*** ../vim-7.4.1261/src/testdir/test_channel.vim        2016-02-04 
22:09:44.692012667 +0100
--- src/testdir/test_channel.vim        2016-02-05 20:45:24.675916217 +0100
***************
*** 69,74 ****
--- 69,81 ----
    endif
  endfunc
  
+ let s:responseHandle = -1
+ let s:responseMsg = ''
+ func s:RequestHandler(handle, msg)
+   let s:responseHandle = a:handle
+   let s:responseMsg = a:msg
+ endfunc
+ 
  func Test_communicate()
    let handle = s:start_server()
    if handle < 0
***************
*** 86,91 ****
--- 93,104 ----
    call assert_equal('added1', getline(line('$') - 1))
    call assert_equal('added2', getline('$'))
  
+   " Send a request with a specific handler.
+   call ch_sendexpr(handle, 'hello!', 's:RequestHandler')
+   sleep 10m
+   call assert_equal(handle, s:responseHandle)
+   call assert_equal('got it', s:responseMsg)
+ 
    " Send an eval request that works.
    call assert_equal('ok', ch_sendexpr(handle, 'eval-works'))
    sleep 10m
*** ../vim-7.4.1261/src/version.c       2016-02-04 22:49:45.695504713 +0100
--- src/version.c       2016-02-05 20:38:23.200369375 +0100
***************
*** 744,745 ****
--- 744,747 ----
  {   /* Add new patch number below this line */
+ /**/
+     1262,
  /**/

-- 
Drink wet cement and get really stoned.

 /// 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