aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjörn Linse <bjorn.linse@gmail.com>2017-08-20 17:47:42 +0200
committerBjörn Linse <bjorn.linse@gmail.com>2017-10-26 20:29:08 +0200
commitbed0a3a8428027af32602ccb169e81767c55e257 (patch)
tree6590bf7ca2de3ca26f8d068505e8f88d623a70ce
parent2050e6604632e190a04d52829f4469f1ef7f7018 (diff)
downloadrneovim-bed0a3a8428027af32602ccb169e81767c55e257.tar.gz
rneovim-bed0a3a8428027af32602ccb169e81767c55e257.tar.bz2
rneovim-bed0a3a8428027af32602ccb169e81767c55e257.zip
ext_cmdline: implement redraw!
-rw-r--r--src/nvim/ex_getln.c166
-rw-r--r--src/nvim/screen.c5
-rw-r--r--test/functional/ui/cmdline_spec.lua54
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('<cr>')
+ -- 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('<cr>')
+ 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<cr>')
screen:expect([[
^ |