Mercurial > vim
comparison src/channel.c @ 8159:d0958e22d9ff v7.4.1373
commit https://github.com/vim/vim/commit/ece61b06ef4726515177c9b293e1c20d2122a73f
Author: Bram Moolenaar <Bram@vim.org>
Date: Sat Feb 20 21:39:05 2016 +0100
patch 7.4.1373
Problem: Calling a Vim function over a channel requires turning the
arguments into a string.
Solution: Add the "call" command. (Damien) Also merge "expr" and "eval"
into one.
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Sat, 20 Feb 2016 21:45:04 +0100 |
parents | 74b44d06d3c7 |
children | 973686665238 |
comparison
equal
deleted
inserted
replaced
8158:75ab0b5bb16e | 8159:d0958e22d9ff |
---|---|
1078 item = item->jq_next; | 1078 item = item->jq_next; |
1079 } | 1079 } |
1080 return FAIL; | 1080 return FAIL; |
1081 } | 1081 } |
1082 | 1082 |
1083 #define CH_JSON_MAX_ARGS 4 | |
1084 | |
1083 /* | 1085 /* |
1084 * Execute a command received over "channel"/"part" | 1086 * Execute a command received over "channel"/"part" |
1085 * "cmd" is the command string, "arg2" the second argument. | 1087 * "argv[0]" is the command string. |
1086 * "arg3" is the third argument, NULL if missing. | 1088 * "argv[1]" etc. have further arguments, type is VAR_UNKNOWN if missing. |
1087 */ | 1089 */ |
1088 static void | 1090 static void |
1089 channel_exe_cmd( | 1091 channel_exe_cmd(channel_T *channel, int part, typval_T *argv) |
1090 channel_T *channel, | 1092 { |
1091 int part, | 1093 char_u *cmd = argv[0].vval.v_string; |
1092 char_u *cmd, | 1094 char_u *arg; |
1093 typval_T *arg2, | 1095 int options = channel->ch_part[part].ch_mode == MODE_JS ? JSON_JS : 0; |
1094 typval_T *arg3) | 1096 |
1095 { | 1097 if (argv[1].v_type != VAR_STRING) |
1096 char_u *arg; | 1098 { |
1097 | 1099 ch_error(channel, "received command with non-string argument"); |
1098 if (arg2->v_type != VAR_STRING) | |
1099 { | |
1100 if (p_verbose > 2) | 1100 if (p_verbose > 2) |
1101 EMSG("E903: received ex command with non-string argument"); | 1101 EMSG("E903: received command with non-string argument"); |
1102 return; | 1102 return; |
1103 } | 1103 } |
1104 arg = arg2->vval.v_string; | 1104 arg = argv[1].vval.v_string; |
1105 if (arg == NULL) | 1105 if (arg == NULL) |
1106 arg = (char_u *)""; | 1106 arg = (char_u *)""; |
1107 | 1107 |
1108 if (STRCMP(cmd, "ex") == 0) | 1108 if (STRCMP(cmd, "ex") == 0) |
1109 { | 1109 { |
1133 gui_update_cursor(FALSE, FALSE); | 1133 gui_update_cursor(FALSE, FALSE); |
1134 gui_mch_flush(); | 1134 gui_mch_flush(); |
1135 } | 1135 } |
1136 #endif | 1136 #endif |
1137 } | 1137 } |
1138 else if (STRCMP(cmd, "expr") == 0 || STRCMP(cmd, "eval") == 0) | 1138 else if (STRCMP(cmd, "expr") == 0 || STRCMP(cmd, "call") == 0) |
1139 { | 1139 { |
1140 int is_eval = cmd[1] == 'v'; | 1140 int is_call = cmd[0] == 'c'; |
1141 | 1141 int id_idx = is_call ? 3 : 2; |
1142 if (is_eval && (arg3 == NULL || arg3->v_type != VAR_NUMBER)) | 1142 |
1143 { | 1143 if (argv[id_idx].v_type != VAR_UNKNOWN |
1144 && argv[id_idx].v_type != VAR_NUMBER) | |
1145 { | |
1146 ch_error(channel, "last argument for expr/call must be a number"); | |
1144 if (p_verbose > 2) | 1147 if (p_verbose > 2) |
1145 EMSG("E904: third argument for eval must be a number"); | 1148 EMSG("E904: last argument for expr/call must be a number"); |
1149 } | |
1150 else if (is_call && argv[2].v_type != VAR_LIST) | |
1151 { | |
1152 ch_error(channel, "third argument for call must be a list"); | |
1153 if (p_verbose > 2) | |
1154 EMSG("E904: third argument for call must be a list"); | |
1146 } | 1155 } |
1147 else | 1156 else |
1148 { | 1157 { |
1149 typval_T *tv; | 1158 typval_T *tv; |
1159 typval_T res_tv; | |
1150 typval_T err_tv; | 1160 typval_T err_tv; |
1151 char_u *json = NULL; | 1161 char_u *json = NULL; |
1152 int options = channel->ch_part[part].ch_mode == MODE_JS | |
1153 ? JSON_JS : 0; | |
1154 | 1162 |
1155 /* Don't pollute the display with errors. */ | 1163 /* Don't pollute the display with errors. */ |
1156 ++emsg_skip; | 1164 ++emsg_skip; |
1157 tv = eval_expr(arg, NULL); | 1165 if (!is_call) |
1158 if (is_eval) | 1166 tv = eval_expr(arg, NULL); |
1167 else if (func_call(arg, &argv[2], NULL, &res_tv) == OK) | |
1168 tv = &res_tv; | |
1169 else | |
1170 tv = NULL; | |
1171 | |
1172 if (argv[id_idx].v_type == VAR_NUMBER) | |
1159 { | 1173 { |
1174 int id = argv[id_idx].vval.v_number; | |
1175 | |
1160 if (tv != NULL) | 1176 if (tv != NULL) |
1161 json = json_encode_nr_expr(arg3->vval.v_number, tv, | 1177 json = json_encode_nr_expr(id, tv, options); |
1162 options); | |
1163 if (tv == NULL || (json != NULL && *json == NUL)) | 1178 if (tv == NULL || (json != NULL && *json == NUL)) |
1164 { | 1179 { |
1165 /* If evaluation failed or the result can't be encoded | 1180 /* If evaluation failed or the result can't be encoded |
1166 * then return the string "ERROR". */ | 1181 * then return the string "ERROR". */ |
1167 vim_free(json); | 1182 vim_free(json); |
1168 free_tv(tv); | 1183 free_tv(tv); |
1169 err_tv.v_type = VAR_STRING; | 1184 err_tv.v_type = VAR_STRING; |
1170 err_tv.vval.v_string = (char_u *)"ERROR"; | 1185 err_tv.vval.v_string = (char_u *)"ERROR"; |
1171 tv = &err_tv; | 1186 tv = &err_tv; |
1172 json = json_encode_nr_expr(arg3->vval.v_number, tv, | 1187 json = json_encode_nr_expr(id, tv, options); |
1173 options); | |
1174 } | 1188 } |
1175 if (json != NULL) | 1189 if (json != NULL) |
1176 { | 1190 { |
1177 channel_send(channel, part, json, "eval"); | 1191 channel_send(channel, |
1192 part == PART_SOCK ? PART_SOCK : PART_IN, | |
1193 json, (char *)cmd); | |
1178 vim_free(json); | 1194 vim_free(json); |
1179 } | 1195 } |
1180 } | 1196 } |
1181 --emsg_skip; | 1197 --emsg_skip; |
1182 if (tv != &err_tv) | 1198 if (tv == &res_tv) |
1199 clear_tv(tv); | |
1200 else if (tv != &err_tv) | |
1183 free_tv(tv); | 1201 free_tv(tv); |
1184 } | 1202 } |
1185 } | 1203 } |
1186 else if (p_verbose > 2) | 1204 else if (p_verbose > 2) |
1205 { | |
1206 ch_errors(channel, "Receved unknown command: %s", (char *)cmd); | |
1187 EMSG2("E905: received unknown command: %s", cmd); | 1207 EMSG2("E905: received unknown command: %s", cmd); |
1208 } | |
1188 } | 1209 } |
1189 | 1210 |
1190 /* | 1211 /* |
1191 * Invoke a callback for "channel"/"part" if needed. | 1212 * Invoke a callback for "channel"/"part" if needed. |
1192 * Return TRUE when a message was handled, there might be another one. | 1213 * Return TRUE when a message was handled, there might be another one. |
1194 static int | 1215 static int |
1195 may_invoke_callback(channel_T *channel, int part) | 1216 may_invoke_callback(channel_T *channel, int part) |
1196 { | 1217 { |
1197 char_u *msg = NULL; | 1218 char_u *msg = NULL; |
1198 typval_T *listtv = NULL; | 1219 typval_T *listtv = NULL; |
1199 list_T *list; | 1220 typval_T argv[CH_JSON_MAX_ARGS]; |
1200 typval_T *typetv; | |
1201 typval_T argv[3]; | |
1202 int seq_nr = -1; | 1221 int seq_nr = -1; |
1203 ch_mode_T ch_mode = channel->ch_part[part].ch_mode; | 1222 ch_mode_T ch_mode = channel->ch_part[part].ch_mode; |
1204 char_u *callback = NULL; | 1223 char_u *callback = NULL; |
1205 | 1224 |
1206 if (channel->ch_close_cb != NULL) | 1225 if (channel->ch_close_cb != NULL) |
1212 else | 1231 else |
1213 callback = channel->ch_callback; | 1232 callback = channel->ch_callback; |
1214 | 1233 |
1215 if (ch_mode == MODE_JSON || ch_mode == MODE_JS) | 1234 if (ch_mode == MODE_JSON || ch_mode == MODE_JS) |
1216 { | 1235 { |
1236 listitem_T *item; | |
1237 int argc = 0; | |
1238 | |
1217 /* Get any json message in the queue. */ | 1239 /* Get any json message in the queue. */ |
1218 if (channel_get_json(channel, part, -1, &listtv) == FAIL) | 1240 if (channel_get_json(channel, part, -1, &listtv) == FAIL) |
1219 { | 1241 { |
1220 /* Parse readahead, return when there is still no message. */ | 1242 /* Parse readahead, return when there is still no message. */ |
1221 channel_parse_json(channel, part); | 1243 channel_parse_json(channel, part); |
1222 if (channel_get_json(channel, part, -1, &listtv) == FAIL) | 1244 if (channel_get_json(channel, part, -1, &listtv) == FAIL) |
1223 return FALSE; | 1245 return FALSE; |
1224 } | 1246 } |
1225 | 1247 |
1226 list = listtv->vval.v_list; | 1248 for (item = listtv->vval.v_list->lv_first; |
1227 argv[1] = list->lv_first->li_next->li_tv; | 1249 item != NULL && argc < CH_JSON_MAX_ARGS; |
1228 typetv = &list->lv_first->li_tv; | 1250 item = item->li_next) |
1229 if (typetv->v_type == VAR_STRING) | 1251 argv[argc++] = item->li_tv; |
1230 { | 1252 while (argc < CH_JSON_MAX_ARGS) |
1231 typval_T *arg3 = NULL; | 1253 argv[argc++].v_type = VAR_UNKNOWN; |
1232 char_u *cmd = typetv->vval.v_string; | 1254 |
1233 | 1255 if (argv[0].v_type == VAR_STRING) |
1234 /* ["cmd", arg] or ["cmd", arg, arg] */ | 1256 { |
1235 if (list->lv_len == 3) | 1257 char_u *cmd = argv[0].vval.v_string; |
1236 arg3 = &list->lv_last->li_tv; | 1258 |
1259 /* ["cmd", arg] or ["cmd", arg, arg] or ["cmd", arg, arg, arg] */ | |
1237 ch_logs(channel, "Executing %s command", (char *)cmd); | 1260 ch_logs(channel, "Executing %s command", (char *)cmd); |
1238 channel_exe_cmd(channel, part, cmd, &argv[1], arg3); | 1261 channel_exe_cmd(channel, part, argv); |
1239 free_tv(listtv); | 1262 free_tv(listtv); |
1240 return TRUE; | 1263 return TRUE; |
1241 } | 1264 } |
1242 | 1265 |
1243 if (typetv->v_type != VAR_NUMBER) | 1266 if (argv[0].v_type != VAR_NUMBER) |
1244 { | 1267 { |
1245 ch_error(channel, | 1268 ch_error(channel, |
1246 "Dropping message with invalid sequence number type"); | 1269 "Dropping message with invalid sequence number type"); |
1247 free_tv(listtv); | 1270 free_tv(listtv); |
1248 return FALSE; | 1271 return FALSE; |
1249 } | 1272 } |
1250 seq_nr = typetv->vval.v_number; | 1273 seq_nr = argv[0].vval.v_number; |
1251 } | 1274 } |
1252 else if (channel_peek(channel, part) == NULL) | 1275 else if (channel_peek(channel, part) == NULL) |
1253 { | 1276 { |
1254 /* nothing to read on RAW or NL channel */ | 1277 /* nothing to read on RAW or NL channel */ |
1255 return FALSE; | 1278 return FALSE; |