Merge #6539 'More cursor shape modes'

This commit is contained in:
Justin M. Keyes
2017-04-21 19:09:50 +02:00
17 changed files with 512 additions and 340 deletions

View File

@@ -73,7 +73,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height,
ui->clear = remote_ui_clear;
ui->eol_clear = remote_ui_eol_clear;
ui->cursor_goto = remote_ui_cursor_goto;
ui->cursor_style_set = remote_ui_cursor_style_set;
ui->mode_info_set = remote_ui_mode_info_set;
ui->update_menu = remote_ui_update_menu;
ui->busy_start = remote_ui_busy_start;
ui->busy_stop = remote_ui_busy_stop;
@@ -269,19 +269,14 @@ static void remote_ui_mouse_off(UI *ui)
push_call(ui, "mouse_off", args);
}
static void remote_ui_mode_change(UI *ui, int mode)
static void remote_ui_mode_change(UI *ui, int mode_idx)
{
Array args = ARRAY_DICT_INIT;
if (mode == INSERT) {
ADD(args, STRING_OBJ(cstr_to_string("insert")));
} else if (mode == REPLACE) {
ADD(args, STRING_OBJ(cstr_to_string("replace")));
} else if (mode == CMDLINE) {
ADD(args, STRING_OBJ(cstr_to_string("cmdline")));
} else {
assert(mode == NORMAL);
ADD(args, STRING_OBJ(cstr_to_string("normal")));
}
char *full_name = shape_table[mode_idx].full_name;
ADD(args, STRING_OBJ(cstr_to_string(full_name)));
ADD(args, INTEGER_OBJ(mode_idx));
push_call(ui, "mode_change", args);
}
@@ -303,12 +298,12 @@ static void remote_ui_scroll(UI *ui, int count)
push_call(ui, "scroll", args);
}
static void remote_ui_cursor_style_set(UI *ui, bool enabled, Dictionary data)
static void remote_ui_mode_info_set(UI *ui, bool guicursor_enabled, Array data)
{
Array args = ARRAY_DICT_INIT;
ADD(args, BOOLEAN_OBJ(enabled));
ADD(args, copy_object(DICTIONARY_OBJ(data)));
push_call(ui, "cursor_style_set", args);
ADD(args, BOOLEAN_OBJ(guicursor_enabled));
ADD(args, copy_object(ARRAY_OBJ(data)));
push_call(ui, "mode_info_set", args);
}
static void remote_ui_highlight_set(UI *ui, HlAttrs attrs)
@@ -396,8 +391,10 @@ static void remote_ui_update_sp(UI *ui, int sp)
static void remote_ui_flush(UI *ui)
{
UIData *data = ui->data;
channel_send_event(data->channel_id, "redraw", data->buffer);
data->buffer = (Array)ARRAY_DICT_INIT;
if (data->buffer.size > 0) {
channel_send_event(data->channel_id, "redraw", data->buffer);
data->buffer = (Array)ARRAY_DICT_INIT;
}
}
static void remote_ui_suspend(UI *ui)

View File

@@ -14,7 +14,7 @@
#include "nvim/ui.h"
/// Handling of cursor and mouse pointer shapes in various modes.
static cursorentry_T shape_table[SHAPE_IDX_COUNT] =
cursorentry_T shape_table[SHAPE_IDX_COUNT] =
{
// Values are set by 'guicursor' and 'mouseshape'.
// Adjust the SHAPE_IDX_ defines when changing this!
@@ -37,11 +37,11 @@ static cursorentry_T shape_table[SHAPE_IDX_COUNT] =
{ "showmatch", 0, 0, 0, 100L, 100L, 100L, 0, 0, "sm", SHAPE_CURSOR },
};
/// Converts cursor_shapes into a Dictionary of dictionaries
/// @return dictionary of the form {"normal" : { "cursor_shape": ... }, ...}
Dictionary cursor_shape_dict(void)
/// Converts cursor_shapes into an Array of Dictionaries
/// @return Array of the form {[ "cursor_shape": ... ], ...}
Array mode_style_array(void)
{
Dictionary all = ARRAY_DICT_INIT;
Array all = ARRAY_DICT_INIT;
for (int i = 0; i < SHAPE_IDX_COUNT; i++) {
Dictionary dic = ARRAY_DICT_INIT;
@@ -65,9 +65,10 @@ Dictionary cursor_shape_dict(void)
PUT(dic, "hl_id", INTEGER_OBJ(cur->id));
PUT(dic, "id_lm", INTEGER_OBJ(cur->id_lm));
}
PUT(dic, "name", STRING_OBJ(cstr_to_string(cur->full_name)));
PUT(dic, "short_name", STRING_OBJ(cstr_to_string(cur->name)));
PUT(all, cur->full_name, DICTIONARY_OBJ(dic));
ADD(all, DICTIONARY_OBJ(dic));
}
return all;
@@ -243,7 +244,7 @@ char_u *parse_shape_opt(int what)
shape_table[SHAPE_IDX_VE].id_lm = shape_table[SHAPE_IDX_V].id_lm;
}
}
ui_cursor_style_set();
ui_mode_info_set();
return NULL;
}
@@ -263,3 +264,35 @@ int cursor_mode_str2int(const char *mode)
return -1;
}
/// Return the index into shape_table[] for the current mode.
int cursor_get_mode_idx(void)
{
if (State == SHOWMATCH) {
return SHAPE_IDX_SM;
} else if (State & VREPLACE_FLAG) {
return SHAPE_IDX_R;
} else if (State & REPLACE_FLAG) {
return SHAPE_IDX_R;
} else if (State & INSERT) {
return SHAPE_IDX_I;
} else if (State & CMDLINE) {
if (cmdline_at_end()) {
return SHAPE_IDX_C;
} else if (cmdline_overstrike()) {
return SHAPE_IDX_CR;
} else {
return SHAPE_IDX_CI;
}
} else if (finish_op) {
return SHAPE_IDX_O;
} else if (VIsual_active) {
if (*p_sel == 'e') {
return SHAPE_IDX_VE;
} else {
return SHAPE_IDX_V;
}
} else {
return SHAPE_IDX_N;
}
}

View File

@@ -25,7 +25,7 @@ SHAPE_IDX_MORE = 14, ///< Hit-return or More
SHAPE_IDX_MOREL = 15, ///< Hit-return or More in last line
SHAPE_IDX_SM = 16, ///< showing matching paren
SHAPE_IDX_COUNT = 17
} MouseMode;
} ModeShape;
typedef enum {
SHAPE_BLOCK = 0, ///< block cursor
@@ -53,6 +53,7 @@ typedef struct cursor_entry {
char used_for; ///< SHAPE_MOUSE and/or SHAPE_CURSOR
} cursorentry_T;
extern cursorentry_T shape_table[SHAPE_IDX_COUNT];
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "cursor_shape.h.generated.h"

View File

@@ -354,6 +354,7 @@ static int command_line_check(VimState *state)
quit_more = false; // reset after CTRL-D which had a more-prompt
cursorcmd(); // set the cursor on the right spot
ui_cursor_shape();
return 1;
}
@@ -2095,6 +2096,18 @@ redraw:
return (char_u *)line_ga.ga_data;
}
bool cmdline_overstrike(void)
{
return ccline.overstrike;
}
/// Return true if the cursor is at the end of the cmdline.
bool cmdline_at_end(void)
{
return (ccline.cmdpos >= ccline.cmdlen);
}
/*
* Allocate a new command line buffer.
* Assigns the new buffer to ccline.cmdbuff and ccline.cmdbufflen.
@@ -2265,6 +2278,7 @@ void putcmdline(int c, int shift)
draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos);
msg_no_more = FALSE;
cursorcmd();
ui_cursor_shape();
}
/*
@@ -2284,6 +2298,7 @@ void unputcmdline(void)
draw_cmdline(ccline.cmdpos, 1);
msg_no_more = FALSE;
cursorcmd();
ui_cursor_shape();
}
/*
@@ -2601,6 +2616,7 @@ void redrawcmdline(void)
compute_cmdrow();
redrawcmd();
cursorcmd();
ui_cursor_shape();
}
static void redrawcmdprompt(void)

View File

@@ -459,6 +459,7 @@ void setmouse(void)
{
int checkfor;
ui_cursor_shape();
/* be quick when mouse is off */
if (*p_mouse == NUL)

View File

@@ -76,7 +76,7 @@ typedef struct {
bool busy;
cursorentry_T cursor_shapes[SHAPE_IDX_COUNT];
HlAttrs print_attrs;
int showing_mode;
ModeShape showing_mode;
struct {
int enable_mouse, disable_mouse;
int enable_bracketed_paste, disable_bracketed_paste;
@@ -104,7 +104,7 @@ UI *tui_start(void)
ui->clear = tui_clear;
ui->eol_clear = tui_eol_clear;
ui->cursor_goto = tui_cursor_goto;
ui->cursor_style_set = tui_cursor_style_set;
ui->mode_info_set = tui_mode_info_set;
ui->update_menu = tui_update_menu;
ui->busy_start = tui_busy_start;
ui->busy_stop = tui_busy_stop;
@@ -134,7 +134,7 @@ static void terminfo_start(UI *ui)
data->can_use_terminal_scroll = true;
data->bufpos = 0;
data->bufsize = sizeof(data->buf) - CNORM_COMMAND_MAX_SIZE;
data->showing_mode = 0;
data->showing_mode = SHAPE_IDX_N;
data->unibi_ext.enable_mouse = -1;
data->unibi_ext.disable_mouse = -1;
data->unibi_ext.set_cursor_color = -1;
@@ -176,7 +176,7 @@ static void terminfo_stop(UI *ui)
{
TUIData *data = ui->data;
// Destroy output stuff
tui_mode_change(ui, NORMAL);
tui_mode_change(ui, SHAPE_IDX_N);
tui_mouse_off(ui);
unibi_out(ui, unibi_exit_attribute_mode);
// cursor should be set to normal before exiting alternate screen
@@ -475,27 +475,24 @@ static cursorentry_T decode_cursor_entry(Dictionary args)
return r;
}
static void tui_cursor_style_set(UI *ui, bool enabled, Dictionary args)
static void tui_mode_info_set(UI *ui, bool guicursor_enabled, Array args)
{
cursor_style_enabled = enabled;
if (!enabled) {
cursor_style_enabled = guicursor_enabled;
if (!guicursor_enabled) {
return; // Do not send cursor style control codes.
}
TUIData *data = ui->data;
assert(args.size);
// Keys: as defined by `shape_table`.
// cursor style entries as defined by `shape_table`.
for (size_t i = 0; i < args.size; i++) {
char *mode_name = args.items[i].key.data;
const int mode_id = cursor_mode_str2int(mode_name);
assert(mode_id >= 0);
cursorentry_T r = decode_cursor_entry(args.items[i].value.data.dictionary);
r.full_name = mode_name;
data->cursor_shapes[mode_id] = r;
assert(args.items[i].type == kObjectTypeDictionary);
cursorentry_T r = decode_cursor_entry(args.items[i].data.dictionary);
data->cursor_shapes[i] = r;
}
MouseMode cursor_mode = tui_mode2cursor(data->showing_mode);
tui_set_cursor(ui, cursor_mode);
tui_set_mode(ui, data->showing_mode);
}
static void tui_update_menu(UI *ui)
@@ -532,7 +529,7 @@ static void tui_mouse_off(UI *ui)
}
/// @param mode one of SHAPE_XXX
static void tui_set_cursor(UI *ui, MouseMode mode)
static void tui_set_mode(UI *ui, ModeShape mode)
{
if (!cursor_style_enabled) {
return;
@@ -587,42 +584,12 @@ static void tui_set_cursor(UI *ui, MouseMode mode)
}
}
/// Returns cursor mode from edit mode
static MouseMode tui_mode2cursor(int mode)
{
switch (mode) {
case INSERT: return SHAPE_IDX_I;
case CMDLINE: return SHAPE_IDX_C;
case REPLACE: return SHAPE_IDX_R;
case NORMAL:
default: return SHAPE_IDX_N;
}
}
/// @param mode editor mode
static void tui_mode_change(UI *ui, int mode)
static void tui_mode_change(UI *ui, int mode_idx)
{
TUIData *data = ui->data;
if (mode == INSERT) {
if (data->showing_mode != INSERT) {
tui_set_cursor(ui, SHAPE_IDX_I);
}
} else if (mode == CMDLINE) {
if (data->showing_mode != CMDLINE) {
tui_set_cursor(ui, SHAPE_IDX_C);
}
} else if (mode == REPLACE) {
if (data->showing_mode != REPLACE) {
tui_set_cursor(ui, SHAPE_IDX_R);
}
} else {
assert(mode == NORMAL);
if (data->showing_mode != NORMAL) {
tui_set_cursor(ui, SHAPE_IDX_N);
}
}
data->showing_mode = mode;
tui_set_mode(ui, (ModeShape)mode_idx);
data->showing_mode = (ModeShape)mode_idx;
}
static void tui_set_scroll_region(UI *ui, int top, int bot, int left,

View File

@@ -56,6 +56,7 @@ static int current_attr_code = 0;
static bool pending_cursor_update = false;
static int busy = 0;
static int height, width;
static int old_mode_idx = -1;
// UI_CALL invokes a function on all registered UI instances. The functions can
// have 0-5 arguments (configurable by SELECT_NTH).
@@ -153,12 +154,6 @@ void ui_event(char *name, Array args)
}
}
// May update the shape of the cursor.
void ui_cursor_shape(void)
{
ui_mode_change();
}
void ui_refresh(void)
{
if (!ui_active()) {
@@ -183,7 +178,9 @@ void ui_refresh(void)
row = col = 0;
screen_resize(width, height);
pum_set_external(pum_external);
ui_cursor_style_set();
ui_mode_info_set();
old_mode_idx = -1;
ui_cursor_shape();
}
static void ui_refresh_event(void **argv)
@@ -381,12 +378,12 @@ void ui_cursor_goto(int new_row, int new_col)
pending_cursor_update = true;
}
void ui_cursor_style_set(void)
void ui_mode_info_set(void)
{
Dictionary style = cursor_shape_dict();
Array style = mode_style_array();
bool enabled = (*p_guicursor != NUL);
UI_CALL(cursor_style_set, enabled, style);
api_free_dictionary(style);
UI_CALL(mode_info_set, enabled, style);
api_free_array(style);
}
void ui_update_menu(void)
@@ -544,25 +541,19 @@ static void flush_cursor_update(void)
}
}
// Notify that the current mode has changed. Can be used to change cursor
// shape, for example.
static void ui_mode_change(void)
/// Check if current mode has changed.
/// May update the shape of the cursor.
void ui_cursor_shape(void)
{
int mode;
if (!full_screen) {
return;
}
// Get a simple UI mode out of State.
if ((State & REPLACE) == REPLACE) {
mode = REPLACE;
} else if (State & INSERT) {
mode = INSERT;
} else if (State & CMDLINE) {
mode = CMDLINE;
} else {
mode = NORMAL;
int mode_idx = cursor_get_mode_idx();
if (old_mode_idx != mode_idx) {
old_mode_idx = mode_idx;
UI_CALL(mode_change, mode_idx);
}
UI_CALL(mode_change, mode);
conceal_check_cursur_line();
}

View File

@@ -22,13 +22,13 @@ struct ui_t {
void (*clear)(UI *ui);
void (*eol_clear)(UI *ui);
void (*cursor_goto)(UI *ui, int row, int col);
void (*cursor_style_set)(UI *ui, bool enabled, Dictionary cursor_styles);
void (*mode_info_set)(UI *ui, bool enabled, Array cursor_styles);
void (*update_menu)(UI *ui);
void (*busy_start)(UI *ui);
void (*busy_stop)(UI *ui);
void (*mouse_on)(UI *ui);
void (*mouse_off)(UI *ui);
void (*mode_change)(UI *ui, int mode);
void (*mode_change)(UI *ui, int mode_idx);
void (*set_scroll_region)(UI *ui, int top, int bot, int left, int right);
void (*scroll)(UI *ui, int count);
void (*highlight_set)(UI *ui, HlAttrs attrs);

View File

@@ -63,7 +63,7 @@ UI *ui_bridge_attach(UI *ui, ui_main_fn ui_main, event_scheduler scheduler)
rv->bridge.clear = ui_bridge_clear;
rv->bridge.eol_clear = ui_bridge_eol_clear;
rv->bridge.cursor_goto = ui_bridge_cursor_goto;
rv->bridge.cursor_style_set = ui_bridge_cursor_style_set;
rv->bridge.mode_info_set = ui_bridge_mode_info_set;
rv->bridge.update_menu = ui_bridge_update_menu;
rv->bridge.busy_start = ui_bridge_busy_start;
rv->bridge.busy_stop = ui_bridge_busy_stop;
@@ -183,23 +183,23 @@ static void ui_bridge_cursor_goto_event(void **argv)
ui->cursor_goto(ui, PTR2INT(argv[1]), PTR2INT(argv[2]));
}
static void ui_bridge_cursor_style_set(UI *b, bool enabled, Dictionary styles)
static void ui_bridge_mode_info_set(UI *b, bool enabled, Array modes)
{
bool *enabledp = xmalloc(sizeof(*enabledp));
Object *stylesp = xmalloc(sizeof(*stylesp));
Object *modesp = xmalloc(sizeof(*modesp));
*enabledp = enabled;
*stylesp = copy_object(DICTIONARY_OBJ(styles));
UI_CALL(b, cursor_style_set, 3, b, enabledp, stylesp);
*modesp = copy_object(ARRAY_OBJ(modes));
UI_CALL(b, mode_info_set, 3, b, enabledp, modesp);
}
static void ui_bridge_cursor_style_set_event(void **argv)
static void ui_bridge_mode_info_set_event(void **argv)
{
UI *ui = UI(argv[0]);
bool *enabled = argv[1];
Object *styles = argv[2];
ui->cursor_style_set(ui, *enabled, styles->data.dictionary);
Object *modes = argv[2];
ui->mode_info_set(ui, *enabled, modes->data.array);
xfree(enabled);
api_free_object(*styles);
xfree(styles);
api_free_object(*modes);
xfree(modes);
}
static void ui_bridge_update_menu(UI *b)
@@ -252,9 +252,9 @@ static void ui_bridge_mouse_off_event(void **argv)
ui->mouse_off(ui);
}
static void ui_bridge_mode_change(UI *b, int mode)
static void ui_bridge_mode_change(UI *b, int mode_idx)
{
UI_CALL(b, mode_change, 2, b, INT2PTR(mode));
UI_CALL(b, mode_change, 2, b, INT2PTR(mode_idx));
}
static void ui_bridge_mode_change_event(void **argv)
{