From 439c39a2cfb0712eb68ad76354b1fd7e92bb71fe Mon Sep 17 00:00:00 2001 From: Dongdong Zhou Date: Thu, 23 Feb 2017 05:33:14 +0000 Subject: ext_cmdline: allow external ui to draw cmdline --- runtime/doc/msgpack_rpc.txt | 33 +++++++++++++++++++ src/nvim/ex_getln.c | 80 ++++++++++++++++++++++++++++++++++++++++----- src/nvim/ui.c | 2 ++ 3 files changed, 106 insertions(+), 9 deletions(-) diff --git a/runtime/doc/msgpack_rpc.txt b/runtime/doc/msgpack_rpc.txt index 98a74ccfd6..4a82b3a1bd 100644 --- a/runtime/doc/msgpack_rpc.txt +++ b/runtime/doc/msgpack_rpc.txt @@ -260,12 +260,23 @@ a dictionary with these (optional) keys: colors. Set to false to use terminal color codes (at most 256 different colors). + `ext_popupmenu` Externalize the popupmenu. |ui-ext-popupmenu| `ext_tabline` Externalize the tabline. |ui-ext-tabline| Externalized widgets will not be drawn by Nvim; only high-level data will be published in new UI event kinds. + `popupmenu_external`: Instead of drawing the completion popupmenu on + the grid, Nvim will send higher-level events to + the ui and let it draw the popupmenu. + Defaults to false. + cmdline_external: Instead of drawing the cmdline on + the grid, Nvim will send higher-level events to + the ui and let it draw the cmdline. + Defaults to false. + + Nvim will then send msgpack-rpc notifications, with the method name "redraw" and a single argument, an array of screen updates (described below). These should be processed in order. Preferably the user should only be able to see @@ -441,5 +452,27 @@ states might be represented as separate modes. curtab: Current Tabpage tabs: List of Dicts [{ "tab": Tabpage, "name": String }, ...] +["cmdline_enter"] + Enter the cmdline. + +["cmdline_leave"] + Leave the cmdline. + +["cmdline_firstc", firstc] + The first character of the command, which could be : / ? etc. With + the firstc, you know wheither it's a command or a search. + +["cmdline", content, pos] + When cmdline_external is set to true, nvim will not draw the cmdline + on the grad, instead nvim will send ui events of the cmdline content + and cursor position to the remote ui. The content is the full content + that should be displayed in the cmdline, and the pos is the position + of the cursor that in the cmdline. This event will be triggered when + you type in the cmdline. + +["cmdline_pos", pos] + When you move your cursor, nvim will send out this event which tells + you the current position of the cursor in the cmdline. + ============================================================================== vim:tw=78:ts=8:noet:ft=help:norl: diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 54e5bcb9ff..87bf46d4d0 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -185,6 +185,8 @@ static int cmd_showtail; /* Only show path tail in lists ? */ static int new_cmdpos; /* position set by set_cmdline_pos() */ +static bool cmdline_external = false; + /* * Type used by call_user_expand_func */ @@ -281,7 +283,9 @@ static uint8_t *command_line_enter(int firstc, long count, int indent) if (!cmd_silent) { s->i = msg_scrolled; msg_scrolled = 0; // avoid wait_return message - gotocmdline(true); + if (!cmdline_external) { + gotocmdline(true); + } msg_scrolled += s->i; redrawcmdprompt(); // draw prompt or indent set_cmdspos(); @@ -1828,7 +1832,16 @@ getcmdline ( int indent // indent for inside conditionals ) { - return command_line_enter(firstc, count, indent); + if (cmdline_external) { + Array args = ARRAY_DICT_INIT; + ui_event("cmdline_enter", args); + } + char_u *p = command_line_enter(firstc, count, indent); + if (cmdline_external) { + Array args = ARRAY_DICT_INIT; + ui_event("cmdline_leave", args); + } + return p; } /// Get a command line with a prompt @@ -2589,6 +2602,14 @@ static void draw_cmdline(int start, int len) return; } + if (cmdline_external) { + Array args = ARRAY_DICT_INIT; + ADD(args, STRING_OBJ(cstr_to_string((char *)(ccline.cmdbuff)))); + ADD(args, INTEGER_OBJ(ccline.cmdpos)); + ui_event("cmdline", args); + return; + } + if (cmdline_star > 0) { for (int i = 0; i < len; i++) { msg_putchar('*'); @@ -2713,11 +2734,28 @@ void putcmdline(int c, int shift) { if (cmd_silent) return; - msg_no_more = TRUE; - msg_putchar(c); - if (shift) - draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos); - msg_no_more = FALSE; + if (!cmdline_external) { + msg_no_more = TRUE; + msg_putchar(c); + if (shift) + draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos); + msg_no_more = FALSE; + } else { + char_u *p; + if (ccline.cmdpos == ccline.cmdlen || shift) { + p = vim_strnsave(ccline.cmdbuff, ccline.cmdlen + 1); + } else { + p = vim_strsave(ccline.cmdbuff); + } + p[ccline.cmdpos] = c; + if (shift) + STRCPY(p + ccline.cmdpos + 1, ccline.cmdbuff + ccline.cmdpos); + Array args = ARRAY_DICT_INIT; + ADD(args, STRING_OBJ(cstr_to_string((char *)(p)))); + ADD(args, INTEGER_OBJ(ccline.cmdpos)); + ui_event("cmdline", args); + xfree(p); + } cursorcmd(); ui_cursor_shape(); } @@ -3066,8 +3104,15 @@ static void redrawcmdprompt(void) if (cmd_silent) return; - if (ccline.cmdfirstc != NUL) - msg_putchar(ccline.cmdfirstc); + if (ccline.cmdfirstc != NUL) { + if (cmdline_external) { + Array args = ARRAY_DICT_INIT; + ADD(args, STRING_OBJ(cstr_to_string((char *)(&ccline.cmdfirstc)))); + ui_event("cmdline_firstc", args); + } else { + msg_putchar(ccline.cmdfirstc); + } + } if (ccline.cmdprompt != NULL) { msg_puts_attr((const char *)ccline.cmdprompt, ccline.cmdattr); ccline.cmdindent = msg_col + (msg_row - cmdline_row) * Columns; @@ -3087,6 +3132,11 @@ void redrawcmd(void) if (cmd_silent) return; + if (cmdline_external) { + draw_cmdline(0, ccline.cmdlen); + return; + } + /* when 'incsearch' is set there may be no command line while redrawing */ if (ccline.cmdbuff == NULL) { ui_cursor_goto(cmdline_row, 0); @@ -3130,6 +3180,13 @@ static void cursorcmd(void) if (cmd_silent) return; + if (cmdline_external) { + Array args = ARRAY_DICT_INIT; + ADD(args, INTEGER_OBJ(ccline.cmdpos)); + ui_event("cmdline_pos", args); + return; + } + if (cmdmsg_rl) { msg_row = cmdline_row + (ccline.cmdspos / (int)(Columns - 1)); msg_col = (int)Columns - (ccline.cmdspos % (int)(Columns - 1)) - 1; @@ -5974,3 +6031,8 @@ static void set_search_match(pos_T *t) coladvance((colnr_T)MAXCOL); } } + +void cmdline_set_external(bool external) +{ + cmdline_external = external; +} diff --git a/src/nvim/ui.c b/src/nvim/ui.c index afe7a51d43..0fa4034ff6 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -30,6 +30,7 @@ #include "nvim/os/input.h" #include "nvim/os/signal.h" #include "nvim/popupmnu.h" +#include "nvim/ex_getln.h" #include "nvim/screen.h" #include "nvim/syntax.h" #include "nvim/window.h" @@ -280,6 +281,7 @@ void ui_refresh(void) int save_p_lz = p_lz; p_lz = false; // convince redrawing() to return true ... + cmdline_set_external(cmdline_external); screen_resize(width, height); p_lz = save_p_lz; -- cgit From 6e90bc7200c87f0af448a8cf0998715db9175f15 Mon Sep 17 00:00:00 2001 From: Dongdong Zhou Date: Thu, 23 Feb 2017 09:53:12 +0000 Subject: ext_cmdline: Added cmdline prompt --- runtime/doc/msgpack_rpc.txt | 3 +++ src/nvim/eval.c | 18 +++++++++++------- src/nvim/ex_getln.c | 21 ++++++++++++++++----- 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/runtime/doc/msgpack_rpc.txt b/runtime/doc/msgpack_rpc.txt index 4a82b3a1bd..b7c790bb64 100644 --- a/runtime/doc/msgpack_rpc.txt +++ b/runtime/doc/msgpack_rpc.txt @@ -462,6 +462,9 @@ states might be represented as separate modes. The first character of the command, which could be : / ? etc. With the firstc, you know wheither it's a command or a search. +["cmdline_prompt", prompt] + The prompt of the cmdline. + ["cmdline", content, pos] When cmdline_external is set to true, nvim will not draw the cmdline on the grad, instead nvim will send ui events of the cmdline content diff --git a/src/nvim/eval.c b/src/nvim/eval.c index aab777955c..72b97cbab9 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -11149,15 +11149,19 @@ void get_user_input(const typval_T *const argvars, // Only the part of the message after the last NL is considered as // prompt for the command line. const char *p = strrchr(prompt, '\n'); - if (p == NULL) { + if (ui_is_external(kUICmdline)) { p = prompt; } else { - p++; - msg_start(); - msg_clr_eos(); - msg_puts_attr_len(prompt, p - prompt, echo_attr); - msg_didout = false; - msg_starthere(); + if (p == NULL) { + p = prompt; + } else { + p++; + msg_start(); + msg_clr_eos(); + msg_puts_attr_len(prompt, p - prompt, echo_attr); + msg_didout = false; + msg_starthere(); + } } cmdline_row = msg_row; diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 87bf46d4d0..a05331d13a 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -3114,11 +3114,17 @@ static void redrawcmdprompt(void) } } if (ccline.cmdprompt != NULL) { - msg_puts_attr((const char *)ccline.cmdprompt, ccline.cmdattr); - ccline.cmdindent = msg_col + (msg_row - cmdline_row) * Columns; - /* do the reverse of set_cmdspos() */ - if (ccline.cmdfirstc != NUL) - --ccline.cmdindent; + if (cmdline_external) { + Array args = ARRAY_DICT_INIT; + ADD(args, STRING_OBJ(cstr_to_string((char *)(ccline.cmdprompt)))); + ui_event("cmdline_prompt", args); + } else { + msg_puts_attr((const char *)ccline.cmdprompt, ccline.cmdattr); + ccline.cmdindent = msg_col + (msg_row - cmdline_row) * Columns; + /* do the reverse of set_cmdspos() */ + if (ccline.cmdfirstc != NUL) + --ccline.cmdindent; + } } else for (i = ccline.cmdindent; i > 0; --i) msg_putchar(' '); @@ -6036,3 +6042,8 @@ void cmdline_set_external(bool external) { cmdline_external = external; } + +bool cmdline_get_external(void) +{ + return cmdline_external; +} -- cgit From 26fd70bd18283701a2ade11407694485cd0f7e35 Mon Sep 17 00:00:00 2001 From: Dongdong Zhou Date: Fri, 24 Feb 2017 07:26:39 +0000 Subject: ext_cmdline: add tests --- src/nvim/ex_getln.c | 11 ++-- test/functional/ui/cmdline_spec.lua | 128 ++++++++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+), 4 deletions(-) create mode 100644 test/functional/ui/cmdline_spec.lua diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index a05331d13a..18d6b26595 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -283,9 +283,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent) if (!cmd_silent) { s->i = msg_scrolled; msg_scrolled = 0; // avoid wait_return message - if (!cmdline_external) { - gotocmdline(true); - } + gotocmdline(true); msg_scrolled += s->i; redrawcmdprompt(); // draw prompt or indent set_cmdspos(); @@ -808,7 +806,9 @@ static int command_line_execute(VimState *state, int key) } if (!cmd_silent) { - ui_cursor_goto(msg_row, 0); + if (!cmdline_external) { + ui_cursor_goto(msg_row, 0); + } ui_flush(); } return 0; @@ -3210,6 +3210,9 @@ static void cursorcmd(void) void gotocmdline(int clr) { + if (cmdline_external) { + return; + } msg_start(); if (cmdmsg_rl) msg_col = Columns - 1; diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua new file mode 100644 index 0000000000..67eff9827c --- /dev/null +++ b/test/functional/ui/cmdline_spec.lua @@ -0,0 +1,128 @@ +local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') +local clear, feed, execute, eq = helpers.clear, helpers.feed, helpers.execute, helpers.eq +local funcs = helpers.funcs + +if helpers.pending_win32(pending) then return end + +describe('External command line completion', function() + local screen + local shown = false + local firstc, prompt, content, pos + + before_each(function() + clear() + screen = Screen.new(25, 5) + screen:attach({rgb=true, cmdline_external=true}) + screen:set_on_event_handler(function(name, data) + if name == "cmdline_enter" then + shown = true + elseif name == "cmdline_leave" then + shown = false + elseif name == "cmdline_firstc" then + firstc = data[1] + elseif name == "cmdline_prompt" then + prompt = data[1] + elseif name == "cmdline" then + content, pos = unpack(data) + elseif name == "cmdline_pos" then + pos = data[1] + end + end) + end) + + after_each(function() + screen:detach() + end) + + describe("'cmdline'", function() + it(':sign', function() + feed(':') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq(true, shown) + eq(':', firstc) + end) + + feed('sign') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq("sign", content) + eq(4, pos) + end) + + feed('') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq("sign", content) + eq(true, shown) + eq(3, pos) + end) + + feed('') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq("sin", content) + eq(true, shown) + eq(2, pos) + end) + + feed('') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq(false, shown) + end) + + feed(':call input("input", "default")') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq(true, shown) + eq("input", prompt) + eq("default", content) + end) + + feed('') + feed(':=1+2') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq("3", content) + end) + + end) + end) +end) -- cgit From b7a8a76f6e3b2de1cfdf32e3ccc66d87ab8e5cad Mon Sep 17 00:00:00 2001 From: Dongdong Zhou Date: Mon, 27 Feb 2017 02:56:38 +0000 Subject: ext_cmdline: lint --- src/nvim/ex_getln.c | 13 ++++++++----- test/functional/ui/cmdline_spec.lua | 3 +-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 18d6b26595..0fae6c9810 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -3121,13 +3121,16 @@ static void redrawcmdprompt(void) } else { msg_puts_attr((const char *)ccline.cmdprompt, ccline.cmdattr); ccline.cmdindent = msg_col + (msg_row - cmdline_row) * Columns; - /* do the reverse of set_cmdspos() */ - if (ccline.cmdfirstc != NUL) - --ccline.cmdindent; + // do the reverse of set_cmdspos() + if (ccline.cmdfirstc != NUL) { + ccline.cmdindent--; + } } - } else - for (i = ccline.cmdindent; i > 0; --i) + } else { + for (i = ccline.cmdindent; i > 0; i--) { msg_putchar(' '); + } + } } /* diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 67eff9827c..d0726f5924 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -1,7 +1,6 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') -local clear, feed, execute, eq = helpers.clear, helpers.feed, helpers.execute, helpers.eq -local funcs = helpers.funcs +local clear, feed, eq = helpers.clear, helpers.feed, helpers.eq if helpers.pending_win32(pending) then return end -- cgit From 550651c130c014e6c668644273db31dd96be475e Mon Sep 17 00:00:00 2001 From: Dongdong Zhou Date: Fri, 28 Apr 2017 06:51:16 +0100 Subject: ext_cmdline: use standard external ui functions --- runtime/doc/msgpack_rpc.txt | 22 ++------ src/nvim/eval.c | 15 +++--- src/nvim/ex_getln.c | 104 +++++++++++++++++------------------- src/nvim/ui.c | 1 - test/functional/ui/cmdline_spec.lua | 16 +++--- 5 files changed, 65 insertions(+), 93 deletions(-) diff --git a/runtime/doc/msgpack_rpc.txt b/runtime/doc/msgpack_rpc.txt index b7c790bb64..46fc6f19c2 100644 --- a/runtime/doc/msgpack_rpc.txt +++ b/runtime/doc/msgpack_rpc.txt @@ -260,23 +260,13 @@ a dictionary with these (optional) keys: colors. Set to false to use terminal color codes (at most 256 different colors). - `ext_popupmenu` Externalize the popupmenu. |ui-ext-popupmenu| `ext_tabline` Externalize the tabline. |ui-ext-tabline| + `ext_cmdline` Externalize the cmdline. |ui-ext-cmdline| Externalized widgets will not be drawn by Nvim; only high-level data will be published in new UI event kinds. - `popupmenu_external`: Instead of drawing the completion popupmenu on - the grid, Nvim will send higher-level events to - the ui and let it draw the popupmenu. - Defaults to false. - cmdline_external: Instead of drawing the cmdline on - the grid, Nvim will send higher-level events to - the ui and let it draw the cmdline. - Defaults to false. - - Nvim will then send msgpack-rpc notifications, with the method name "redraw" and a single argument, an array of screen updates (described below). These should be processed in order. Preferably the user should only be able to see @@ -452,20 +442,14 @@ states might be represented as separate modes. curtab: Current Tabpage tabs: List of Dicts [{ "tab": Tabpage, "name": String }, ...] + *ui-ext-cmdline* ["cmdline_enter"] Enter the cmdline. ["cmdline_leave"] Leave the cmdline. -["cmdline_firstc", firstc] - The first character of the command, which could be : / ? etc. With - the firstc, you know wheither it's a command or a search. - -["cmdline_prompt", prompt] - The prompt of the cmdline. - -["cmdline", content, pos] +["cmdline_show", content, pos, firstc, prompt] When cmdline_external is set to true, nvim will not draw the cmdline on the grad, instead nvim will send ui events of the cmdline content and cursor position to the remote ui. The content is the full content diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 72b97cbab9..3c9614dfcd 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -11147,15 +11147,12 @@ void get_user_input(const typval_T *const argvars, cmd_silent = false; // Want to see the prompt. // Only the part of the message after the last NL is considered as - // prompt for the command line. - const char *p = strrchr(prompt, '\n'); - if (ui_is_external(kUICmdline)) { - p = prompt; - } else { - if (p == NULL) { - p = prompt; - } else { - p++; + // prompt for the command line, unlsess cmdline is externalized + const char *p = prompt; + if (!ui_is_external(kUICmdline)) { + const char *lastnl = strrchr(prompt, '\n'); + if (lastnl != NULL) { + p = lastnl+1; msg_start(); msg_clr_eos(); msg_puts_attr_len(prompt, p - prompt, echo_attr); diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 0fae6c9810..8c9e081c89 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -185,8 +185,6 @@ static int cmd_showtail; /* Only show path tail in lists ? */ static int new_cmdpos; /* position set by set_cmdline_pos() */ -static bool cmdline_external = false; - /* * Type used by call_user_expand_func */ @@ -806,7 +804,7 @@ static int command_line_execute(VimState *state, int key) } if (!cmd_silent) { - if (!cmdline_external) { + if (!ui_is_external(kUICmdline)) { ui_cursor_goto(msg_row, 0); } ui_flush(); @@ -1832,12 +1830,12 @@ getcmdline ( int indent // indent for inside conditionals ) { - if (cmdline_external) { + if (ui_is_external(kUICmdline)) { Array args = ARRAY_DICT_INIT; ui_event("cmdline_enter", args); } char_u *p = command_line_enter(firstc, count, indent); - if (cmdline_external) { + if (ui_is_external(kUICmdline)) { Array args = ARRAY_DICT_INIT; ui_event("cmdline_leave", args); } @@ -2602,11 +2600,8 @@ static void draw_cmdline(int start, int len) return; } - if (cmdline_external) { - Array args = ARRAY_DICT_INIT; - ADD(args, STRING_OBJ(cstr_to_string((char *)(ccline.cmdbuff)))); - ADD(args, INTEGER_OBJ(ccline.cmdpos)); - ui_event("cmdline", args); + if (ui_is_external(kUICmdline)) { + ui_ext_cmdline_show(); return; } @@ -2725,6 +2720,32 @@ draw_cmdline_no_arabicshape: } } +void ui_ext_cmdline_char(int c, int shift) +{ + Array args = ARRAY_DICT_INIT; + ADD(args, STRING_OBJ(cstr_to_string((char *)(&c)))); + ADD(args, INTEGER_OBJ(shift)); + ui_event("cmdline_char", args); +} + +void ui_ext_cmdline_show(void) +{ + Array args = ARRAY_DICT_INIT; + ADD(args, STRING_OBJ(cstr_to_string((char *)(ccline.cmdbuff)))); + ADD(args, INTEGER_OBJ(ccline.cmdpos)); + if (ccline.cmdfirstc != NUL) { + ADD(args, STRING_OBJ(cstr_to_string((char *)(&ccline.cmdfirstc)))); + } else { + ADD(args, STRING_OBJ(cstr_to_string(""))); + } + if (ccline.cmdprompt != NULL) { + ADD(args, STRING_OBJ(cstr_to_string((char *)(ccline.cmdprompt)))); + } else { + ADD(args, STRING_OBJ(cstr_to_string(""))); + } + ui_event("cmdline_show", args); +} + /* * Put a character on the command line. Shifts the following text to the * right when "shift" is TRUE. Used for CTRL-V, CTRL-K, etc. @@ -2732,29 +2753,17 @@ draw_cmdline_no_arabicshape: */ void putcmdline(int c, int shift) { - if (cmd_silent) + if (cmd_silent) { return; - if (!cmdline_external) { + } + if (!ui_is_external(kUICmdline)) { msg_no_more = TRUE; msg_putchar(c); if (shift) draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos); msg_no_more = FALSE; } else { - char_u *p; - if (ccline.cmdpos == ccline.cmdlen || shift) { - p = vim_strnsave(ccline.cmdbuff, ccline.cmdlen + 1); - } else { - p = vim_strsave(ccline.cmdbuff); - } - p[ccline.cmdpos] = c; - if (shift) - STRCPY(p + ccline.cmdpos + 1, ccline.cmdbuff + ccline.cmdpos); - Array args = ARRAY_DICT_INIT; - ADD(args, STRING_OBJ(cstr_to_string((char *)(p)))); - ADD(args, INTEGER_OBJ(ccline.cmdpos)); - ui_event("cmdline", args); - xfree(p); + ui_ext_cmdline_char(c, shift); } cursorcmd(); ui_cursor_shape(); @@ -3104,27 +3113,19 @@ static void redrawcmdprompt(void) if (cmd_silent) return; + if (ui_is_external(kUICmdline)) { + ui_ext_cmdline_show(); + return; + } if (ccline.cmdfirstc != NUL) { - if (cmdline_external) { - Array args = ARRAY_DICT_INIT; - ADD(args, STRING_OBJ(cstr_to_string((char *)(&ccline.cmdfirstc)))); - ui_event("cmdline_firstc", args); - } else { - msg_putchar(ccline.cmdfirstc); - } + msg_putchar(ccline.cmdfirstc); } if (ccline.cmdprompt != NULL) { - if (cmdline_external) { - Array args = ARRAY_DICT_INIT; - ADD(args, STRING_OBJ(cstr_to_string((char *)(ccline.cmdprompt)))); - ui_event("cmdline_prompt", args); - } else { - msg_puts_attr((const char *)ccline.cmdprompt, ccline.cmdattr); - ccline.cmdindent = msg_col + (msg_row - cmdline_row) * Columns; - // do the reverse of set_cmdspos() - if (ccline.cmdfirstc != NUL) { - ccline.cmdindent--; - } + msg_puts_attr((const char *)ccline.cmdprompt, ccline.cmdattr); + ccline.cmdindent = msg_col + (msg_row - cmdline_row) * Columns; + // do the reverse of set_cmdspos() + if (ccline.cmdfirstc != NUL) { + ccline.cmdindent--; } } else { for (i = ccline.cmdindent; i > 0; i--) { @@ -3141,7 +3142,7 @@ void redrawcmd(void) if (cmd_silent) return; - if (cmdline_external) { + if (ui_is_external(kUICmdline)) { draw_cmdline(0, ccline.cmdlen); return; } @@ -3189,7 +3190,7 @@ static void cursorcmd(void) if (cmd_silent) return; - if (cmdline_external) { + if (ui_is_external(kUICmdline)) { Array args = ARRAY_DICT_INIT; ADD(args, INTEGER_OBJ(ccline.cmdpos)); ui_event("cmdline_pos", args); @@ -3213,7 +3214,7 @@ static void cursorcmd(void) void gotocmdline(int clr) { - if (cmdline_external) { + if (ui_is_external(kUICmdline)) { return; } msg_start(); @@ -6044,12 +6045,3 @@ static void set_search_match(pos_T *t) } } -void cmdline_set_external(bool external) -{ - cmdline_external = external; -} - -bool cmdline_get_external(void) -{ - return cmdline_external; -} diff --git a/src/nvim/ui.c b/src/nvim/ui.c index 0fa4034ff6..6b09f6e6db 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -281,7 +281,6 @@ void ui_refresh(void) int save_p_lz = p_lz; p_lz = false; // convince redrawing() to return true ... - cmdline_set_external(cmdline_external); screen_resize(width, height); p_lz = save_p_lz; diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index d0726f5924..35cacbf4d0 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -7,23 +7,21 @@ if helpers.pending_win32(pending) then return end describe('External command line completion', function() local screen local shown = false - local firstc, prompt, content, pos + local firstc, prompt, content, pos, char, shift before_each(function() clear() screen = Screen.new(25, 5) - screen:attach({rgb=true, cmdline_external=true}) + screen:attach({rgb=true, ext_cmdline=true}) screen:set_on_event_handler(function(name, data) if name == "cmdline_enter" then shown = true elseif name == "cmdline_leave" then shown = false - elseif name == "cmdline_firstc" then - firstc = data[1] - elseif name == "cmdline_prompt" then - prompt = data[1] - elseif name == "cmdline" then - content, pos = unpack(data) + elseif name == "cmdline_show" then + content, pos, firstc, prompt = unpack(data) + elseif name == "cmdline_char" then + char, shift = unpack(data) elseif name == "cmdline_pos" then pos = data[1] end @@ -120,6 +118,8 @@ describe('External command line completion', function() | ]], nil, nil, function() eq("3", content) + eq("\"", char) + eq(1, shift) end) end) -- cgit From daec81ab5179c7ce8e3813af556b1e2f05fc59c6 Mon Sep 17 00:00:00 2001 From: Dongdong Zhou Date: Fri, 28 Apr 2017 07:49:45 +0100 Subject: ext_cmdline: change the content format --- runtime/doc/msgpack_rpc.txt | 2 ++ src/nvim/ex_getln.c | 7 ++++++- test/functional/ui/cmdline_spec.lua | 10 +++++----- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/runtime/doc/msgpack_rpc.txt b/runtime/doc/msgpack_rpc.txt index 46fc6f19c2..ef4a22db0b 100644 --- a/runtime/doc/msgpack_rpc.txt +++ b/runtime/doc/msgpack_rpc.txt @@ -450,6 +450,8 @@ states might be represented as separate modes. Leave the cmdline. ["cmdline_show", content, pos, firstc, prompt] + content: List of [highlight group, string] + [["Normal", "t"], ["Search", "est"], ...] When cmdline_external is set to true, nvim will not draw the cmdline on the grad, instead nvim will send ui events of the cmdline content and cursor position to the remote ui. The content is the full content diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 8c9e081c89..12f3f53c81 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -2731,7 +2731,12 @@ void ui_ext_cmdline_char(int c, int shift) void ui_ext_cmdline_show(void) { Array args = ARRAY_DICT_INIT; - ADD(args, STRING_OBJ(cstr_to_string((char *)(ccline.cmdbuff)))); + Array content = ARRAY_DICT_INIT; + Array text = ARRAY_DICT_INIT; + ADD(text, STRING_OBJ(cstr_to_string("Normal"))); + ADD(text, STRING_OBJ(cstr_to_string((char *)(ccline.cmdbuff)))); + ADD(content, ARRAY_OBJ(text)); + ADD(args, ARRAY_OBJ(content)); ADD(args, INTEGER_OBJ(ccline.cmdpos)); if (ccline.cmdfirstc != NUL) { ADD(args, STRING_OBJ(cstr_to_string((char *)(&ccline.cmdfirstc)))); diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 35cacbf4d0..523f7065d4 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -54,7 +54,7 @@ describe('External command line completion', function() ~ | | ]], nil, nil, function() - eq("sign", content) + eq({{'Normal', 'sign'}}, content) eq(4, pos) end) @@ -66,7 +66,7 @@ describe('External command line completion', function() ~ | | ]], nil, nil, function() - eq("sign", content) + eq({{'Normal', 'sign'}}, content) eq(true, shown) eq(3, pos) end) @@ -79,7 +79,7 @@ describe('External command line completion', function() ~ | | ]], nil, nil, function() - eq("sin", content) + eq({{'Normal', 'sin'}}, content) eq(true, shown) eq(2, pos) end) @@ -105,7 +105,7 @@ describe('External command line completion', function() ]], nil, nil, function() eq(true, shown) eq("input", prompt) - eq("default", content) + eq({{'Normal', 'default'}}, content) end) feed('') @@ -117,7 +117,7 @@ describe('External command line completion', function() ~ | | ]], nil, nil, function() - eq("3", content) + eq({{'Normal', '3'}}, content) eq("\"", char) eq(1, shift) end) -- cgit From e164ba41c8460d4e5b2e7e2b929d8479a0310738 Mon Sep 17 00:00:00 2001 From: Dongdong Zhou Date: Thu, 11 May 2017 04:48:59 +0100 Subject: ext_cmdline: fix firstc, change cmdline_leave to cmdline_hide --- runtime/doc/msgpack_rpc.txt | 4 ++-- src/nvim/ex_getln.c | 19 ++++++++----------- test/functional/ui/cmdline_spec.lua | 2 +- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/runtime/doc/msgpack_rpc.txt b/runtime/doc/msgpack_rpc.txt index ef4a22db0b..77938fbd82 100644 --- a/runtime/doc/msgpack_rpc.txt +++ b/runtime/doc/msgpack_rpc.txt @@ -446,8 +446,8 @@ states might be represented as separate modes. ["cmdline_enter"] Enter the cmdline. -["cmdline_leave"] - Leave the cmdline. +["cmdline_hide"] + Hide the cmdline. ["cmdline_show", content, pos, firstc, prompt] content: List of [highlight group, string] diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 12f3f53c81..34547c59c9 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -1837,7 +1837,7 @@ getcmdline ( char_u *p = command_line_enter(firstc, count, indent); if (ui_is_external(kUICmdline)) { Array args = ARRAY_DICT_INIT; - ui_event("cmdline_leave", args); + ui_event("cmdline_hide", args); } return p; } @@ -2738,16 +2738,13 @@ void ui_ext_cmdline_show(void) ADD(content, ARRAY_OBJ(text)); ADD(args, ARRAY_OBJ(content)); ADD(args, INTEGER_OBJ(ccline.cmdpos)); - if (ccline.cmdfirstc != NUL) { - ADD(args, STRING_OBJ(cstr_to_string((char *)(&ccline.cmdfirstc)))); - } else { - ADD(args, STRING_OBJ(cstr_to_string(""))); - } - if (ccline.cmdprompt != NULL) { - ADD(args, STRING_OBJ(cstr_to_string((char *)(ccline.cmdprompt)))); - } else { - ADD(args, STRING_OBJ(cstr_to_string(""))); - } + char *firstc = (char []) { (char)ccline.cmdfirstc }; + String str = (String) { + .data = xmemdupz(firstc, 1), + .size = 1 + }; + ADD(args, STRING_OBJ(str)); + ADD(args, STRING_OBJ(cstr_to_string((char *)(ccline.cmdprompt)))); ui_event("cmdline_show", args); } diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 523f7065d4..479f5c3b7d 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -16,7 +16,7 @@ describe('External command line completion', function() screen:set_on_event_handler(function(name, data) if name == "cmdline_enter" then shown = true - elseif name == "cmdline_leave" then + elseif name == "cmdline_hide" then shown = false elseif name == "cmdline_show" then content, pos, firstc, prompt = unpack(data) -- cgit From ab85999eb7c53e9d2b5bca5f8896ea11cb1df13e Mon Sep 17 00:00:00 2001 From: Dongdong Zhou Date: Thu, 11 May 2017 07:11:21 +0100 Subject: ext_cmdline: change to use ui_call --- src/nvim/api/ui_events.in.h | 11 +++++++++++ src/nvim/ex_getln.c | 27 +++++---------------------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h index 1b5d17584f..093251bb00 100644 --- a/src/nvim/api/ui_events.in.h +++ b/src/nvim/api/ui_events.in.h @@ -68,4 +68,15 @@ void popupmenu_select(Integer selected) void tabline_update(Tabpage current, Array tabs) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; +void cmdline_enter(void) + FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; +void cmdline_show(Array content, Integer pos, String firstc, String prompt) + FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; +void cmdline_pos(Integer pos) + FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; +void cmdline_char(String c, Integer shift) + FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; +void cmdline_hide(void) + FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; + #endif // NVIM_API_UI_EVENTS_IN_H diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 34547c59c9..0223d9e936 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -1831,13 +1831,11 @@ getcmdline ( ) { if (ui_is_external(kUICmdline)) { - Array args = ARRAY_DICT_INIT; - ui_event("cmdline_enter", args); + ui_call_cmdline_enter(); } char_u *p = command_line_enter(firstc, count, indent); if (ui_is_external(kUICmdline)) { - Array args = ARRAY_DICT_INIT; - ui_event("cmdline_hide", args); + ui_call_cmdline_hide(); } return p; } @@ -2720,32 +2718,19 @@ draw_cmdline_no_arabicshape: } } -void ui_ext_cmdline_char(int c, int shift) -{ - Array args = ARRAY_DICT_INIT; - ADD(args, STRING_OBJ(cstr_to_string((char *)(&c)))); - ADD(args, INTEGER_OBJ(shift)); - ui_event("cmdline_char", args); -} - void ui_ext_cmdline_show(void) { - Array args = ARRAY_DICT_INIT; Array content = ARRAY_DICT_INIT; Array text = ARRAY_DICT_INIT; ADD(text, STRING_OBJ(cstr_to_string("Normal"))); ADD(text, STRING_OBJ(cstr_to_string((char *)(ccline.cmdbuff)))); ADD(content, ARRAY_OBJ(text)); - ADD(args, ARRAY_OBJ(content)); - ADD(args, INTEGER_OBJ(ccline.cmdpos)); char *firstc = (char []) { (char)ccline.cmdfirstc }; String str = (String) { .data = xmemdupz(firstc, 1), .size = 1 }; - ADD(args, STRING_OBJ(str)); - ADD(args, STRING_OBJ(cstr_to_string((char *)(ccline.cmdprompt)))); - ui_event("cmdline_show", args); + ui_call_cmdline_show(content, ccline.cmdpos, str, cstr_to_string((char *)(ccline.cmdprompt))); } /* @@ -2765,7 +2750,7 @@ void putcmdline(int c, int shift) draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos); msg_no_more = FALSE; } else { - ui_ext_cmdline_char(c, shift); + ui_call_cmdline_char(cstr_to_string((char *)(&c)), shift); } cursorcmd(); ui_cursor_shape(); @@ -3193,9 +3178,7 @@ static void cursorcmd(void) return; if (ui_is_external(kUICmdline)) { - Array args = ARRAY_DICT_INIT; - ADD(args, INTEGER_OBJ(ccline.cmdpos)); - ui_event("cmdline_pos", args); + ui_call_cmdline_pos(ccline.cmdpos); return; } -- cgit From 866dadaf753ba3733feb8c22d7da47af757bd35c Mon Sep 17 00:00:00 2001 From: Dongdong Zhou Date: Thu, 11 May 2017 07:51:10 +0100 Subject: ext_cmdline: added cmdline level add cchar_to_string --- src/nvim/api/private/helpers.c | 16 ++++++++++++ src/nvim/api/ui_events.in.h | 11 +++----- src/nvim/ex_getln.c | 40 +++++++++++++--------------- test/functional/ui/cmdline_spec.lua | 52 +++++++++++++++++++++++++++++++------ 4 files changed, 82 insertions(+), 37 deletions(-) diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index e736e29e2d..f00fbf69ea 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -667,6 +667,22 @@ tabpage_T *find_tab_by_handle(Tabpage tabpage, Error *err) return rv; } +/// Allocates a String consisting of a single char. Does not support multibyte +/// characters. The resulting string is also NUL-terminated, to facilitate +/// interoperating with code using C strings. +/// +/// @param char the char to convert +/// @return the resulting String, if the input char was NUL, an +/// empty String is returned +String cchar_to_string(char c) +{ + char buf[] = { c, NUL }; + return (String) { + .data = xmemdupz(buf, 1), + .size = (c != NUL) ? 1 : 0 + }; +} + /// Copies a C string into a String (binary safe string, characters + length). /// The resulting string is also NUL-terminated, to facilitate interoperating /// with code using C strings. diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h index 093251bb00..17eefbe1d6 100644 --- a/src/nvim/api/ui_events.in.h +++ b/src/nvim/api/ui_events.in.h @@ -66,17 +66,14 @@ void popupmenu_hide(void) void popupmenu_select(Integer selected) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; void tabline_update(Tabpage current, Array tabs) - FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; - -void cmdline_enter(void) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; -void cmdline_show(Array content, Integer pos, String firstc, String prompt) +void cmdline_show(Array content, Integer pos, String firstc, String prompt, Integer level) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; -void cmdline_pos(Integer pos) +void cmdline_pos(Integer pos, Integer level) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; -void cmdline_char(String c, Integer shift) +void cmdline_char(String c, Integer shift, Integer level) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; -void cmdline_hide(void) +void cmdline_hide(Integer level) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; #endif // NVIM_API_UI_EVENTS_IN_H diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 0223d9e936..548459a8ce 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -91,6 +91,7 @@ struct cmdline_info { int input_fn; // when TRUE Invoked for input() function unsigned prompt_id; ///< Prompt number, used to disable coloring on errors. Callback highlight_callback; ///< Callback used for coloring user input. + int level; // current cmdline level }; /// Last value of prompt_id, incremented when doing new prompt static unsigned last_prompt_id = 0; @@ -238,7 +239,9 @@ static uint8_t *command_line_enter(int firstc, long count, int indent) cmd_hkmap = 0; } + // TODO(bfredl): can these be combined? ccline.prompt_id = last_prompt_id++; + ccline.level++; ccline.overstrike = false; // always start in insert mode clearpos(&s->match_end); s->save_cursor = curwin->w_cursor; // may be restored later @@ -414,6 +417,11 @@ static uint8_t *command_line_enter(int firstc, long count, int indent) // Make ccline empty, getcmdline() may try to use it. ccline.cmdbuff = NULL; + + if (ui_is_external(kUICmdline)) { + ui_call_cmdline_hide(ccline.level); + } + ccline.level--; return p; } } @@ -1830,14 +1838,7 @@ getcmdline ( int indent // indent for inside conditionals ) { - if (ui_is_external(kUICmdline)) { - ui_call_cmdline_enter(); - } - char_u *p = command_line_enter(firstc, count, indent); - if (ui_is_external(kUICmdline)) { - ui_call_cmdline_hide(); - } - return p; + return command_line_enter(firstc, count, indent); } /// Get a command line with a prompt @@ -2720,17 +2721,12 @@ draw_cmdline_no_arabicshape: void ui_ext_cmdline_show(void) { - Array content = ARRAY_DICT_INIT; - Array text = ARRAY_DICT_INIT; - ADD(text, STRING_OBJ(cstr_to_string("Normal"))); - ADD(text, STRING_OBJ(cstr_to_string((char *)(ccline.cmdbuff)))); - ADD(content, ARRAY_OBJ(text)); - char *firstc = (char []) { (char)ccline.cmdfirstc }; - String str = (String) { - .data = xmemdupz(firstc, 1), - .size = 1 - }; - ui_call_cmdline_show(content, ccline.cmdpos, str, cstr_to_string((char *)(ccline.cmdprompt))); + Array content = ARRAY_DICT_INIT; + Array text = ARRAY_DICT_INIT; + ADD(text, STRING_OBJ(cstr_to_string("Normal"))); + ADD(text, STRING_OBJ(cstr_to_string((char *)(ccline.cmdbuff)))); + ADD(content, ARRAY_OBJ(text)); + ui_call_cmdline_show(content, ccline.cmdpos, cchar_to_string((char)ccline.cmdfirstc), cstr_to_string((char *)(ccline.cmdprompt)), ccline.level); } /* @@ -2750,7 +2746,7 @@ void putcmdline(int c, int shift) draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos); msg_no_more = FALSE; } else { - ui_call_cmdline_char(cstr_to_string((char *)(&c)), shift); + ui_call_cmdline_char(cchar_to_string((char)(c)), shift, ccline.level); } cursorcmd(); ui_cursor_shape(); @@ -3178,7 +3174,7 @@ static void cursorcmd(void) return; if (ui_is_external(kUICmdline)) { - ui_call_cmdline_pos(ccline.cmdpos); + ui_call_cmdline_pos(ccline.cmdpos, ccline.level); return; } @@ -3200,7 +3196,7 @@ static void cursorcmd(void) void gotocmdline(int clr) { if (ui_is_external(kUICmdline)) { - return; + return; } msg_start(); if (cmdmsg_rl) diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 479f5c3b7d..479d40e959 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -7,19 +7,19 @@ if helpers.pending_win32(pending) then return end describe('External command line completion', function() local screen local shown = false - local firstc, prompt, content, pos, char, shift + local firstc, prompt, content, pos, char, shift, level, current_hide_level before_each(function() clear() screen = Screen.new(25, 5) screen:attach({rgb=true, ext_cmdline=true}) screen:set_on_event_handler(function(name, data) - if name == "cmdline_enter" then - shown = true - elseif name == "cmdline_hide" then + if name == "cmdline_hide" then shown = false + current_hide_level = data[1] elseif name == "cmdline_show" then - content, pos, firstc, prompt = unpack(data) + shown = true + content, pos, firstc, prompt, level = unpack(data) elseif name == "cmdline_char" then char, shift = unpack(data) elseif name == "cmdline_pos" then @@ -107,9 +107,9 @@ describe('External command line completion', function() eq("input", prompt) eq({{'Normal', 'default'}}, content) end) - feed('') - feed(':=1+2') + + feed(':') screen:expect([[ ^ | ~ | @@ -117,9 +117,45 @@ describe('External command line completion', function() ~ | | ]], nil, nil, function() - eq({{'Normal', '3'}}, content) + eq(1, level) + end) + + feed('=1+2') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({{'Normal', '1+2'}}, content) eq("\"", char) eq(1, shift) + eq(2, level) + end) + + feed('') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({{'Normal', '3'}}, content) + eq(2, current_hide_level) + eq(1, level) + end) + + feed('') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq(1, current_hide_level) end) end) -- cgit From 461ae698242458bffbf5fb68de89fe8b2a3defd2 Mon Sep 17 00:00:00 2001 From: Dongdong Zhou Date: Mon, 26 Jun 2017 11:19:40 +0100 Subject: ext_cmdline: Add function block support --- src/nvim/api/ui_events.in.h | 4 ++++ src/nvim/eval.c | 11 ++++++++++- test/functional/ui/cmdline_spec.lua | 39 ++++++++++++++++++++++++++++++++++++- 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h index 17eefbe1d6..5602dc6df3 100644 --- a/src/nvim/api/ui_events.in.h +++ b/src/nvim/api/ui_events.in.h @@ -75,5 +75,9 @@ void cmdline_char(String c, Integer shift, Integer level) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; void cmdline_hide(Integer level) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; +void cmdline_function_show(void) + FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; +void cmdline_function_hide(void) + FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; #endif // NVIM_API_UI_EVENTS_IN_H diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 3c9614dfcd..d5ff01e922 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -19816,6 +19816,10 @@ void ex_function(exarg_T *eap) goto errret_2; } + if (ui_is_external(kUICmdline)) { + ui_call_cmdline_function_show(); + } + // find extra arguments "range", "dict", "abort" and "closure" for (;; ) { p = skipwhite(p); @@ -19868,7 +19872,9 @@ void ex_function(exarg_T *eap) if (!eap->skip && did_emsg) goto erret; - msg_putchar('\n'); /* don't overwrite the function name */ + if (!ui_is_external(kUICmdline)) { + msg_putchar('\n'); /* don't overwrite the function name */ + } cmdline_row = msg_row; } @@ -20194,6 +20200,9 @@ ret_free: xfree(name); did_emsg |= saved_did_emsg; need_wait_return |= saved_wait_return; + if (ui_is_external(kUICmdline)) { + ui_call_cmdline_function_hide(); + } } /// Get a function name, translating "" and "". diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 479d40e959..9e2857bc95 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -7,7 +7,7 @@ if helpers.pending_win32(pending) then return end describe('External command line completion', function() local screen local shown = false - local firstc, prompt, content, pos, char, shift, level, current_hide_level + local firstc, prompt, content, pos, char, shift, level, current_hide_level, in_function before_each(function() clear() @@ -24,6 +24,10 @@ describe('External command line completion', function() char, shift = unpack(data) elseif name == "cmdline_pos" then pos = data[1] + elseif name == "cmdline_function_show" then + in_function = true + elseif name == "cmdline_function_hide" then + in_function = false end end) end) @@ -158,6 +162,39 @@ describe('External command line completion', function() eq(1, current_hide_level) end) + feed(':function Foo()') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq(true, in_function) + end) + + feed('line1') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq(true, in_function) + end) + + feed('endfunction') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq(false, in_function) + end) + end) end) end) -- cgit From fb389a6b4b1e6fedb559dc2e5845dd138e8ff264 Mon Sep 17 00:00:00 2001 From: Dongdong Zhou Date: Mon, 26 Jun 2017 15:27:49 +0100 Subject: ext_cmdline: added indent --- src/nvim/api/ui_events.in.h | 2 +- src/nvim/ex_getln.c | 6 +++++- test/functional/ui/cmdline_spec.lua | 17 +++++++++++++++-- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h index 5602dc6df3..700d99dc6b 100644 --- a/src/nvim/api/ui_events.in.h +++ b/src/nvim/api/ui_events.in.h @@ -67,7 +67,7 @@ void popupmenu_select(Integer selected) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; void tabline_update(Tabpage current, Array tabs) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; -void cmdline_show(Array content, Integer pos, String firstc, String prompt, Integer level) +void cmdline_show(Array content, Integer pos, String firstc, String prompt, Integer indent, Integer level) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; void cmdline_pos(Integer pos, Integer level) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 548459a8ce..6f941e66ef 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -2726,7 +2726,11 @@ void ui_ext_cmdline_show(void) ADD(text, STRING_OBJ(cstr_to_string("Normal"))); ADD(text, STRING_OBJ(cstr_to_string((char *)(ccline.cmdbuff)))); ADD(content, ARRAY_OBJ(text)); - ui_call_cmdline_show(content, ccline.cmdpos, cchar_to_string((char)ccline.cmdfirstc), cstr_to_string((char *)(ccline.cmdprompt)), ccline.level); + ui_call_cmdline_show(content, ccline.cmdpos, + cchar_to_string((char)ccline.cmdfirstc), + cstr_to_string((char *)(ccline.cmdprompt)), + ccline.cmdindent, + ccline.level); } /* diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 9e2857bc95..1e30ba1449 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -7,7 +7,7 @@ if helpers.pending_win32(pending) then return end describe('External command line completion', function() local screen local shown = false - local firstc, prompt, content, pos, char, shift, level, current_hide_level, in_function + local firstc, prompt, content, pos, char, shift, indent, level, current_hide_level, in_function before_each(function() clear() @@ -19,7 +19,7 @@ describe('External command line completion', function() current_hide_level = data[1] elseif name == "cmdline_show" then shown = true - content, pos, firstc, prompt, level = unpack(data) + content, pos, firstc, prompt, indent, level = unpack(data) elseif name == "cmdline_char" then char, shift = unpack(data) elseif name == "cmdline_pos" then @@ -171,6 +171,7 @@ describe('External command line completion', function() | ]], nil, nil, function() eq(true, in_function) + eq(2, indent) end) feed('line1') @@ -182,6 +183,7 @@ describe('External command line completion', function() | ]], nil, nil, function() eq(true, in_function) + eq(2, indent) end) feed('endfunction') @@ -195,6 +197,17 @@ describe('External command line completion', function() eq(false, in_function) end) + feed(':sign') + screen:expect([[ + | + [No Name] | + :sign^ | + [Command Line] | + | + ]], nil, nil, function() + eq(false, in_function) + end) + end) end) end) -- cgit From 5ad591ef2d0ef184f78c728b1774c2a55fe2e581 Mon Sep 17 00:00:00 2001 From: Dongdong Zhou Date: Tue, 27 Jun 2017 02:20:27 +0100 Subject: ext_cmdline: lint --- src/nvim/api/ui_events.in.h | 17 +++++++++-------- src/nvim/eval.c | 2 +- src/nvim/ex_getln.c | 7 ++++--- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h index 700d99dc6b..bb1084c838 100644 --- a/src/nvim/api/ui_events.in.h +++ b/src/nvim/api/ui_events.in.h @@ -66,18 +66,19 @@ void popupmenu_hide(void) void popupmenu_select(Integer selected) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; void tabline_update(Tabpage current, Array tabs) - FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; -void cmdline_show(Array content, Integer pos, String firstc, String prompt, Integer indent, Integer level) - FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; + FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; +void cmdline_show(Array content, Integer pos, String firstc, String prompt, + Integer indent, Integer level) + FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; void cmdline_pos(Integer pos, Integer level) - FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; + FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; void cmdline_char(String c, Integer shift, Integer level) - FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; + FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; void cmdline_hide(Integer level) - FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; + FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; void cmdline_function_show(void) - FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; + FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; void cmdline_function_hide(void) - FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; + FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; #endif // NVIM_API_UI_EVENTS_IN_H diff --git a/src/nvim/eval.c b/src/nvim/eval.c index d5ff01e922..5f655cdc7b 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -19873,7 +19873,7 @@ void ex_function(exarg_T *eap) goto erret; if (!ui_is_external(kUICmdline)) { - msg_putchar('\n'); /* don't overwrite the function name */ + msg_putchar('\n'); // don't overwrite the function name } cmdline_row = msg_row; } diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 6f941e66ef..93c060b4b7 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -2744,11 +2744,12 @@ void putcmdline(int c, int shift) return; } if (!ui_is_external(kUICmdline)) { - msg_no_more = TRUE; + msg_no_more = true; msg_putchar(c); - if (shift) + if (shift) { draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos); - msg_no_more = FALSE; + } + msg_no_more = false; } else { ui_call_cmdline_char(cchar_to_string((char)(c)), shift, ccline.level); } -- cgit From 22402fb99d05191cf140293cfb5f67902e78a8a8 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Wed, 16 Aug 2017 12:19:29 +0200 Subject: ext_cmdline: add support for highlighting --- src/nvim/api/private/helpers.c | 17 ++++++++ src/nvim/ex_getln.c | 31 ++++++++++++--- test/functional/ui/cmdline_spec.lua | 77 ++++++++++++++++++++++++++++++++++--- 3 files changed, 114 insertions(+), 11 deletions(-) diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index f00fbf69ea..2944925a9c 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -703,6 +703,23 @@ String cstr_to_string(const char *str) }; } +/// Copies buffer to an allocated String. +/// The resulting string is also NUL-terminated, to facilitate interoperating +/// with code using C strings. +/// +/// @param buf the buffer to copy +/// @param size length of the buffer +/// @return the resulting String, if the input string was NULL, an +/// empty String is returned +String cbuf_to_string(const char *buf, size_t size) + FUNC_ATTR_NONNULL_ALL +{ + return (String) { + .data = xmemdupz(buf, size), + .size = size + }; +} + /// Creates a String using the given C string. Unlike /// cstr_to_string this function DOES NOT copy the C string. /// diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 93c060b4b7..624a108bd4 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -2372,6 +2372,7 @@ static bool color_cmdline(const CmdlineInfo *const colored_ccline, FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { bool printed_errmsg = false; + #define PRINT_ERRMSG(...) \ do { \ msg_putchar('\n'); \ @@ -2405,7 +2406,7 @@ static bool color_cmdline(const CmdlineInfo *const colored_ccline, static unsigned prev_prompt_id = UINT_MAX; static int prev_prompt_errors = 0; - Callback color_cb = { .type = kCallbackNone }; + Callback color_cb = CALLBACK_NONE; bool can_free_cb = false; TryState tstate; Error err = ERROR_INIT; @@ -2722,10 +2723,30 @@ draw_cmdline_no_arabicshape: void ui_ext_cmdline_show(void) { Array content = ARRAY_DICT_INIT; - Array text = ARRAY_DICT_INIT; - ADD(text, STRING_OBJ(cstr_to_string("Normal"))); - ADD(text, STRING_OBJ(cstr_to_string((char *)(ccline.cmdbuff)))); - ADD(content, ARRAY_OBJ(text)); + if (kv_size(last_ccline_colors.colors)) { + for (size_t i = 0; i < kv_size(last_ccline_colors.colors); i++) { + CmdlineColorChunk chunk = kv_A(last_ccline_colors.colors, i); + Array item = ARRAY_DICT_INIT; + + if (chunk.attr) { + attrentry_T *aep = syn_cterm_attr2entry(chunk.attr); + // TODO(bfredl): this desicion could be delayed by making attr_code a + // recognized type + HlAttrs rgb_attrs = attrentry2hlattrs(aep, true); + ADD(item, DICTIONARY_OBJ(hlattrs2dict(rgb_attrs))); + } else { + ADD(item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT)); + } + ADD(item, STRING_OBJ(cbuf_to_string((char *)ccline.cmdbuff + chunk.start, + chunk.end-chunk.start))); + ADD(content, ARRAY_OBJ(item)); + } + } else { + Array item = ARRAY_DICT_INIT; + ADD(item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT)); + ADD(item, STRING_OBJ(cstr_to_string((char *)(ccline.cmdbuff)))); + ADD(content, ARRAY_OBJ(item)); + } ui_call_cmdline_show(content, ccline.cmdpos, cchar_to_string((char)ccline.cmdfirstc), cstr_to_string((char *)(ccline.cmdprompt)), diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 1e30ba1449..8d694052ee 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -1,6 +1,7 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local clear, feed, eq = helpers.clear, helpers.feed, helpers.eq +local source = helpers.source if helpers.pending_win32(pending) then return end @@ -36,6 +37,22 @@ describe('External command line completion', function() screen:detach() end) + function expect_cmdline(expected) + local attr_ids = screen._default_attr_ids + local attr_ignore = screen._default_attr_ignore + local actual = '' + for _, chunk in ipairs(content or {}) do + local attrs, text = chunk[1], chunk[2] + if screen:_equal_attrs(attrs, {}) then + actual = actual..text + else + local attr_id = screen:_get_attr_id(attr_ids, attr_ignore, attrs) + actual = actual..'{' .. attr_id .. ':' .. text .. '}' + end + end + eq(expected, actual) + end + describe("'cmdline'", function() it(':sign', function() feed(':') @@ -58,7 +75,7 @@ describe('External command line completion', function() ~ | | ]], nil, nil, function() - eq({{'Normal', 'sign'}}, content) + eq({{{}, 'sign'}}, content) eq(4, pos) end) @@ -70,7 +87,7 @@ describe('External command line completion', function() ~ | | ]], nil, nil, function() - eq({{'Normal', 'sign'}}, content) + eq({{{}, 'sign'}}, content) eq(true, shown) eq(3, pos) end) @@ -83,7 +100,7 @@ describe('External command line completion', function() ~ | | ]], nil, nil, function() - eq({{'Normal', 'sin'}}, content) + eq({{{}, 'sin'}}, content) eq(true, shown) eq(2, pos) end) @@ -109,7 +126,7 @@ describe('External command line completion', function() ]], nil, nil, function() eq(true, shown) eq("input", prompt) - eq({{'Normal', 'default'}}, content) + eq({{{}, 'default'}}, content) end) feed('') @@ -132,7 +149,7 @@ describe('External command line completion', function() ~ | | ]], nil, nil, function() - eq({{'Normal', '1+2'}}, content) + eq({{{}, '1+2'}}, content) eq("\"", char) eq(1, shift) eq(2, level) @@ -146,7 +163,7 @@ describe('External command line completion', function() ~ | | ]], nil, nil, function() - eq({{'Normal', '3'}}, content) + eq({{{}, '3'}}, content) eq(2, current_hide_level) eq(1, level) end) @@ -210,4 +227,52 @@ describe('External command line completion', function() end) end) + + it('works with highlighted cmdline', function() + source([[ + highlight RBP1 guibg=Red + highlight RBP2 guibg=Yellow + highlight RBP3 guibg=Green + highlight RBP4 guibg=Blue + let g:NUM_LVLS = 4 + function RainBowParens(cmdline) + let ret = [] + let i = 0 + let lvl = 0 + while i < len(a:cmdline) + if a:cmdline[i] is# '(' + call add(ret, [i, i + 1, 'RBP' . ((lvl % g:NUM_LVLS) + 1)]) + let lvl += 1 + elseif a:cmdline[i] is# ')' + let lvl -= 1 + call add(ret, [i, i + 1, 'RBP' . ((lvl % g:NUM_LVLS) + 1)]) + endif + let i += 1 + endwhile + return ret + endfunction + map :let x = input({'prompt':'>','highlight':'RainBowParens'}) + "map :let x = input({'prompt':'>'}) + ]]) + screen:set_default_attr_ids({ + RBP1={background = Screen.colors.Red}, + RBP2={background = Screen.colors.Yellow}, + RBP3={background = Screen.colors.Green}, + RBP4={background = Screen.colors.Blue}, + EOB={bold = true, foreground = Screen.colors.Blue1}, + ERR={foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + SK={foreground = Screen.colors.Blue}, + PE={bold = true, foreground = Screen.colors.SeaGreen4} + }) + feed('(a(b)a)') + screen:expect([[ + ^ | + {EOB:~ }| + {EOB:~ }| + {EOB:~ }| + | + ]], nil, nil, function() + expect_cmdline('{RBP1:(}a{RBP2:(}b{RBP2:)}a{RBP1:)}') + end) + end) end) -- cgit From ddfc077da468450d1fab81fe3b3f594bb6ebf6dd Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Wed, 16 Aug 2017 13:36:02 +0200 Subject: ext_cmdline: disable some redraws --- src/nvim/ex_getln.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 624a108bd4..0e620e59d8 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -1144,7 +1144,7 @@ static int command_line_handle_key(CommandLineState *s) xfree(ccline.cmdbuff); // no commandline to return ccline.cmdbuff = NULL; - if (!cmd_silent) { + if (!cmd_silent && !ui_is_external(kUICmdline)) { if (cmdmsg_rl) { msg_col = Columns; } else { @@ -1596,9 +1596,14 @@ static int command_line_handle_key(CommandLineState *s) s->do_abbr = false; // don't do abbreviation now // may need to remove ^ when composing char was typed if (enc_utf8 && utf_iscomposing(s->c) && !cmd_silent) { - draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos); - msg_putchar(' '); - cursorcmd(); + if (ui_is_external(kUICmdline)) { + // TODO(bfredl): why not make unputcmdline also work with true? + unputcmdline(); + } else { + draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos); + msg_putchar(' '); + cursorcmd(); + } } break; @@ -2778,22 +2783,19 @@ void putcmdline(int c, int shift) ui_cursor_shape(); } -/* - * Undo a putcmdline(c, FALSE). - */ +/// Undo a putcmdline(c, FALSE). void unputcmdline(void) { - if (cmd_silent) + if (cmd_silent) { return; - msg_no_more = TRUE; - if (ccline.cmdlen == ccline.cmdpos) + } + msg_no_more = true; + if (ccline.cmdlen == ccline.cmdpos && !ui_is_external(kUICmdline)) { msg_putchar(' '); - else if (has_mbyte) - draw_cmdline(ccline.cmdpos, - (*mb_ptr2len)(ccline.cmdbuff + ccline.cmdpos)); - else - draw_cmdline(ccline.cmdpos, 1); - msg_no_more = FALSE; + } else { + draw_cmdline(ccline.cmdpos, mb_ptr2len(ccline.cmdbuff + ccline.cmdpos)); + } + msg_no_more = false; cursorcmd(); ui_cursor_shape(); } -- cgit From a68817f56517a31943806bd0b5a0030cdd35e182 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Wed, 16 Aug 2017 13:57:58 +0200 Subject: ext_cmdline: extend "function" to generic "block" mechanism --- src/nvim/api/ui_events.in.h | 7 +++++-- src/nvim/eval.c | 13 +++++++++---- src/nvim/ex_getln.c | 28 ++++++++++++++++++++++++++++ test/functional/ui/cmdline_spec.lua | 18 +++++++++--------- 4 files changed, 51 insertions(+), 15 deletions(-) diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h index bb1084c838..764078c6bd 100644 --- a/src/nvim/api/ui_events.in.h +++ b/src/nvim/api/ui_events.in.h @@ -67,6 +67,7 @@ void popupmenu_select(Integer selected) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; void tabline_update(Tabpage current, Array tabs) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; + void cmdline_show(Array content, Integer pos, String firstc, String prompt, Integer indent, Integer level) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; @@ -76,9 +77,11 @@ void cmdline_char(String c, Integer shift, Integer level) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; void cmdline_hide(Integer level) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; -void cmdline_function_show(void) +void cmdline_block_show(Array lines) + FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; +void cmdline_block_append(Array lines) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; -void cmdline_function_hide(void) +void cmdline_block_hide(void) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; #endif // NVIM_API_UI_EVENTS_IN_H diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 5f655cdc7b..50044718b6 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -19643,6 +19643,7 @@ void ex_function(exarg_T *eap) int todo; hashitem_T *hi; int sourcing_lnum_off; + bool show_block = false; /* * ":function" without argument: list functions. @@ -19816,8 +19817,9 @@ void ex_function(exarg_T *eap) goto errret_2; } - if (ui_is_external(kUICmdline)) { - ui_call_cmdline_function_show(); + if (KeyTyped && ui_is_external(kUICmdline)) { + show_block = true; + ui_ext_cmdline_block_append(0, (const char *)eap->cmd); } // find extra arguments "range", "dict", "abort" and "closure" @@ -19908,6 +19910,9 @@ void ex_function(exarg_T *eap) EMSG(_("E126: Missing :endfunction")); goto erret; } + if (show_block) { + ui_ext_cmdline_block_append(indent, (const char *)theline); + } /* Detect line continuation: sourcing_lnum increased more than one. */ if (sourcing_lnum > sourcing_lnum_off + 1) @@ -20200,8 +20205,8 @@ ret_free: xfree(name); did_emsg |= saved_did_emsg; need_wait_return |= saved_wait_return; - if (ui_is_external(kUICmdline)) { - ui_call_cmdline_function_hide(); + if (show_block) { + ui_ext_cmdline_block_leave(); } } diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 0e620e59d8..50cccc8d10 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -186,6 +186,8 @@ static int cmd_showtail; /* Only show path tail in lists ? */ static int new_cmdpos; /* position set by set_cmdline_pos() */ +static Array cmdline_block; ///< currently displayed block of context + /* * Type used by call_user_expand_func */ @@ -2759,6 +2761,32 @@ void ui_ext_cmdline_show(void) ccline.level); } +void ui_ext_cmdline_block_append(int indent, const char *line) +{ + char *buf = xmallocz(indent + strlen(line)); + memset(buf, ' ', indent); + memcpy(buf+indent, line, strlen(line)); + + Array item = ARRAY_DICT_INIT; + ADD(item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT)); + ADD(item, STRING_OBJ(cstr_as_string(buf))); + Array content = ARRAY_DICT_INIT; + ADD(content, ARRAY_OBJ(item)); + ADD(cmdline_block, ARRAY_OBJ(content)); + if (cmdline_block.size > 1) { + ui_call_cmdline_block_append(copy_array(content)); + } else { + ui_call_cmdline_block_show(copy_array(cmdline_block)); + } +} + +void ui_ext_cmdline_block_leave(void) +{ + api_free_array(cmdline_block); + ui_call_cmdline_block_hide(); +} + + /* * Put a character on the command line. Shifts the following text to the * right when "shift" is TRUE. Used for CTRL-V, CTRL-K, etc. diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 8d694052ee..3b63a3bd9e 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -8,7 +8,7 @@ if helpers.pending_win32(pending) then return end describe('External command line completion', function() local screen local shown = false - local firstc, prompt, content, pos, char, shift, indent, level, current_hide_level, in_function + local firstc, prompt, content, pos, char, shift, indent, level, current_hide_level, in_block before_each(function() clear() @@ -25,10 +25,10 @@ describe('External command line completion', function() char, shift = unpack(data) elseif name == "cmdline_pos" then pos = data[1] - elseif name == "cmdline_function_show" then - in_function = true - elseif name == "cmdline_function_hide" then - in_function = false + elseif name == "cmdline_block_show" then + in_block = true + elseif name == "cmdline_block_hide" then + in_block = false end end) end) @@ -187,7 +187,7 @@ describe('External command line completion', function() ~ | | ]], nil, nil, function() - eq(true, in_function) + eq(true, in_block) eq(2, indent) end) @@ -199,7 +199,7 @@ describe('External command line completion', function() ~ | | ]], nil, nil, function() - eq(true, in_function) + eq(true, in_block) eq(2, indent) end) @@ -211,7 +211,7 @@ describe('External command line completion', function() ~ | | ]], nil, nil, function() - eq(false, in_function) + eq(false, in_block) end) feed(':sign') @@ -222,7 +222,7 @@ describe('External command line completion', function() [Command Line] | | ]], nil, nil, function() - eq(false, in_function) + eq(false, in_block) end) end) -- cgit From f2aaa4ae8b84f74666b4379b391f333f34868a45 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Wed, 16 Aug 2017 15:38:12 +0200 Subject: ext_cmdline: rename cmdline_char to cmdline_special_char --- src/nvim/api/ui_events.in.h | 2 +- src/nvim/ex_getln.c | 3 ++- test/functional/ui/cmdline_spec.lua | 4 +++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h index 764078c6bd..65357d008a 100644 --- a/src/nvim/api/ui_events.in.h +++ b/src/nvim/api/ui_events.in.h @@ -73,7 +73,7 @@ void cmdline_show(Array content, Integer pos, String firstc, String prompt, FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; void cmdline_pos(Integer pos, Integer level) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; -void cmdline_char(String c, Integer shift, Integer level) +void cmdline_special_char(String c, Boolean shift, Integer level) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; void cmdline_hide(Integer level) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 50cccc8d10..b9cf7b977c 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -2805,7 +2805,8 @@ void putcmdline(int c, int shift) } msg_no_more = false; } else { - ui_call_cmdline_char(cchar_to_string((char)(c)), shift, ccline.level); + ui_call_cmdline_special_char(cchar_to_string((char)(c)), shift, + ccline.level); } cursorcmd(); ui_cursor_shape(); diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 3b63a3bd9e..33835dd9e4 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -21,7 +21,9 @@ describe('External command line completion', function() elseif name == "cmdline_show" then shown = true content, pos, firstc, prompt, indent, level = unpack(data) - elseif name == "cmdline_char" then + -- FIXME: + --char, shift = nil, nil + elseif name == "cmdline_special_char" then char, shift = unpack(data) elseif name == "cmdline_pos" then pos = data[1] -- cgit From 87a723963e720612d16c7cfb577d529f58a3d4d1 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Wed, 16 Aug 2017 15:38:23 +0200 Subject: ext_cmdline: documentation --- runtime/doc/msgpack_rpc.txt | 62 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 14 deletions(-) diff --git a/runtime/doc/msgpack_rpc.txt b/runtime/doc/msgpack_rpc.txt index 77938fbd82..9601e239f2 100644 --- a/runtime/doc/msgpack_rpc.txt +++ b/runtime/doc/msgpack_rpc.txt @@ -302,6 +302,8 @@ kind. Set the default foreground, background and special colors respectively. + + *ui-event-highlight_set* ["highlight_set", attrs] Set the attributes that the next text put on the screen will have. `attrs` is a dict with the keys below. Any absent key is reset @@ -443,25 +445,57 @@ states might be represented as separate modes. tabs: List of Dicts [{ "tab": Tabpage, "name": String }, ...] *ui-ext-cmdline* -["cmdline_enter"] - Enter the cmdline. +["cmdline_show", content, pos, firstc, prompt, indent, level] + content: List of [attrs, string] + [[{}, "t"], [attrs, "est"], ...] + When cmdline_external is set to true, nvim will not draw the cmdline + on the grid, instead nvim will send ui events of the cmdline content + and cursor position to the remote ui. The `content` is the full content + that should be displayed in the cmdline, and the `pos` is the position + of the cursor that in the cmdline. This event will be triggered when + you type in the cmdline. The content is divided into chunks with + different highlight attributes represented as a dict, see + |ui-event-highlight_set|. + + `firstc` and `prompt` are text, that if non-empty should be + displayed in front of the command line. `firstc` always indicates + built in command lines such as `:` (ex command) and `/` `?` (search), + while `prompt` is an |input()| prompt. `indent` tells how many spaces + the content should be indented + + The command line in nvim can be invoked recursively, for instance by + typing `=` at the command line prompt. The `level` field is used + to distinguish different command lines active at the same time. The + first invoked command line will always have level 1, and the next + recursively invoked prompt will have level 2. Also, a command line + invoked while in command line window will have a higher level than + than the edited command line. + +["cmdline_pos", pos, level] + Change the cursor position in the cmdline. + +["cmdline_special_char", c, shift, level] + Display a special char in the cmdline at the cursor position. This is + typically used to indicate a pending state, like right after Ctrl-V. + if shift is true the text after the cursor should be shifted, + otherwise it should overshadow the char at the cursor. + Should be hidden at next cmdline_char + ["cmdline_hide"] Hide the cmdline. -["cmdline_show", content, pos, firstc, prompt] - content: List of [highlight group, string] - [["Normal", "t"], ["Search", "est"], ...] - When cmdline_external is set to true, nvim will not draw the cmdline - on the grad, instead nvim will send ui events of the cmdline content - and cursor position to the remote ui. The content is the full content - that should be displayed in the cmdline, and the pos is the position - of the cursor that in the cmdline. This event will be triggered when - you type in the cmdline. +["cmdline_block_show", lines] + Show a block of context to the current command line. This occurs for + instance if a function is interactively defined at the command line. + `lines` is a list of lines where each line is represented as a list of + highlighted chunks, just like `contents` of |ui-event-cmdline_show|. + +["cmdline_block_append", line] + Append a line at the end of the currently shown block. -["cmdline_pos", pos] - When you move your cursor, nvim will send out this event which tells - you the current position of the cursor in the cmdline. +["cmdline_block_hide"] + Hide the block. ============================================================================== vim:tw=78:ts=8:noet:ft=help:norl: -- cgit From 91f94bfef80c1f39a597dd47806e8dbe45a22578 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Thu, 17 Aug 2017 12:26:33 +0200 Subject: ext_cmdline: restructure and improve tests --- test/functional/ui/cmdline_spec.lua | 450 ++++++++++++++++++++++-------------- 1 file changed, 274 insertions(+), 176 deletions(-) diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 33835dd9e4..3f9ce8ad67 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -2,35 +2,42 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local clear, feed, eq = helpers.clear, helpers.feed, helpers.eq local source = helpers.source +local ok = helpers.ok if helpers.pending_win32(pending) then return end -describe('External command line completion', function() +describe('external cmdline', function() local screen - local shown = false - local firstc, prompt, content, pos, char, shift, indent, level, current_hide_level, in_block + local last_level = 0 + local cmdline = {} + local block = nil before_each(function() clear() screen = Screen.new(25, 5) screen:attach({rgb=true, ext_cmdline=true}) screen:set_on_event_handler(function(name, data) - if name == "cmdline_hide" then - shown = false - current_hide_level = data[1] - elseif name == "cmdline_show" then - shown = true - content, pos, firstc, prompt, indent, level = unpack(data) - -- FIXME: - --char, shift = nil, nil + if name == "cmdline_show" then + local content, pos, firstc, prompt, indent, level = unpack(data) + ok(level > 0) + cmdline[level] = {content=content, pos=pos, firstc=firstc, + prompt=prompt, indent=indent} + last_level = level + elseif name == "cmdline_hide" then + local level = data[1] + cmdline[level] = nil elseif name == "cmdline_special_char" then - char, shift = unpack(data) + local char, shift, level = unpack(data) + cmdline[level].special = {char, shift} elseif name == "cmdline_pos" then - pos = data[1] + local pos, level = unpack(data) + cmdline[level].pos = pos elseif name == "cmdline_block_show" then - in_block = true + block = data[1] + elseif name == "cmdline_block_append" then + block[#block+1] = data[1] elseif name == "cmdline_block_hide" then - in_block = false + block = nil end end) end) @@ -39,11 +46,11 @@ describe('External command line completion', function() screen:detach() end) - function expect_cmdline(expected) + local function expect_cmdline(level, expected) local attr_ids = screen._default_attr_ids local attr_ignore = screen._default_attr_ignore local actual = '' - for _, chunk in ipairs(content or {}) do + for _, chunk in ipairs(cmdline[level] and cmdline[level].content or {}) do local attrs, text = chunk[1], chunk[2] if screen:_equal_attrs(attrs, {}) then actual = actual..text @@ -55,181 +62,272 @@ describe('External command line completion', function() eq(expected, actual) end - describe("'cmdline'", function() - it(':sign', function() - feed(':') - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - | - ]], nil, nil, function() - eq(true, shown) - eq(':', firstc) - end) + it('works', function() + feed(':') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq(1, last_level) + eq({{ + content = { { {}, "" } }, + firstc = ":", + indent = 0, + pos = 0, + prompt = "" + }}, cmdline) + end) - feed('sign') - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - | - ]], nil, nil, function() - eq({{{}, 'sign'}}, content) - eq(4, pos) - end) + feed('sign') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({{ + content = { { {}, "sign" } }, + firstc = ":", + indent = 0, + pos = 4, + prompt = "" + }}, cmdline) + end) - feed('') - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - | - ]], nil, nil, function() - eq({{{}, 'sign'}}, content) - eq(true, shown) - eq(3, pos) - end) + feed('') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({{ + content = { { {}, "sign" } }, + firstc = ":", + indent = 0, + pos = 3, + prompt = "" + }}, cmdline) + end) - feed('') - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - | - ]], nil, nil, function() - eq({{{}, 'sin'}}, content) - eq(true, shown) - eq(2, pos) - end) + feed('') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({{ + content = { { {}, "sin" } }, + firstc = ":", + indent = 0, + pos = 2, + prompt = "" + }}, cmdline) + end) - feed('') - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - | - ]], nil, nil, function() - eq(false, shown) - end) + feed('') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({}, cmdline) + end) + end) - feed(':call input("input", "default")') - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - | - ]], nil, nil, function() - eq(true, shown) - eq("input", prompt) - eq({{{}, 'default'}}, content) - end) - feed('') + it("works with input()", function() + feed(':call input("input", "default")') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({{ + content = { { {}, "default" } }, + firstc = "", + indent = 0, + pos = 7, + prompt = "input" + }}, cmdline) + end) + feed('') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({}, cmdline) + end) - feed(':') - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - | - ]], nil, nil, function() - eq(1, level) - end) + end) - feed('=1+2') - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - | - ]], nil, nil, function() - eq({{{}, '1+2'}}, content) - eq("\"", char) - eq(1, shift) - eq(2, level) - end) + it("works with special chars and nested cmdline", function() + feed(':xx') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({{ + content = { { {}, "xx" } }, + firstc = ":", + indent = 0, + pos = 2, + prompt = "", + special = {'"', true}, + }}, cmdline) + end) - feed('') - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - | - ]], nil, nil, function() - eq({{{}, '3'}}, content) - eq(2, current_hide_level) - eq(1, level) - end) + feed('=') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({{ + content = { { {}, "xx" } }, + firstc = ":", + indent = 0, + pos = 2, + prompt = "", + special = {'"', true}, + },{ + content = { { {}, "" } }, + firstc = "=", + indent = 0, + pos = 0, + prompt = "", + }}, cmdline) + end) - feed('') - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - | - ]], nil, nil, function() - eq(1, current_hide_level) - end) + feed('1+2') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({{ + content = { { {}, "xx" } }, + firstc = ":", + indent = 0, + pos = 2, + prompt = "", + special = {'"', true}, + },{ + content = { { {}, "1+2" } }, + firstc = "=", + indent = 0, + pos = 3, + prompt = "", + }}, cmdline) + end) - feed(':function Foo()') - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - | - ]], nil, nil, function() - eq(true, in_block) - eq(2, indent) - end) + feed('') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({{ + content = { { {}, "xx3" } }, + firstc = ":", + indent = 0, + pos = 3, + prompt = "", + }}, cmdline) + end) - feed('line1') - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - | - ]], nil, nil, function() - eq(true, in_block) - eq(2, indent) - end) + feed('') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({}, cmdline) + end) + end) - feed('endfunction') - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - | - ]], nil, nil, function() - eq(false, in_block) - end) + it("works with function definitions", function() + feed(':function Foo()') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({{ + content = { { {}, "" } }, + firstc = ":", + indent = 2, + pos = 0, + prompt = "", + }}, cmdline) + eq({{{{}, 'function Foo()'}}}, block) + end) - feed(':sign') - screen:expect([[ - | - [No Name] | - :sign^ | - [Command Line] | - | - ]], nil, nil, function() - eq(false, in_block) - end) + feed('line1') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({{{{}, 'function Foo()'}}, + {{{}, ' line1'}}}, block) + end) + feed('endfunction') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq(nil, block) end) end) + pending("works with cmdline window", function() + feed(':sign') + screen:expect([[ + | + [No Name] | + :sign^ | + [Command Line] | + | + ]], nil, nil, function() + eq({}, cmdline) + end) + + feed(":blargh") + end) + it('works with highlighted cmdline', function() source([[ highlight RBP1 guibg=Red @@ -274,7 +372,7 @@ describe('External command line completion', function() {EOB:~ }| | ]], nil, nil, function() - expect_cmdline('{RBP1:(}a{RBP2:(}b{RBP2:)}a{RBP1:)}') + expect_cmdline(1, '{RBP1:(}a{RBP2:(}b{RBP2:)}a{RBP1:)}') end) end) end) -- cgit From 2050e6604632e190a04d52829f4469f1ef7f7018 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sun, 20 Aug 2017 16:30:09 +0200 Subject: ext_cmdline: turn nested cmdlines into a linked list --- src/nvim/ex_getln.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index b9cf7b977c..2ac9ecdc2b 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -92,6 +92,7 @@ struct cmdline_info { unsigned prompt_id; ///< Prompt number, used to disable coloring on errors. Callback highlight_callback; ///< Callback used for coloring user input. int level; // current cmdline level + struct cmdline_info *prev_ccline; ///< pointer to saved cmdline state }; /// Last value of prompt_id, incremented when doing new prompt static unsigned last_prompt_id = 0; @@ -2958,9 +2959,6 @@ void put_on_cmdline(char_u *str, int len, int redraw) msg_check(); } -static struct cmdline_info prev_ccline; -static int prev_ccline_used = FALSE; - /* * Save ccline, because obtaining the "=" register may execute "normal :cmd" * and overwrite it. But get_cmdline_str() may need it, thus make it @@ -2968,12 +2966,8 @@ static int prev_ccline_used = FALSE; */ static void save_cmdline(struct cmdline_info *ccp) { - if (!prev_ccline_used) { - memset(&prev_ccline, 0, sizeof(struct cmdline_info)); - prev_ccline_used = TRUE; - } - *ccp = prev_ccline; - prev_ccline = ccline; + *ccp = ccline; + ccline.prev_ccline = ccp; ccline.cmdbuff = NULL; ccline.cmdprompt = NULL; ccline.xpc = NULL; @@ -2984,8 +2978,7 @@ static void save_cmdline(struct cmdline_info *ccp) */ static void restore_cmdline(struct cmdline_info *ccp) { - ccline = prev_ccline; - prev_ccline = *ccp; + ccline = *ccp; } /* @@ -5312,13 +5305,15 @@ int get_history_idx(int histype) */ static struct cmdline_info *get_ccline_ptr(void) { - if ((State & CMDLINE) == 0) + if ((State & CMDLINE) == 0) { return NULL; - if (ccline.cmdbuff != NULL) + } else if (ccline.cmdbuff != NULL) { return &ccline; - if (prev_ccline_used && prev_ccline.cmdbuff != NULL) - return &prev_ccline; - return NULL; + } else if (ccline.prev_ccline && ccline.prev_ccline->cmdbuff != NULL) { + return ccline.prev_ccline; + } else { + return NULL; + } } /* -- cgit From bed0a3a8428027af32602ccb169e81767c55e257 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sun, 20 Aug 2017 17:47:42 +0200 Subject: ext_cmdline: implement redraw! --- src/nvim/ex_getln.c | 166 +++++++++++++++++++++--------------- src/nvim/screen.c | 5 +- test/functional/ui/cmdline_spec.lua | 54 +++++++++--- 3 files changed, 145 insertions(+), 80 deletions(-) diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 2ac9ecdc2b..933aea7b93 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -67,6 +67,30 @@ #include "nvim/api/private/helpers.h" #include "nvim/highlight_defs.h" +/// Command-line colors: one chunk +/// +/// Defines a region which has the same highlighting. +typedef struct { + int start; ///< Colored chunk start. + int end; ///< Colored chunk end (exclusive, > start). + int attr; ///< Highlight attr. +} CmdlineColorChunk; + +/// Command-line colors +/// +/// Holds data about all colors. +typedef kvec_t(CmdlineColorChunk) CmdlineColors; + +/// Command-line coloring +/// +/// Holds both what are the colors and what have been colored. Latter is used to +/// suppress unnecessary calls to coloring callbacks. +typedef struct { + unsigned prompt_id; ///< ID of the prompt which was colored last. + char *cmdbuff; ///< What exactly was colored last time or NULL. + CmdlineColors colors; ///< Last colors. +} ColoredCmdline; + /* * Variables shared between getcmdline(), redrawcmdline() and others. * These need to be saved when using CTRL-R |, that's why they are in a @@ -91,8 +115,11 @@ struct cmdline_info { int input_fn; // when TRUE Invoked for input() function unsigned prompt_id; ///< Prompt number, used to disable coloring on errors. Callback highlight_callback; ///< Callback used for coloring user input. + ColoredCmdline last_colors; ///< Last cmdline colors int level; // current cmdline level struct cmdline_info *prev_ccline; ///< pointer to saved cmdline state + char special_char; ///< last putcmdline char (used for redraws) + bool special_shift; ///< shift of last putcmdline char }; /// Last value of prompt_id, incremented when doing new prompt static unsigned last_prompt_id = 0; @@ -145,36 +172,6 @@ typedef struct command_line_state { struct cmdline_info save_ccline; } CommandLineState; -/// Command-line colors: one chunk -/// -/// Defines a region which has the same highlighting. -typedef struct { - int start; ///< Colored chunk start. - int end; ///< Colored chunk end (exclusive, > start). - int attr; ///< Highlight attr. -} CmdlineColorChunk; - -/// Command-line colors -/// -/// Holds data about all colors. -typedef kvec_t(CmdlineColorChunk) CmdlineColors; - -/// Command-line coloring -/// -/// Holds both what are the colors and what have been colored. Latter is used to -/// suppress unnecessary calls to coloring callbacks. -typedef struct { - unsigned prompt_id; ///< ID of the prompt which was colored last. - char *cmdbuff; ///< What exactly was colored last time or NULL. - CmdlineColors colors; ///< Last colors. -} ColoredCmdline; - -/// Last command-line colors. -ColoredCmdline last_ccline_colors = { - .cmdbuff = NULL, - .colors = KV_INITIAL_VALUE -}; - typedef struct cmdline_info CmdlineInfo; /* The current cmdline_info. It is initialized in getcmdline() and after that @@ -242,7 +239,6 @@ static uint8_t *command_line_enter(int firstc, long count, int indent) cmd_hkmap = 0; } - // TODO(bfredl): can these be combined? ccline.prompt_id = last_prompt_id++; ccline.level++; ccline.overstrike = false; // always start in insert mode @@ -264,6 +260,9 @@ static uint8_t *command_line_enter(int firstc, long count, int indent) ccline.cmdlen = ccline.cmdpos = 0; ccline.cmdbuff[0] = NUL; + ccline.last_colors = (ColoredCmdline){ .cmdbuff = NULL, + .colors = KV_INITIAL_VALUE }; + // autoindent for :insert and :append if (s->firstc <= 0) { memset(ccline.cmdbuff, ' ', s->indent); @@ -414,6 +413,8 @@ static uint8_t *command_line_enter(int firstc, long count, int indent) setmouse(); ui_cursor_shape(); // may show different cursor shape xfree(s->save_p_icm); + xfree(ccline.last_colors.cmdbuff); + kv_destroy(ccline.last_colors.colors); { char_u *p = ccline.cmdbuff; @@ -2364,8 +2365,7 @@ enum { MAX_CB_ERRORS = 1 }; /// Should use built-in command parser or user-specified one. Currently only the /// latter is supported. /// -/// @param[in] colored_ccline Command-line to color. -/// @param[out] ret_ccline_colors What should be colored. Also holds a cache: +/// @param[in,out] colored_ccline Command-line to color. Also holds a cache: /// if ->prompt_id and ->cmdbuff values happen /// to be equal to those from colored_cmdline it /// will just do nothing, assuming that ->colors @@ -2375,8 +2375,7 @@ enum { MAX_CB_ERRORS = 1 }; /// /// @return true if draw_cmdline may proceed, false if it does not need anything /// to do. -static bool color_cmdline(const CmdlineInfo *const colored_ccline, - ColoredCmdline *const ret_ccline_colors) +static bool color_cmdline(CmdlineInfo *colored_ccline) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { bool printed_errmsg = false; @@ -2389,19 +2388,21 @@ static bool color_cmdline(const CmdlineInfo *const colored_ccline, } while (0) bool ret = true; + ColoredCmdline *ccline_colors = &colored_ccline->last_colors; + // Check whether result of the previous call is still valid. - if (ret_ccline_colors->prompt_id == colored_ccline->prompt_id - && ret_ccline_colors->cmdbuff != NULL - && STRCMP(ret_ccline_colors->cmdbuff, colored_ccline->cmdbuff) == 0) { + if (ccline_colors->prompt_id == colored_ccline->prompt_id + && ccline_colors->cmdbuff != NULL + && STRCMP(ccline_colors->cmdbuff, colored_ccline->cmdbuff) == 0) { return ret; } - kv_size(ret_ccline_colors->colors) = 0; + kv_size(ccline_colors->colors) = 0; if (colored_ccline->cmdbuff == NULL || *colored_ccline->cmdbuff == NUL) { // Nothing to do, exiting. - xfree(ret_ccline_colors->cmdbuff); - ret_ccline_colors->cmdbuff = NULL; + xfree(ccline_colors->cmdbuff); + ccline_colors->cmdbuff = NULL; return ret; } @@ -2523,7 +2524,7 @@ static bool color_cmdline(const CmdlineInfo *const colored_ccline, goto color_cmdline_error; } if (start != prev_end) { - kv_push(ret_ccline_colors->colors, ((CmdlineColorChunk) { + kv_push(ccline_colors->colors, ((CmdlineColorChunk) { .start = prev_end, .end = start, .attr = 0, @@ -2552,14 +2553,14 @@ static bool color_cmdline(const CmdlineInfo *const colored_ccline, } const int id = syn_name2id((char_u *)group); const int attr = (id == 0 ? 0 : syn_id2attr(id)); - kv_push(ret_ccline_colors->colors, ((CmdlineColorChunk) { + kv_push(ccline_colors->colors, ((CmdlineColorChunk) { .start = start, .end = end, .attr = attr, })); } if (prev_end < colored_ccline->cmdlen) { - kv_push(ret_ccline_colors->colors, ((CmdlineColorChunk) { + kv_push(ccline_colors->colors, ((CmdlineColorChunk) { .start = prev_end, .end = colored_ccline->cmdlen, .attr = 0, @@ -2571,14 +2572,14 @@ color_cmdline_end: if (can_free_cb) { callback_free(&color_cb); } - xfree(ret_ccline_colors->cmdbuff); + xfree(ccline_colors->cmdbuff); // Note: errors “output” is cached just as well as regular results. - ret_ccline_colors->prompt_id = colored_ccline->prompt_id; + ccline_colors->prompt_id = colored_ccline->prompt_id; if (arg_allocated) { - ret_ccline_colors->cmdbuff = (char *)arg.vval.v_string; + ccline_colors->cmdbuff = (char *)arg.vval.v_string; } else { - ret_ccline_colors->cmdbuff = xmemdupz((const char *)colored_ccline->cmdbuff, - (size_t)colored_ccline->cmdlen); + ccline_colors->cmdbuff = xmemdupz((const char *)colored_ccline->cmdbuff, + (size_t)colored_ccline->cmdlen); } tv_clear(&tv); return ret; @@ -2591,7 +2592,7 @@ color_cmdline_error: (void)printed_errmsg; prev_prompt_errors++; - kv_size(ret_ccline_colors->colors) = 0; + kv_size(ccline_colors->colors) = 0; redrawcmdline(); ret = false; goto color_cmdline_end; @@ -2604,12 +2605,13 @@ color_cmdline_error: */ static void draw_cmdline(int start, int len) { - if (!color_cmdline(&ccline, &last_ccline_colors)) { + if (!color_cmdline(&ccline)) { return; } if (ui_is_external(kUICmdline)) { - ui_ext_cmdline_show(); + ccline.special_char = NUL; + ui_ext_cmdline_show(&ccline); return; } @@ -2711,9 +2713,9 @@ static void draw_cmdline(int start, int len) msg_outtrans_len(arshape_buf, newlen); } else { draw_cmdline_no_arabicshape: - if (kv_size(last_ccline_colors.colors)) { - for (size_t i = 0; i < kv_size(last_ccline_colors.colors); i++) { - CmdlineColorChunk chunk = kv_A(last_ccline_colors.colors, i); + if (kv_size(ccline.last_colors.colors)) { + for (size_t i = 0; i < kv_size(ccline.last_colors.colors); i++) { + CmdlineColorChunk chunk = kv_A(ccline.last_colors.colors, i); if (chunk.end <= start) { continue; } @@ -2728,12 +2730,12 @@ draw_cmdline_no_arabicshape: } } -void ui_ext_cmdline_show(void) +static void ui_ext_cmdline_show(CmdlineInfo *line) { Array content = ARRAY_DICT_INIT; - if (kv_size(last_ccline_colors.colors)) { - for (size_t i = 0; i < kv_size(last_ccline_colors.colors); i++) { - CmdlineColorChunk chunk = kv_A(last_ccline_colors.colors, i); + if (kv_size(line->last_colors.colors)) { + for (size_t i = 0; i < kv_size(line->last_colors.colors); i++) { + CmdlineColorChunk chunk = kv_A(line->last_colors.colors, i); Array item = ARRAY_DICT_INIT; if (chunk.attr) { @@ -2745,21 +2747,26 @@ void ui_ext_cmdline_show(void) } else { ADD(item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT)); } - ADD(item, STRING_OBJ(cbuf_to_string((char *)ccline.cmdbuff + chunk.start, + ADD(item, STRING_OBJ(cbuf_to_string((char *)line->cmdbuff + chunk.start, chunk.end-chunk.start))); ADD(content, ARRAY_OBJ(item)); } } else { Array item = ARRAY_DICT_INIT; ADD(item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT)); - ADD(item, STRING_OBJ(cstr_to_string((char *)(ccline.cmdbuff)))); + ADD(item, STRING_OBJ(cstr_to_string((char *)(line->cmdbuff)))); ADD(content, ARRAY_OBJ(item)); } - ui_call_cmdline_show(content, ccline.cmdpos, - cchar_to_string((char)ccline.cmdfirstc), - cstr_to_string((char *)(ccline.cmdprompt)), - ccline.cmdindent, - ccline.level); + ui_call_cmdline_show(content, line->cmdpos, + cchar_to_string((char)line->cmdfirstc), + cstr_to_string((char *)(line->cmdprompt)), + line->cmdindent, + line->level); + if (line->special_char) { + ui_call_cmdline_special_char(cchar_to_string((char)(line->special_char)), + line->special_shift, + line->level); + } } void ui_ext_cmdline_block_append(int indent, const char *line) @@ -2787,6 +2794,28 @@ void ui_ext_cmdline_block_leave(void) ui_call_cmdline_block_hide(); } +/// Extra redrawing needed for redraw! and on ui_attach +/// assumes "redrawcmdline()" will already be invoked +void cmdline_screen_cleared(void) +{ + if (!ui_is_external(kUICmdline)) { + return; + } + + if (cmdline_block.size) { + ui_call_cmdline_block_show(copy_array(cmdline_block)); + } + + int prev_level = ccline.level-1; + CmdlineInfo *prev_ccline = ccline.prev_ccline; + while (prev_level > 0 && prev_ccline) { + if (prev_ccline->level == prev_level) { + ui_ext_cmdline_show(prev_ccline); + prev_level--; + } + prev_ccline = prev_ccline->prev_ccline; + } +} /* * Put a character on the command line. Shifts the following text to the @@ -2806,6 +2835,8 @@ void putcmdline(int c, int shift) } msg_no_more = false; } else { + ccline.special_char = c; + ccline.special_shift = shift; ui_call_cmdline_special_char(cchar_to_string((char)(c)), shift, ccline.level); } @@ -2971,6 +3002,7 @@ static void save_cmdline(struct cmdline_info *ccp) ccline.cmdbuff = NULL; ccline.cmdprompt = NULL; ccline.xpc = NULL; + ccline.special_char = NUL; } /* @@ -3147,7 +3179,7 @@ static void redrawcmdprompt(void) if (cmd_silent) return; if (ui_is_external(kUICmdline)) { - ui_ext_cmdline_show(); + ui_ext_cmdline_show(&ccline); return; } if (ccline.cmdfirstc != NUL) { diff --git a/src/nvim/screen.c b/src/nvim/screen.c index f5730cf70a..0f47103a84 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -345,8 +345,9 @@ void update_screen(int type) if (need_highlight_changed) highlight_changed(); - if (type == CLEAR) { /* first clear screen */ - screenclear(); /* will reset clear_cmdline */ + if (type == CLEAR) { // first clear screen + screenclear(); // will reset clear_cmdline + cmdline_screen_cleared(); // clear external cmdline state type = NOT_VALID; } diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 3f9ce8ad67..e4d625df8e 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -3,6 +3,7 @@ local Screen = require('test.functional.ui.screen') local clear, feed, eq = helpers.clear, helpers.feed, helpers.eq local source = helpers.source local ok = helpers.ok +local command = helpers.command if helpers.pending_win32(pending) then return end @@ -218,14 +219,7 @@ describe('external cmdline', function() end) feed('1+2') - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - | - ]], nil, nil, function() - eq({{ + local expectation = {{ content = { { {}, "xx" } }, firstc = ":", indent = 0, @@ -238,16 +232,40 @@ describe('external cmdline', function() indent = 0, pos = 3, prompt = "", - }}, cmdline) + }} + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq(expectation, cmdline) end) - feed('') + -- erase information, so we check if it is retransmitted + cmdline = {} + command("redraw!") + -- redraw! forgets cursor position. Be OK with that, as UI should indicate + -- focus is at external cmdline anyway. screen:expect([[ - ^ | + | ~ | ~ | ~ | + ^ | + ]], nil, nil, function() + eq(expectation, cmdline) + end) + + + feed('') + screen:expect([[ | + ~ | + ~ | + ~ | + ^ | ]], nil, nil, function() eq({{ content = { { {}, "xx3" } }, @@ -301,6 +319,20 @@ describe('external cmdline', function() {{{}, ' line1'}}}, block) end) + block = {} + command("redraw!") + screen:expect([[ + | + ~ | + ~ | + ~ | + ^ | + ]], nil, nil, function() + eq({{{{}, 'function Foo()'}}, + {{{}, ' line1'}}}, block) + end) + + feed('endfunction') screen:expect([[ ^ | -- cgit From 91d8e26bc7471378b8005b8843182dc1af90d81a Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sun, 27 Aug 2017 09:57:30 +0200 Subject: ext_cmdline: interact with cmdline window --- src/nvim/ex_getln.c | 10 +++- src/nvim/globals.h | 7 ++- test/functional/ui/cmdline_spec.lua | 107 ++++++++++++++++++++++++++++++++++-- 3 files changed, 115 insertions(+), 9 deletions(-) diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 933aea7b93..bcc8d598db 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -2810,7 +2810,10 @@ void cmdline_screen_cleared(void) CmdlineInfo *prev_ccline = ccline.prev_ccline; while (prev_level > 0 && prev_ccline) { if (prev_ccline->level == prev_level) { - ui_ext_cmdline_show(prev_ccline); + // don't redraw a cmdline already shown in the cmdline window + if (prev_level != cmdwin_level) { + ui_ext_cmdline_show(prev_ccline); + } prev_level--; } prev_ccline = prev_ccline->prev_ccline; @@ -5781,6 +5784,7 @@ static int ex_window(void) return K_IGNORE; } cmdwin_type = get_cmdline_type(); + cmdwin_level = ccline.level; // Create empty command-line buffer. buf_open_scratch(0, "[Command Line]"); @@ -5833,6 +5837,9 @@ static int ex_window(void) curwin->w_cursor.col = ccline.cmdpos; changed_line_abv_curs(); invalidate_botline(); + if (ui_is_external(kUICmdline)) { + ui_call_cmdline_hide(ccline.level); + } redraw_later(SOME_VALID); // Save the command line info, can be used recursively. @@ -5875,6 +5882,7 @@ static int ex_window(void) // Restore the command line info. restore_cmdline(&save_ccline); cmdwin_type = 0; + cmdwin_level = 0; exmode_active = save_exmode; diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 300e506854..f24286360a 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -981,9 +981,10 @@ EXTERN int fill_diff INIT(= '-'); EXTERN int km_stopsel INIT(= FALSE); EXTERN int km_startsel INIT(= FALSE); -EXTERN int cedit_key INIT(= -1); /* key value of 'cedit' option */ -EXTERN int cmdwin_type INIT(= 0); /* type of cmdline window or 0 */ -EXTERN int cmdwin_result INIT(= 0); /* result of cmdline window or 0 */ +EXTERN int cedit_key INIT(= -1); ///< key value of 'cedit' option +EXTERN int cmdwin_type INIT(= 0); ///< type of cmdline window or 0 +EXTERN int cmdwin_result INIT(= 0); ///< result of cmdline window or 0 +EXTERN int cmdwin_level INIT(= 0); ///< cmdline level of cmdline window or 0 EXTERN char_u no_lines_msg[] INIT(= N_("--No lines in buffer--")); diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index e4d625df8e..b886596e00 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -232,7 +232,7 @@ describe('external cmdline', function() indent = 0, pos = 3, prompt = "", - }} + }} screen:expect([[ ^ | ~ | @@ -345,19 +345,116 @@ describe('external cmdline', function() end) end) - pending("works with cmdline window", function() - feed(':sign') + it("works with cmdline window", function() + feed(':make') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({{ + content = { { {}, "make" } }, + firstc = ":", + indent = 0, + pos = 4, + prompt = "" + }}, cmdline) + end) + + feed('') + screen:expect([[ + | + [No Name] | + :make^ | + [Command Line] | + | + ]], nil, nil, function() + eq({}, cmdline) + end) + + -- nested cmdline + feed(':yank') + screen:expect([[ + | + [No Name] | + :make^ | + [Command Line] | + | + ]], nil, nil, function() + eq({nil, { + content = { { {}, "yank" } }, + firstc = ":", + indent = 0, + pos = 4, + prompt = "" + }}, cmdline) + end) + + cmdline = {} + command("redraw!") + screen:expect([[ + | + [No Name] | + :make | + [Command Line] | + ^ | + ]], nil, nil, function() + eq({nil, { + content = { { {}, "yank" } }, + firstc = ":", + indent = 0, + pos = 4, + prompt = "" + }}, cmdline) + end) + + feed("") screen:expect([[ | [No Name] | - :sign^ | + :make^ | [Command Line] | | ]], nil, nil, function() eq({}, cmdline) end) - feed(":blargh") + feed("") + screen:expect([[ + | + [No Name] | + :make^ | + [Command Line] | + | + ]], nil, nil, function() + eq({{ + content = { { {}, "make" } }, + firstc = ":", + indent = 0, + pos = 4, + prompt = "" + }}, cmdline) + end) + + cmdline = {} + command("redraw!") + screen:expect([[ + | + ~ | + ~ | + ~ | + ^ | + ]], nil, nil, function() + eq({{ + content = { { {}, "make" } }, + firstc = ":", + indent = 0, + pos = 4, + prompt = "" + }}, cmdline) + end) end) it('works with highlighted cmdline', function() -- cgit From 445f25998c66ee7e4dc5bbfeed4108818e439b92 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Wed, 30 Aug 2017 08:51:39 +0200 Subject: ext_cmdline: fix inputsecret() --- src/nvim/ex_getln.c | 13 ++++++++++++- test/functional/ui/cmdline_spec.lua | 20 ++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index bcc8d598db..e79476ab53 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -2733,7 +2733,18 @@ draw_cmdline_no_arabicshape: static void ui_ext_cmdline_show(CmdlineInfo *line) { Array content = ARRAY_DICT_INIT; - if (kv_size(line->last_colors.colors)) { + if (cmdline_star) { + size_t len = 0; + for (char_u *p = ccline.cmdbuff; *p; mb_ptr_adv(p)) { + len++; + } + char *buf = xmallocz(len); + memset(buf, '*', len); + Array item = ARRAY_DICT_INIT; + ADD(item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT)); + ADD(item, STRING_OBJ(((String) { .data = buf, .size = len }))); + ADD(content, ARRAY_OBJ(item)); + } else if (kv_size(line->last_colors.colors)) { for (size_t i = 0; i < kv_size(line->last_colors.colors); i++) { CmdlineColorChunk chunk = kv_A(line->last_colors.colors, i); Array item = ARRAY_DICT_INIT; diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index b886596e00..6a9f4a22b4 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -15,6 +15,7 @@ describe('external cmdline', function() before_each(function() clear() + cmdline, block = {}, nil screen = Screen.new(25, 5) screen:attach({rgb=true, ext_cmdline=true}) screen:set_on_event_handler(function(name, data) @@ -457,6 +458,25 @@ describe('external cmdline', function() end) end) + it('works with inputsecret()', function() + feed(":call inputsecret('secret:')abc123") + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({{ + content = { { {}, "******" } }, + firstc = "", + indent = 0, + pos = 6, + prompt = "secret:" + }}, cmdline) + end) + end) + it('works with highlighted cmdline', function() source([[ highlight RBP1 guibg=Red -- cgit From f640ae0d6e788bb3ca06508d216a397c1ff190d5 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sun, 10 Sep 2017 10:01:18 +0200 Subject: docs: breakout ui.txt from msgpack_rpc.txt --- runtime/doc/api.txt | 2 +- runtime/doc/msgpack_rpc.txt | 255 --------------------------------------- runtime/doc/ui.txt | 284 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 285 insertions(+), 256 deletions(-) create mode 100644 runtime/doc/ui.txt diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt index 8aead087db..159dd93c5e 100644 --- a/runtime/doc/api.txt +++ b/runtime/doc/api.txt @@ -48,7 +48,7 @@ version.api_compatible API is backwards-compatible with this level version.api_prerelease Declares the current API level as unstable > (version.api_prerelease && fn.since == version.api_level) functions API function signatures -ui_events UI event signatures |rpc-remote-ui| +ui_events UI event signatures |ui| {fn}.since API level where function {fn} was introduced {fn}.deprecated_since API level where function {fn} was deprecated types Custom handle types defined by Nvim diff --git a/runtime/doc/msgpack_rpc.txt b/runtime/doc/msgpack_rpc.txt index 9601e239f2..7af6e401da 100644 --- a/runtime/doc/msgpack_rpc.txt +++ b/runtime/doc/msgpack_rpc.txt @@ -243,259 +243,4 @@ Even for statically compiled clients it is good practice to avoid hardcoding the type codes, because a client may be built against one Nvim version but connect to another with different type codes. -============================================================================== -6. Remote UIs *rpc-remote-ui* - -GUIs can be implemented as external processes communicating with Nvim over the -RPC API. The UI model consists of a terminal-like grid with a single, -monospace font size. Some elements (UI "widgets") can be drawn separately from -the grid ("externalized"). - -After connecting to Nvim (usually a spawned, embedded instance) use the -|nvim_ui_attach| API method to tell Nvim that your program wants to draw the -Nvim screen on a grid of width × height cells. `options` must be -a dictionary with these (optional) keys: - `rgb` Controls what color format to use. - Set to true (default) to use 24-bit rgb - colors. - Set to false to use terminal color codes (at - most 256 different colors). - `ext_popupmenu` Externalize the popupmenu. |ui-ext-popupmenu| - `ext_tabline` Externalize the tabline. |ui-ext-tabline| - `ext_cmdline` Externalize the cmdline. |ui-ext-cmdline| - Externalized widgets will not be drawn by - Nvim; only high-level data will be published - in new UI event kinds. - -Nvim will then send msgpack-rpc notifications, with the method name "redraw" -and a single argument, an array of screen updates (described below). These -should be processed in order. Preferably the user should only be able to see -the screen state after all updates in the same "redraw" event are processed -(not any intermediate state after processing only a part of the array). - -Future versions of Nvim may add new update kinds and may append new parameters -to existing update kinds. Clients must be prepared to ignore such extensions -to be forward-compatible. |api-contract| - -Screen updates are tuples whose first element is the string name of the update -kind. - -["resize", width, height] - The grid is resized to `width` and `height` cells. - -["clear"] - Clear the screen. - -["eol_clear"] - Clear from the cursor position to the end of the current line. - -["cursor_goto", row, col] - Move the cursor to position (row, col). Currently, the same cursor is - used to define the position for text insertion and the visible cursor. - However, only the last cursor position, after processing the entire - array in the "redraw" event, is intended to be a visible cursor - position. - -["update_fg", color] -["update_bg", color] -["update_sp", color] - Set the default foreground, background and special colors - respectively. - - - *ui-event-highlight_set* -["highlight_set", attrs] - Set the attributes that the next text put on the screen will have. - `attrs` is a dict with the keys below. Any absent key is reset - to its default value. Color defaults are set by the `update_fg` etc - updates. All boolean keys default to false. - - `foreground`: foreground color. - `background`: backround color. - `special`: color to use for underline and undercurl, when present. - `reverse`: reverse video. Foreground and background colors are - switched. - `italic`: italic text. - `bold`: bold text. - `underline`: underlined text. The line has `special` color. - `undercurl`: undercurled text. The curl has `special` color. - -["put", text] - The (utf-8 encoded) string `text` is put at the cursor position - (and the cursor is advanced), with the highlights as set by the - last `highlight_set` update. - -["set_scroll_region", top, bot, left, right] - Define the scroll region used by `scroll` below. - -["scroll", count] - Scroll the text in the scroll region. The diagrams below illustrate - what will happen, depending on the scroll direction. "=" is used to - represent the SR(scroll region) boundaries and "-" the moved rectangles. - Note that dst and src share a common region. - - If count is bigger than 0, move a rectangle in the SR up, this can - happen while scrolling down. -> - +-------------------------+ - | (clipped above SR) | ^ - |=========================| dst_top | - | dst (still in SR) | | - +-------------------------+ src_top | - | src (moved up) and dst | | - |-------------------------| dst_bot | - | src (cleared) | | - +=========================+ src_bot -< - If count is less than zero, move a rectangle in the SR down, this can - happen while scrolling up. -> - +=========================+ src_top - | src (cleared) | | - |------------------------ | dst_top | - | src (moved down) and dst| | - +-------------------------+ src_bot | - | dst (still in SR) | | - |=========================| dst_bot | - | (clipped below SR) | v - +-------------------------+ -< -["set_title", title] -["set_icon", icon] - Set the window title, and icon (minimized) window title, respectively. - In windowing systems not distinguishing between the two, "set_icon" - can be ignored. - -["mouse_on"] -["mouse_off"] - Tells the client whether mouse support, as determined by |'mouse'| - option, is considered to be active in the current mode. This is mostly - useful for a terminal frontend, or other situations where nvim mouse - would conflict with other usages of the mouse. It is safe for a client - to ignore this and always send mouse events. - -["busy_on"] -["busy_off"] - Nvim started or stopped being busy, and possibly not responsible to user - input. This could be indicated to the user by hiding the cursor. - -["suspend"] - |:suspend| command or |Ctrl-Z| mapping is used. A terminal client (or other - client where it makes sense) could suspend itself. Other clients can - safely ignore it. - -["bell"] -["visual_bell"] - Notify the user with an audible or visual bell, respectively. - -["update_menu"] - The menu mappings changed. - -["mode_info_set", cursor_style_enabled, mode_info] -`cursor_style_enabled` is a boolean indicating if the UI should set the cursor -style. `mode_info` is a list of mode property maps. The current mode is given -by the `mode_idx` field of the `mode_change` event. - -Each mode property map may contain these keys: - KEY DESCRIPTION ~ - `cursor_shape`: "block", "horizontal", "vertical" - `cell_percentage`: Cell % occupied by the cursor. - `blinkwait`, `blinkon`, `blinkoff`: See |cursor-blinking|. - `hl_id`: Cursor highlight group. - `hl_lm`: Cursor highlight group if 'langmap' is active. - `short_name`: Mode code name, see 'guicursor'. - `name`: Mode descriptive name. - `mouse_shape`: (To be implemented.) - -Some keys are missing in some modes. - -["mode_change", mode, mode_idx] -The mode changed. The first parameter `mode` is a string representing the -current mode. `mode_idx` is an index into the array received in the -`mode_info_set` event. UIs should change the cursor style according to the -properties specified in the corresponding item. The set of modes reported will -change in new versions of Nvim, for instance more submodes and temporary -states might be represented as separate modes. - - *ui-ext-popupmenu* -["popupmenu_show", items, selected, row, col] - When `popupmenu_external` is set to true, nvim will not draw the - popupmenu on the grid, instead when the popupmenu is to be displayed - this update is sent. `items` is an array of the items to show, the - items are themselves arrays of the form [word, kind, menu, info] - as defined at |complete-items|, except that `word` is replaced by - `abbr` if present. `selected` is the initially selected item, either a - zero-based index into the array of items, or -1 if no item is - selected. `row` and `col` is the anchor position, where the first - character of the completed word will be. - -["popupmenu_select", selected] - An item in the currently displayed popupmenu is selected. `selected` - is either a zero-based index into the array of items from the last - `popupmenu_show` event, or -1 if no item is selected. - -["popupmenu_hide"] - The popupmenu is hidden. - - *ui-ext-tabline* -["tabline_update", curtab, tabs] - Tabline was updated. UIs should present this data in a custom tabline - widget. - curtab: Current Tabpage - tabs: List of Dicts [{ "tab": Tabpage, "name": String }, ...] - - *ui-ext-cmdline* -["cmdline_show", content, pos, firstc, prompt, indent, level] - content: List of [attrs, string] - [[{}, "t"], [attrs, "est"], ...] - When cmdline_external is set to true, nvim will not draw the cmdline - on the grid, instead nvim will send ui events of the cmdline content - and cursor position to the remote ui. The `content` is the full content - that should be displayed in the cmdline, and the `pos` is the position - of the cursor that in the cmdline. This event will be triggered when - you type in the cmdline. The content is divided into chunks with - different highlight attributes represented as a dict, see - |ui-event-highlight_set|. - - `firstc` and `prompt` are text, that if non-empty should be - displayed in front of the command line. `firstc` always indicates - built in command lines such as `:` (ex command) and `/` `?` (search), - while `prompt` is an |input()| prompt. `indent` tells how many spaces - the content should be indented - - The command line in nvim can be invoked recursively, for instance by - typing `=` at the command line prompt. The `level` field is used - to distinguish different command lines active at the same time. The - first invoked command line will always have level 1, and the next - recursively invoked prompt will have level 2. Also, a command line - invoked while in command line window will have a higher level than - than the edited command line. - -["cmdline_pos", pos, level] - Change the cursor position in the cmdline. - -["cmdline_special_char", c, shift, level] - Display a special char in the cmdline at the cursor position. This is - typically used to indicate a pending state, like right after Ctrl-V. - if shift is true the text after the cursor should be shifted, - otherwise it should overshadow the char at the cursor. - Should be hidden at next cmdline_char - - -["cmdline_hide"] - Hide the cmdline. - -["cmdline_block_show", lines] - Show a block of context to the current command line. This occurs for - instance if a function is interactively defined at the command line. - `lines` is a list of lines where each line is represented as a list of - highlighted chunks, just like `contents` of |ui-event-cmdline_show|. - -["cmdline_block_append", line] - Append a line at the end of the currently shown block. - -["cmdline_block_hide"] - Hide the block. -============================================================================== - vim:tw=78:ts=8:noet:ft=help:norl: diff --git a/runtime/doc/ui.txt b/runtime/doc/ui.txt new file mode 100644 index 0000000000..b875c1b183 --- /dev/null +++ b/runtime/doc/ui.txt @@ -0,0 +1,284 @@ +*ui.txt* Nvim + + + NVIM REFERENCE MANUAL by Thiago de Arruda + + +UI protocol *ui* + + Type to see the table of contents. + +============================================================================== +Introduction *ui-intro* + +GUIs can be implemented as external processes communicating with Nvim over the +RPC API. The UI model consists of a terminal-like grid with a single, +monospace font size. Some elements (UI "widgets") can be drawn separately from +the grid ("externalized"). + + *ui-options* +After connecting to Nvim (usually a spawned, embedded instance) use the +|nvim_ui_attach| API method to tell Nvim that your program wants to draw the +Nvim screen grid with a size of width × height cells. `options` must be +a dictionary with these (optional) keys: + `rgb` Controls what color format to use. + Set to true (default) to use 24-bit rgb + colors. + Set to false to use terminal color codes (at + most 256 different colors). + `ext_popupmenu` Externalize the popupmenu. |ui-popupmenu| + `ext_tabline` Externalize the tabline. |ui-tabline| + `ext_cmdline` Externalize the cmdline. |ui-cmdline| + +Nvim will then send msgpack-rpc notifications, with the method name "redraw" +and a single argument, an array of screen update events. +Update events are tuples whose first element is the string name of the update +kind. The rest are parameters for each update, described in the sections below. +These should be processed in order. Preferably the user should only be able to +see the screen state after all update events in the same "redraw" event are +processed (not any intermediate state after processing only a part of the +array). + +Section 2 and 3 describes grid and mode events that are send unconditionally, +and suffice to implement a terminal-like interface. Nvim also allows a number +of screen elements to be sent as descriptive events for the GUI to draw +itself, rather than Nvim drawing itself on the grid. This is controlled by the +`ext_` options. + +Future versions of Nvim may add new update kinds and may append new parameters +to existing update kinds. Clients must be prepared to ignore such extensions +to be forward-compatible. |api-contract| + +============================================================================== +Global Events *ui-global* + +["set_title", title] +["set_icon", icon] + Set the window title, and icon (minimized) window title, respectively. + In windowing systems not distinguishing between the two, "set_icon" + can be ignored. + +["mode_info_set", cursor_style_enabled, mode_info] + `cursor_style_enabled` is a boolean indicating if the UI should set + the cursor style. `mode_info` is a list of mode property maps. The + current mode is given by the `mode_idx` field of the `mode_change` + event. + +Each mode property map may contain these keys: + KEY DESCRIPTION ~ + `cursor_shape`: "block", "horizontal", "vertical" + `cell_percentage`: Cell % occupied by the cursor. + `blinkwait`, `blinkon`, `blinkoff`: See |cursor-blinking|. + `hl_id`: Cursor highlight group. + `hl_lm`: Cursor highlight group if 'langmap' is active. + `short_name`: Mode code name, see 'guicursor'. + `name`: Mode descriptive name. + `mouse_shape`: (To be implemented.) + +Some keys are missing in some modes. + +["mode_change", mode, mode_idx] + The mode changed. The first parameter `mode` is a string representing + the current mode. `mode_idx` is an index into the array received in + the `mode_info_set` event. UIs should change the cursor style + according to the properties specified in the corresponding item. The + set of modes reported will change in new versions of Nvim, for + instance more submodes and temporary states might be represented as + separate modes. + + +["mouse_on"] +["mouse_off"] + Tells the client whether mouse support, as determined by |'mouse'| + option, is considered to be active in the current mode. This is mostly + useful for a terminal frontend, or other situations where nvim mouse + would conflict with other usages of the mouse. It is safe for a client + to ignore this and always send mouse events. + +["busy_on"] +["busy_off"] + Nvim started or stopped being busy, and possibly not responsible to user + input. This could be indicated to the user by hiding the cursor. + +["suspend"] + |:suspend| command or |Ctrl-Z| mapping is used. A terminal client (or other + client where it makes sense) could suspend itself. Other clients can + safely ignore it. + +["update_menu"] + The menu mappings changed. + +["bell"] +["visual_bell"] + Notify the user with an audible or visual bell, respectively. + +============================================================================== +Grid Events *ui-grid* + +["resize", width, height] + The grid is resized to `width` and `height` cells. + +["clear"] + Clear the grid. + +["eol_clear"] + Clear from the cursor position to the end of the current line. + +["cursor_goto", row, col] + Move the cursor to position (row, col). Currently, the same cursor is + used to define the position for text insertion and the visible cursor. + However, only the last cursor position, after processing the entire + array in the "redraw" event, is intended to be a visible cursor + position. + +["update_fg", color] +["update_bg", color] +["update_sp", color] + Set the default foreground, background and special colors + respectively. + + *ui-event-highlight_set* +["highlight_set", attrs] + Set the attributes that the next text put on the grid will have. + `attrs` is a dict with the keys below. Any absent key is reset + to its default value. Color defaults are set by the `update_fg` etc + updates. All boolean keys default to false. + + `foreground`: foreground color. + `background`: backround color. + `special`: color to use for underline and undercurl, when present. + `reverse`: reverse video. Foreground and background colors are + switched. + `italic`: italic text. + `bold`: bold text. + `underline`: underlined text. The line has `special` color. + `undercurl`: undercurled text. The curl has `special` color. + +["put", text] + The (utf-8 encoded) string `text` is put at the cursor position + (and the cursor is advanced), with the highlights as set by the + last `highlight_set` update. + +["set_scroll_region", top, bot, left, right] + Define the scroll region used by `scroll` below. + +["scroll", count] + Scroll the text in the scroll region. The diagrams below illustrate + what will happen, depending on the scroll direction. "=" is used to + represent the SR(scroll region) boundaries and "-" the moved rectangles. + Note that dst and src share a common region. + + If count is bigger than 0, move a rectangle in the SR up, this can + happen while scrolling down. +> + +-------------------------+ + | (clipped above SR) | ^ + |=========================| dst_top | + | dst (still in SR) | | + +-------------------------+ src_top | + | src (moved up) and dst | | + |-------------------------| dst_bot | + | src (cleared) | | + +=========================+ src_bot +< + If count is less than zero, move a rectangle in the SR down, this can + happen while scrolling up. +> + +=========================+ src_top + | src (cleared) | | + |------------------------ | dst_top | + | src (moved down) and dst| | + +-------------------------+ src_bot | + | dst (still in SR) | | + |=========================| dst_bot | + | (clipped below SR) | v + +-------------------------+ +< +============================================================================== +Popupmenu Events *ui-popupmenu* + +Only sent if `ext_popupmenu` option is set in |ui-options| + +["popupmenu_show", items, selected, row, col] + `items` is an array of the items to show, the + items are themselves arrays of the form [word, kind, menu, info] + as defined at |complete-items|, except that `word` is replaced by + `abbr` if present. `selected` is the initially selected item, either a + zero-based index into the array of items, or -1 if no item is + selected. `row` and `col` is the anchor position, where the first + character of the completed word will be. + +["popupmenu_select", selected] + An item in the currently displayed popupmenu is selected. `selected` + is either a zero-based index into the array of items from the last + `popupmenu_show` event, or -1 if no item is selected. + +["popupmenu_hide"] + The popupmenu is hidden. + +============================================================================== +Tabline Events *ui-tabline* + +Only sent if `ext_tabline` option is set in |ui-options| + +["tabline_update", curtab, tabs] + Tabline was updated. UIs should present this data in a custom tabline + widget. + curtab: Current Tabpage + tabs: List of Dicts [{ "tab": Tabpage, "name": String }, ...] + +============================================================================== +Cmdline Events *ui-cmdline* + +Only sent if `ext_cmdline` option is set in |ui-options| + +["cmdline_show", content, pos, firstc, prompt, indent, level] + content: List of [attrs, string] + [[{}, "t"], [attrs, "est"], ...] + The `content` is the full content that should be displayed in the + cmdline, and the `pos` is the position of the cursor that in the + cmdline. This event will be triggered when you type in the cmdline. + The content is divided into chunks with different highlight attributes + represented as a dict, see |ui-event-highlight_set|. + + `firstc` and `prompt` are text, that if non-empty should be + displayed in front of the command line. `firstc` always indicates + built in command lines such as `:` (ex command) and `/` `?` (search), + while `prompt` is an |input()| prompt. `indent` tells how many spaces + the content should be indented + + The command line in nvim can be invoked recursively, for instance by + typing `=` at the command line prompt. The `level` field is used + to distinguish different command lines active at the same time. The + first invoked command line will always have level 1, and the next + recursively invoked prompt will have level 2. Also, a command line + invoked while in command line window will have a higher level than + than the edited command line. + +["cmdline_pos", pos, level] + Change the cursor position in the cmdline. + +["cmdline_special_char", c, shift, level] + Display a special char in the cmdline at the cursor position. This is + typically used to indicate a pending state, like right after Ctrl-V. + if shift is true the text after the cursor should be shifted, + otherwise it should overshadow the char at the cursor. + Should be hidden at next cmdline_char + +["cmdline_hide"] + Hide the cmdline. + +["cmdline_block_show", lines] + Show a block of context to the current command line. This occurs for + instance if a function is interactively defined at the command line. + `lines` is a list of lines where each line is represented as a list of + highlighted chunks, just like `contents` of |ui-event-cmdline_show|. + +["cmdline_block_append", line] + Append a line at the end of the currently shown block. + +["cmdline_block_hide"] + Hide the block. + +============================================================================== + vim:tw=78:ts=8:noet:ft=help:norl: -- cgit From 8526902790680b9eea5462c19bd7d45caa40f16d Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 28 Oct 2017 23:49:41 +0200 Subject: doc/ui.txt --- runtime/doc/ui.txt | 96 +++++++++++++++++++++++++++++------------------------- src/nvim/globals.h | 2 +- src/nvim/ui.c | 1 - 3 files changed, 52 insertions(+), 47 deletions(-) diff --git a/runtime/doc/ui.txt b/runtime/doc/ui.txt index b875c1b183..deac1609c0 100644 --- a/runtime/doc/ui.txt +++ b/runtime/doc/ui.txt @@ -1,12 +1,12 @@ *ui.txt* Nvim - NVIM REFERENCE MANUAL by Thiago de Arruda + NVIM REFERENCE MANUAL -UI protocol *ui* +Nvim UI protocol *ui* - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== Introduction *ui-intro* @@ -16,34 +16,35 @@ RPC API. The UI model consists of a terminal-like grid with a single, monospace font size. Some elements (UI "widgets") can be drawn separately from the grid ("externalized"). - *ui-options* + *ui-options* After connecting to Nvim (usually a spawned, embedded instance) use the |nvim_ui_attach| API method to tell Nvim that your program wants to draw the Nvim screen grid with a size of width × height cells. `options` must be a dictionary with these (optional) keys: - `rgb` Controls what color format to use. - Set to true (default) to use 24-bit rgb - colors. - Set to false to use terminal color codes (at - most 256 different colors). + `rgb` Decides the color format. + Set true (default) for 24-bit RGB colors. + Set false for terminal colors (max of 256). + *ui-ext-options* `ext_popupmenu` Externalize the popupmenu. |ui-popupmenu| `ext_tabline` Externalize the tabline. |ui-tabline| `ext_cmdline` Externalize the cmdline. |ui-cmdline| Nvim will then send msgpack-rpc notifications, with the method name "redraw" and a single argument, an array of screen update events. -Update events are tuples whose first element is the string name of the update -kind. The rest are parameters for each update, described in the sections below. -These should be processed in order. Preferably the user should only be able to -see the screen state after all update events in the same "redraw" event are -processed (not any intermediate state after processing only a part of the -array). - -Section 2 and 3 describes grid and mode events that are send unconditionally, -and suffice to implement a terminal-like interface. Nvim also allows a number -of screen elements to be sent as descriptive events for the GUI to draw -itself, rather than Nvim drawing itself on the grid. This is controlled by the -`ext_` options. +Update events are tuples whose first element is the event name and remaining +elements the event parameters. + +Events must be handled in order. The user should only see the updated screen +state after all events in the same "redraw" batch are processed (not any +intermediate state after processing only part of the array). + +Nvim sends |ui-global| and |ui-grid| events unconditionally; these suffice to +implement a terminal-like interface. + +Nvim optionally sends screen elements "semantically" as structured events +instead of raw grid-lines. Then the UI must decide how to present those +elements itself; Nvim will not draw those elements on the grid. This is +controlled by the |ui-ext-options|. Future versions of Nvim may add new update kinds and may append new parameters to existing update kinds. Clients must be prepared to ignore such extensions @@ -64,7 +65,8 @@ Global Events *ui-global* current mode is given by the `mode_idx` field of the `mode_change` event. -Each mode property map may contain these keys: + Each mode property map may contain these keys: + KEY DESCRIPTION ~ `cursor_shape`: "block", "horizontal", "vertical" `cell_percentage`: Cell % occupied by the cursor. @@ -75,7 +77,7 @@ Each mode property map may contain these keys: `name`: Mode descriptive name. `mouse_shape`: (To be implemented.) -Some keys are missing in some modes. + Some keys are missing in some modes. ["mode_change", mode, mode_idx] The mode changed. The first parameter `mode` is a string representing @@ -86,7 +88,6 @@ Some keys are missing in some modes. instance more submodes and temporary states might be represented as separate modes. - ["mouse_on"] ["mouse_off"] Tells the client whether mouse support, as determined by |'mouse'| @@ -97,8 +98,8 @@ Some keys are missing in some modes. ["busy_on"] ["busy_off"] - Nvim started or stopped being busy, and possibly not responsible to user - input. This could be indicated to the user by hiding the cursor. + Nvim started or stopped being busy, and possibly not responsive to + user input. This could be indicated to the user by hiding the cursor. ["suspend"] |:suspend| command or |Ctrl-Z| mapping is used. A terminal client (or other @@ -137,7 +138,7 @@ Grid Events *ui-grid* Set the default foreground, background and special colors respectively. - *ui-event-highlight_set* + *ui-event-highlight_set* ["highlight_set", attrs] Set the attributes that the next text put on the grid will have. `attrs` is a dict with the keys below. Any absent key is reset @@ -235,44 +236,49 @@ Only sent if `ext_cmdline` option is set in |ui-options| ["cmdline_show", content, pos, firstc, prompt, indent, level] content: List of [attrs, string] [[{}, "t"], [attrs, "est"], ...] + + Triggered when the user types in the cmdline. The `content` is the full content that should be displayed in the cmdline, and the `pos` is the position of the cursor that in the - cmdline. This event will be triggered when you type in the cmdline. - The content is divided into chunks with different highlight attributes - represented as a dict, see |ui-event-highlight_set|. + cmdline. The content is divided into chunks with different highlight + attributes represented as a dict (see |ui-event-highlight_set|). `firstc` and `prompt` are text, that if non-empty should be displayed in front of the command line. `firstc` always indicates - built in command lines such as `:` (ex command) and `/` `?` (search), + built-in command lines such as `:` (ex command) and `/` `?` (search), while `prompt` is an |input()| prompt. `indent` tells how many spaces - the content should be indented + the content should be indented. - The command line in nvim can be invoked recursively, for instance by + The Nvim command line can be invoked recursively, for instance by typing `=` at the command line prompt. The `level` field is used to distinguish different command lines active at the same time. The - first invoked command line will always have level 1, and the next - recursively invoked prompt will have level 2. Also, a command line - invoked while in command line window will have a higher level than - than the edited command line. + first invoked command line has level 1, the next recursively-invoked + prompt has level 2. A command line invoked from the |cmd-line-window| + has a higher level than than the edited command line. ["cmdline_pos", pos, level] Change the cursor position in the cmdline. ["cmdline_special_char", c, shift, level] Display a special char in the cmdline at the cursor position. This is - typically used to indicate a pending state, like right after Ctrl-V. - if shift is true the text after the cursor should be shifted, - otherwise it should overshadow the char at the cursor. - Should be hidden at next cmdline_char + typically used to indicate a pending state, e.g. after |c_CTRL-V|. If + `shift` is true the text after the cursor should be shifted, otherwise + it should overwrite the char at the cursor. + + Should be hidden at next cmdline_pos. ["cmdline_hide"] Hide the cmdline. ["cmdline_block_show", lines] - Show a block of context to the current command line. This occurs for - instance if a function is interactively defined at the command line. - `lines` is a list of lines where each line is represented as a list of - highlighted chunks, just like `contents` of |ui-event-cmdline_show|. + Show a block of context to the current command line. For example if + the user defines a |:function| interactively: > + :function Foo() + : echo "foo" + : +< + `lines` is a list of lines of highlighted chunks, in the same form as + the "cmdline_show" `contents` parameter. ["cmdline_block_append", line] Append a line at the end of the currently shown block. diff --git a/src/nvim/globals.h b/src/nvim/globals.h index f24286360a..0f3e132bc0 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -984,7 +984,7 @@ EXTERN int km_startsel INIT(= FALSE); EXTERN int cedit_key INIT(= -1); ///< key value of 'cedit' option EXTERN int cmdwin_type INIT(= 0); ///< type of cmdline window or 0 EXTERN int cmdwin_result INIT(= 0); ///< result of cmdline window or 0 -EXTERN int cmdwin_level INIT(= 0); ///< cmdline level of cmdline window or 0 +EXTERN int cmdwin_level INIT(= 0); ///< cmdline recursion level EXTERN char_u no_lines_msg[] INIT(= N_("--No lines in buffer--")); diff --git a/src/nvim/ui.c b/src/nvim/ui.c index 6b09f6e6db..afe7a51d43 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -30,7 +30,6 @@ #include "nvim/os/input.h" #include "nvim/os/signal.h" #include "nvim/popupmnu.h" -#include "nvim/ex_getln.h" #include "nvim/screen.h" #include "nvim/syntax.h" #include "nvim/window.h" -- cgit From 1a93f5883105c304d496d6c2e841626ebb7d44c1 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 29 Oct 2017 00:56:00 +0200 Subject: test: ui/cmdline_spec.lua: enable on Windows --- test/functional/ui/cmdline_spec.lua | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 6a9f4a22b4..0f8302b036 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -5,8 +5,6 @@ local source = helpers.source local ok = helpers.ok local command = helpers.command -if helpers.pending_win32(pending) then return end - describe('external cmdline', function() local screen local last_level = 0 -- cgit