To: vim_dev@googlegroups.com Subject: Patch 7.4.2258 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 7.4.2258 Problem: Two JSON messages are sent without a separator. Solution: Separate messages with a NL. (closes #1001) Files: src/json.c, src/channel.c, src/vim.h, src/testdir/test_channel.py, src/testdir/test_channel.vim, runtime/doc/channel.txt *** ../vim-7.4.2257/src/json.c 2016-07-01 18:16:47.493936250 +0200 --- src/json.c 2016-08-26 17:40:00.359878833 +0200 *************** *** 23,31 **** /* * Encode "val" into a JSON format string. * The result is in allocated memory. * The result is empty when encoding fails. ! * "options" can be JSON_JS or zero; */ char_u * json_encode(typval_T *val, int options) --- 23,48 ---- /* * Encode "val" into a JSON format string. + * The result is added to "gap" + * Returns FAIL on failure and makes gap->ga_data empty. + */ + static int + json_encode_gap(garray_T *gap, typval_T *val, int options) + { + if (json_encode_item(gap, val, get_copyID(), options) == FAIL) + { + ga_clear(gap); + gap->ga_data = vim_strsave((char_u *)""); + return FAIL; + } + return OK; + } + + /* + * Encode "val" into a JSON format string. * The result is in allocated memory. * The result is empty when encoding fails. ! * "options" can contain JSON_JS, JSON_NO_NONE and JSON_NL. */ char_u * json_encode(typval_T *val, int options) *************** *** 34,50 **** /* Store bytes in the growarray. */ ga_init2(&ga, 1, 4000); ! if (json_encode_item(&ga, val, get_copyID(), options) == FAIL) ! { ! vim_free(ga.ga_data); ! return vim_strsave((char_u *)""); ! } return ga.ga_data; } /* * Encode ["nr", "val"] into a JSON format string in allocated memory. ! * "options" can be JSON_JS or zero; * Returns NULL when out of memory. */ char_u * --- 51,63 ---- /* Store bytes in the growarray. */ ga_init2(&ga, 1, 4000); ! json_encode_gap(&ga, val, options); return ga.ga_data; } /* * Encode ["nr", "val"] into a JSON format string in allocated memory. ! * "options" can contain JSON_JS, JSON_NO_NONE and JSON_NL. * Returns NULL when out of memory. */ char_u * *************** *** 52,58 **** { typval_T listtv; typval_T nrtv; ! char_u *text; nrtv.v_type = VAR_NUMBER; nrtv.vval.v_number = nr; --- 65,71 ---- { typval_T listtv; typval_T nrtv; ! garray_T ga; nrtv.v_type = VAR_NUMBER; nrtv.vval.v_number = nr; *************** *** 65,73 **** return NULL; } ! text = json_encode(&listtv, options); list_unref(listtv.vval.v_list); ! return text; } static void --- 78,88 ---- return NULL; } ! ga_init2(&ga, 1, 4000); ! if (json_encode_gap(&ga, &listtv, options) == OK && (options & JSON_NL)) ! ga_append(&ga, '\n'); list_unref(listtv.vval.v_list); ! return ga.ga_data; } static void *** ../vim-7.4.2257/src/channel.c 2016-08-24 22:11:52.329278078 +0200 --- src/channel.c 2016-08-26 16:56:29.486541260 +0200 *************** *** 2165,2171 **** int id = argv[id_idx].vval.v_number; if (tv != NULL) ! json = json_encode_nr_expr(id, tv, options); if (tv == NULL || (json != NULL && *json == NUL)) { /* If evaluation failed or the result can't be encoded --- 2165,2171 ---- int id = argv[id_idx].vval.v_number; if (tv != NULL) ! json = json_encode_nr_expr(id, tv, options | JSON_NL); if (tv == NULL || (json != NULL && *json == NUL)) { /* If evaluation failed or the result can't be encoded *************** *** 2175,2181 **** err_tv.v_type = VAR_STRING; err_tv.vval.v_string = (char_u *)"ERROR"; tv = &err_tv; ! json = json_encode_nr_expr(id, tv, options); } if (json != NULL) { --- 2175,2181 ---- err_tv.v_type = VAR_STRING; err_tv.vval.v_string = (char_u *)"ERROR"; tv = &err_tv; ! json = json_encode_nr_expr(id, tv, options | JSON_NL); } if (json != NULL) { *************** *** 3500,3506 **** id = ++channel->ch_last_msg_id; text = json_encode_nr_expr(id, &argvars[1], ! ch_mode == MODE_JS ? JSON_JS : 0); if (text == NULL) return; --- 3500,3506 ---- id = ++channel->ch_last_msg_id; text = json_encode_nr_expr(id, &argvars[1], ! (ch_mode == MODE_JS ? JSON_JS : 0) | JSON_NL); if (text == NULL) return; *** ../vim-7.4.2257/src/vim.h 2016-08-25 23:02:08.541261676 +0200 --- src/vim.h 2016-08-26 16:54:12.703761178 +0200 *************** *** 2440,2445 **** --- 2440,2446 ---- /* Options for json_encode() and json_decode. */ #define JSON_JS 1 /* use JS instead of JSON */ #define JSON_NO_NONE 2 /* v:none item not allowed */ + #define JSON_NL 4 /* append a NL */ /* Used for flags of do_in_path() */ #define DIP_ALL 0x01 /* all matches, not just the first one */ *** ../vim-7.4.2257/src/testdir/test_channel.py 2016-03-26 22:56:41.879646383 +0100 --- src/testdir/test_channel.py 2016-08-26 17:22:37.232844199 +0200 *************** *** 38,52 **** print("received: {0}".format(received)) # We may receive two messages at once. Take the part up to the ! # matching "]" (recognized by finding "]["). todo = received while todo != '': ! splitidx = todo.find('][') if splitidx < 0: used = todo todo = '' else: ! used = todo[:splitidx + 1] todo = todo[splitidx + 1:] if used != received: print("using: {0}".format(used)) --- 38,52 ---- print("received: {0}".format(received)) # We may receive two messages at once. Take the part up to the ! # newline, which should be after the matching "]". todo = received while todo != '': ! splitidx = todo.find('\n') if splitidx < 0: used = todo todo = '' else: ! used = todo[:splitidx] todo = todo[splitidx + 1:] if used != received: print("using: {0}".format(used)) *** ../vim-7.4.2257/src/testdir/test_channel.vim 2016-07-31 14:17:22.903502231 +0200 --- src/testdir/test_channel.vim 2016-08-26 17:41:05.211322138 +0200 *************** *** 55,60 **** --- 55,71 ---- call WaitFor('exists("g:split")') call assert_equal(123, g:split) + " string with ][ should work + call assert_equal('this][that', ch_evalexpr(handle, 'echo this][that')) + + " sending three messages quickly then reading should work + for i in range(3) + call ch_sendexpr(handle, 'echo hello ' . i) + endfor + call assert_equal('hello 0', ch_read(handle)[1]) + call assert_equal('hello 1', ch_read(handle)[1]) + call assert_equal('hello 2', ch_read(handle)[1]) + " Request that triggers sending two ex commands. These will usually be " handled before getting the response, but it's not guaranteed, thus wait a " tiny bit for the commands to get executed. *** ../vim-7.4.2257/runtime/doc/channel.txt 2016-05-29 16:16:39.381326993 +0200 --- runtime/doc/channel.txt 2016-08-26 17:55:36.543677513 +0200 *************** *** 258,266 **** This way Vim knows which sent message matches with which received message and can call the right handler. Also when the messages arrive out of order. The sender must always send valid JSON to Vim. Vim can check for the end of the message by parsing the JSON. It will only accept the message if the end ! was received. When the process wants to send a message to Vim without first receiving a message, it must use the number zero: --- 247,261 ---- This way Vim knows which sent message matches with which received message and can call the right handler. Also when the messages arrive out of order. + A newline character is terminating the JSON text. This can be used to + separate the read text. For example, in Python: + splitidx = read_text.find('\n') + message = read_text[:splitidx] + rest = read_text[splitidx + 1:] + The sender must always send valid JSON to Vim. Vim can check for the end of the message by parsing the JSON. It will only accept the message if the end ! was received. A newline after the message is optional. When the process wants to send a message to Vim without first receiving a message, it must use the number zero: *** ../vim-7.4.2257/src/version.c 2016-08-26 16:38:58.119952135 +0200 --- src/version.c 2016-08-26 17:55:54.967515847 +0200 *************** *** 765,766 **** --- 765,768 ---- { /* Add new patch number below this line */ + /**/ + 2258, /**/ -- hundred-and-one symptoms of being an internet addict: 90. Instead of calling you to dinner, your spouse sends e-mail. /// 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 ///