diff options
-rw-r--r-- | src/nvim/api/private/helpers.c | 16 | ||||
-rw-r--r-- | src/nvim/api/ui_events.in.h | 11 | ||||
-rw-r--r-- | src/nvim/ex_getln.c | 40 | ||||
-rw-r--r-- | 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('<cr>') - feed(':<C-R>=1+2<cr>') + + 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('<C-R>=1+2') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({{'Normal', '1+2'}}, content) eq("\"", char) eq(1, shift) + eq(2, level) + end) + + feed('<cr>') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({{'Normal', '3'}}, content) + eq(2, current_hide_level) + eq(1, level) + end) + + feed('<esc>') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq(1, current_hide_level) end) end) |