static void remote_ui_cursor_goto(UI *ui, int row, int col) { Array args = ARRAY_DICT_INIT; ADD(args, INTEGER_OBJ(row)); ADD(args, INTEGER_OBJ(col)); push_call(ui, "cursor_goto", args); }
static void remote_ui_resize(UI *ui, int width, int height) { Array args = ARRAY_DICT_INIT; ADD(args, INTEGER_OBJ(width)); ADD(args, INTEGER_OBJ(height)); push_call(ui, "resize", args); }
Dictionary version_dict(void) { Dictionary d = ARRAY_DICT_INIT; PUT(d, "major", INTEGER_OBJ(NVIM_VERSION_MAJOR)); PUT(d, "minor", INTEGER_OBJ(NVIM_VERSION_MINOR)); PUT(d, "patch", INTEGER_OBJ(NVIM_VERSION_PATCH)); PUT(d, "api_level", INTEGER_OBJ(NVIM_API_LEVEL)); PUT(d, "api_compatible", INTEGER_OBJ(NVIM_API_LEVEL_COMPAT)); PUT(d, "api_prerelease", BOOLEAN_OBJ(NVIM_API_PRERELEASE)); return d; }
static void remote_ui_set_scroll_region(UI *ui, int top, int bot, int left, int right) { Array args = ARRAY_DICT_INIT; ADD(args, INTEGER_OBJ(top)); ADD(args, INTEGER_OBJ(bot)); ADD(args, INTEGER_OBJ(left)); ADD(args, INTEGER_OBJ(right)); push_call(ui, "set_scroll_region", args); }
/// Converts an HlAttrs into Dictionary /// /// @param[in] aep data to convert /// @param use_rgb use 'gui*' settings if true, else resorts to 'cterm*' Dictionary hlattrs2dict(const HlAttrs *aep, bool use_rgb) { assert(aep); Dictionary hl = ARRAY_DICT_INIT; int mask = use_rgb ? aep->rgb_ae_attr : aep->cterm_ae_attr; if (mask & HL_BOLD) { PUT(hl, "bold", BOOLEAN_OBJ(true)); } if (mask & HL_STANDOUT) { PUT(hl, "standout", BOOLEAN_OBJ(true)); } if (mask & HL_UNDERLINE) { PUT(hl, "underline", BOOLEAN_OBJ(true)); } if (mask & HL_UNDERCURL) { PUT(hl, "undercurl", BOOLEAN_OBJ(true)); } if (mask & HL_ITALIC) { PUT(hl, "italic", BOOLEAN_OBJ(true)); } if (mask & HL_INVERSE) { PUT(hl, "reverse", BOOLEAN_OBJ(true)); } if (use_rgb) { if (aep->rgb_fg_color != -1) { PUT(hl, "foreground", INTEGER_OBJ(aep->rgb_fg_color)); } if (aep->rgb_bg_color != -1) { PUT(hl, "background", INTEGER_OBJ(aep->rgb_bg_color)); } if (aep->rgb_sp_color != -1) { PUT(hl, "special", INTEGER_OBJ(aep->rgb_sp_color)); } } else { if (cterm_normal_fg_color != aep->cterm_fg_color) { PUT(hl, "foreground", INTEGER_OBJ(aep->cterm_fg_color - 1)); } if (cterm_normal_bg_color != aep->cterm_bg_color) { PUT(hl, "background", INTEGER_OBJ(aep->cterm_bg_color - 1)); } } return hl; }
static void remote_ui_grid_resize(UI *ui, Integer grid, Integer width, Integer height) { Array args = ARRAY_DICT_INIT; if (ui->ui_ext[kUILinegrid]) { ADD(args, INTEGER_OBJ(grid)); } ADD(args, INTEGER_OBJ(width)); ADD(args, INTEGER_OBJ(height)); const char *name = ui->ui_ext[kUILinegrid] ? "grid_resize" : "resize"; push_call(ui, name, args); }
/// Gets the cursor position in the window /// /// @param window The window handle /// @param[out] err Details of an error that may have occurred /// @return the (row, col) tuple ArrayOf(Integer, 2) window_get_cursor(Window window, Error *err) { Array rv = ARRAY_DICT_INIT; win_T *win = find_window_by_handle(window, err); if (win) { ADD(rv, INTEGER_OBJ(win->w_cursor.lnum)); ADD(rv, INTEGER_OBJ(win->w_cursor.col)); } return rv; }
/// Gets the window position in display cells. First position is zero. /// /// @param window The window handle /// @param[out] err Details of an error that may have occurred /// @return The (row, col) tuple with the window position ArrayOf(Integer, 2) window_get_position(Window window, Error *err) { Array rv = ARRAY_DICT_INIT; win_T *win = find_window_by_handle(window, err); if (win) { ADD(rv, INTEGER_OBJ(win->w_winrow)); ADD(rv, INTEGER_OBJ(win->w_wincol)); } return rv; }
/// emulated cursor used both for drawing and for input focus static void remote_ui_cursor_goto(UI *ui, Integer row, Integer col) { UIData *data = ui->data; if (data->client_row == row && data->client_col == col) { return; } data->client_row = row; data->client_col = col; Array args = ARRAY_DICT_INIT; ADD(args, INTEGER_OBJ(row)); ADD(args, INTEGER_OBJ(col)); push_call(ui, "cursor_goto", args); }
static void remote_ui_default_colors_set(UI *ui, Integer rgb_fg, Integer rgb_bg, Integer rgb_sp, Integer cterm_fg, Integer cterm_bg) { Array args = ARRAY_DICT_INIT; ADD(args, INTEGER_OBJ(rgb_fg)); ADD(args, INTEGER_OBJ(rgb_bg)); ADD(args, INTEGER_OBJ(rgb_sp)); ADD(args, INTEGER_OBJ(cterm_fg)); ADD(args, INTEGER_OBJ(cterm_bg)); push_call(ui, "default_colors_set", args); // Deprecated if (!ui->ui_ext[kUILinegrid]) { args = (Array)ARRAY_DICT_INIT; ADD(args, INTEGER_OBJ(ui->rgb ? rgb_fg : cterm_fg - 1)); push_call(ui, "update_fg", args); args = (Array)ARRAY_DICT_INIT; ADD(args, INTEGER_OBJ(ui->rgb ? rgb_bg : cterm_bg - 1)); push_call(ui, "update_bg", args); args = (Array)ARRAY_DICT_INIT; ADD(args, INTEGER_OBJ(ui->rgb ? rgb_sp : -1)); push_call(ui, "update_sp", args); } }
static void init_error_type_metadata(Dictionary *metadata) { Dictionary types = ARRAY_DICT_INIT; Dictionary exception_metadata = ARRAY_DICT_INIT; PUT(exception_metadata, "id", INTEGER_OBJ(kErrorTypeException)); Dictionary validation_metadata = ARRAY_DICT_INIT; PUT(validation_metadata, "id", INTEGER_OBJ(kErrorTypeValidation)); PUT(types, "Exception", DICTIONARY_OBJ(exception_metadata)); PUT(types, "Validation", DICTIONARY_OBJ(validation_metadata)); PUT(*metadata, "error_types", DICTIONARY_OBJ(types)); }
/// "true" cursor used only for input focus static void remote_ui_grid_cursor_goto(UI *ui, Integer grid, Integer row, Integer col) { if (ui->ui_ext[kUILinegrid]) { Array args = ARRAY_DICT_INIT; ADD(args, INTEGER_OBJ(grid)); ADD(args, INTEGER_OBJ(row)); ADD(args, INTEGER_OBJ(col)); push_call(ui, "grid_cursor_goto", args); } else { UIData *data = ui->data; data->cursor_row = row; data->cursor_col = col; remote_ui_cursor_goto(ui, row, col); } }
static void remote_ui_grid_clear(UI *ui, Integer grid) { Array args = ARRAY_DICT_INIT; if (ui->ui_ext[kUILinegrid]) { ADD(args, INTEGER_OBJ(grid)); } const char *name = ui->ui_ext[kUILinegrid] ? "grid_clear" : "clear"; push_call(ui, name, args); }
static void init_type_metadata(Dictionary *metadata) { Dictionary types = ARRAY_DICT_INIT; Dictionary buffer_metadata = ARRAY_DICT_INIT; PUT(buffer_metadata, "id", INTEGER_OBJ(kObjectTypeBuffer)); Dictionary window_metadata = ARRAY_DICT_INIT; PUT(window_metadata, "id", INTEGER_OBJ(kObjectTypeWindow)); Dictionary tabpage_metadata = ARRAY_DICT_INIT; PUT(tabpage_metadata, "id", INTEGER_OBJ(kObjectTypeTabpage)); PUT(types, "Buffer", DICTIONARY_OBJ(buffer_metadata)); PUT(types, "Window", DICTIONARY_OBJ(window_metadata)); PUT(types, "Tabpage", DICTIONARY_OBJ(tabpage_metadata)); PUT(*metadata, "types", DICTIONARY_OBJ(types)); }
Array ui_array(void) { Array all_uis = ARRAY_DICT_INIT; for (size_t i = 0; i < ui_count; i++) { UI *ui = uis[i]; Dictionary info = ARRAY_DICT_INIT; PUT(info, "width", INTEGER_OBJ(ui->width)); PUT(info, "height", INTEGER_OBJ(ui->height)); PUT(info, "rgb", BOOLEAN_OBJ(ui->rgb)); for (UIExtension j = 0; j < kUIExtCount; j++) { PUT(info, ui_ext_names[j], BOOLEAN_OBJ(ui->ui_ext[j])); } if (ui->inspect) { ui->inspect(ui, &info); } ADD(all_uis, DICTIONARY_OBJ(info)); } return all_uis; }
static void remote_ui_highlight_set(UI *ui, HlAttrs attrs) { Array args = ARRAY_DICT_INIT; Dictionary hl = ARRAY_DICT_INIT; if (attrs.bold) { PUT(hl, "bold", BOOLEAN_OBJ(true)); } if (attrs.underline) { PUT(hl, "underline", BOOLEAN_OBJ(true)); } if (attrs.undercurl) { PUT(hl, "undercurl", BOOLEAN_OBJ(true)); } if (attrs.italic) { PUT(hl, "italic", BOOLEAN_OBJ(true)); } if (attrs.reverse) { PUT(hl, "reverse", BOOLEAN_OBJ(true)); } if (attrs.foreground != -1) { PUT(hl, "foreground", INTEGER_OBJ(attrs.foreground)); } if (attrs.background != -1) { PUT(hl, "background", INTEGER_OBJ(attrs.background)); } if (attrs.special != -1) { PUT(hl, "special", INTEGER_OBJ(attrs.special)); } ADD(args, DICTIONARY_OBJ(hl)); push_call(ui, "highlight_set", args); }
static void remote_ui_hl_attr_define(UI *ui, Integer id, HlAttrs rgb_attrs, HlAttrs cterm_attrs, Array info) { if (!ui->ui_ext[kUILinegrid]) { return; } Array args = ARRAY_DICT_INIT; ADD(args, INTEGER_OBJ(id)); ADD(args, DICTIONARY_OBJ(hlattrs2dict(rgb_attrs, true))); ADD(args, DICTIONARY_OBJ(hlattrs2dict(cterm_attrs, false))); if (ui->ui_ext[kUIHlState]) { ADD(args, ARRAY_OBJ(copy_array(info))); } else { ADD(args, ARRAY_OBJ((Array)ARRAY_DICT_INIT)); } push_call(ui, "hl_attr_define", args); }
static void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Integer endcol, Integer clearcol, Integer clearattr, Boolean wrap, const schar_T *chunk, const sattr_T *attrs) { UIData *data = ui->data; if (ui->ui_ext[kUILinegrid]) { Array args = ARRAY_DICT_INIT; ADD(args, INTEGER_OBJ(grid)); ADD(args, INTEGER_OBJ(row)); ADD(args, INTEGER_OBJ(startcol)); Array cells = ARRAY_DICT_INIT; int repeat = 0; size_t ncells = (size_t)(endcol-startcol); int last_hl = -1; for (size_t i = 0; i < ncells; i++) { repeat++; if (i == ncells-1 || attrs[i] != attrs[i+1] || STRCMP(chunk[i], chunk[i+1])) { Array cell = ARRAY_DICT_INIT; ADD(cell, STRING_OBJ(cstr_to_string((const char *)chunk[i]))); if (attrs[i] != last_hl || repeat > 1) { ADD(cell, INTEGER_OBJ(attrs[i])); last_hl = attrs[i]; } if (repeat > 1) { ADD(cell, INTEGER_OBJ(repeat)); } ADD(cells, ARRAY_OBJ(cell)); repeat = 0; } } if (endcol < clearcol) { Array cell = ARRAY_DICT_INIT; ADD(cell, STRING_OBJ(cstr_to_string(" "))); ADD(cell, INTEGER_OBJ(clearattr)); ADD(cell, INTEGER_OBJ(clearcol-endcol)); ADD(cells, ARRAY_OBJ(cell)); } ADD(args, ARRAY_OBJ(cells)); push_call(ui, "grid_line", args); } else { for (int i = 0; i < endcol-startcol; i++) { remote_ui_cursor_goto(ui, row, startcol+i); remote_ui_highlight_set(ui, attrs[i]); remote_ui_put(ui, (const char *)chunk[i]); if (utf_ambiguous_width(utf_ptr2char(chunk[i]))) { data->client_col = -1; // force cursor update } } if (endcol < clearcol) { remote_ui_cursor_goto(ui, row, endcol); remote_ui_highlight_set(ui, (int)clearattr); // legacy eol_clear was only ever used with cleared attributes // so be on the safe side if (clearattr == 0 && clearcol == Columns) { Array args = ARRAY_DICT_INIT; push_call(ui, "eol_clear", args); } else { for (Integer c = endcol; c < clearcol; c++) { remote_ui_put(ui, " "); } } } } }
static void remote_ui_update_sp(UI *ui, int sp) { Array args = ARRAY_DICT_INIT; ADD(args, INTEGER_OBJ(sp)); push_call(ui, "update_sp", args); }
static void remote_ui_update_bg(UI *ui, int bg) { Array args = ARRAY_DICT_INIT; ADD(args, INTEGER_OBJ(bg)); push_call(ui, "update_bg", args); }
static void remote_ui_scroll(UI *ui, int count) { Array args = ARRAY_DICT_INIT; ADD(args, INTEGER_OBJ(count)); push_call(ui, "scroll", args); }
static void remote_ui_grid_scroll(UI *ui, Integer grid, Integer top, Integer bot, Integer left, Integer right, Integer rows, Integer cols) { if (ui->ui_ext[kUILinegrid]) { Array args = ARRAY_DICT_INIT; ADD(args, INTEGER_OBJ(grid)); ADD(args, INTEGER_OBJ(top)); ADD(args, INTEGER_OBJ(bot)); ADD(args, INTEGER_OBJ(left)); ADD(args, INTEGER_OBJ(right)); ADD(args, INTEGER_OBJ(rows)); ADD(args, INTEGER_OBJ(cols)); push_call(ui, "grid_scroll", args); } else { Array args = ARRAY_DICT_INIT; ADD(args, INTEGER_OBJ(top)); ADD(args, INTEGER_OBJ(bot-1)); ADD(args, INTEGER_OBJ(left)); ADD(args, INTEGER_OBJ(right-1)); push_call(ui, "set_scroll_region", args); args = (Array)ARRAY_DICT_INIT; ADD(args, INTEGER_OBJ(rows)); push_call(ui, "scroll", args); // some clients have "clear" being affected by scroll region, // so reset it. args = (Array)ARRAY_DICT_INIT; ADD(args, INTEGER_OBJ(0)); ADD(args, INTEGER_OBJ(ui->height-1)); ADD(args, INTEGER_OBJ(0)); ADD(args, INTEGER_OBJ(ui->width-1)); push_call(ui, "set_scroll_region", args); } }
/// Show the popup menu with items "array[size]". /// "array" must remain valid until pum_undisplay() is called! /// When possible the leftmost character is aligned with screen column "col". /// The menu appears above the screen line "row" or at "row" + "height" - 1. /// /// @param array /// @param size /// @param selected index of initially selected item, none if out of range /// @param array_changed if true, array contains different items since last call /// if false, a new item is selected, but the array /// is the same void pum_display(pumitem_T *array, int size, int selected, bool array_changed) { int w; int def_width; int max_width; int kind_width; int extra_width; int i; int top_clear; int row; int context_lines; int col; int above_row = cmdline_row; int redo_count = 0; if (!pum_is_visible) { // To keep the code simple, we only allow changing the // draw mode when the popup menu is not being displayed pum_external = pum_wants_external; } redo: // Mark the pum as visible already here, // to avoid that must_redraw is set when 'cursorcolumn' is on. pum_is_visible = true; validate_cursor_col(); // anchor position: the start of the completed word row = curwin->w_wrow + curwin->w_winrow; if (curwin->w_p_rl) { col = curwin->w_wincol + curwin->w_width - curwin->w_wcol - 1; } else { col = curwin->w_wincol + curwin->w_wcol; } if (pum_external) { Array args = ARRAY_DICT_INIT; if (array_changed) { Array arr = ARRAY_DICT_INIT; for (i = 0; i < size; i++) { Array item = ARRAY_DICT_INIT; ADD(item, STRING_OBJ(cstr_to_string((char *)array[i].pum_text))); ADD(item, STRING_OBJ(cstr_to_string((char *)array[i].pum_kind))); ADD(item, STRING_OBJ(cstr_to_string((char *)array[i].pum_extra))); ADD(item, STRING_OBJ(cstr_to_string((char *)array[i].pum_info))); ADD(arr, ARRAY_OBJ(item)); } ADD(args, ARRAY_OBJ(arr)); ADD(args, INTEGER_OBJ(selected)); ADD(args, INTEGER_OBJ(row)); ADD(args, INTEGER_OBJ(col)); ui_event("popupmenu_show", args); } else { ADD(args, INTEGER_OBJ(selected)); ui_event("popupmenu_select", args); } return; } def_width = PUM_DEF_WIDTH; max_width = 0; kind_width = 0; extra_width = 0; if (firstwin->w_p_pvw) { top_clear = firstwin->w_height; } else { top_clear = 0; } // When the preview window is at the bottom stop just above it. Also // avoid drawing over the status line so that it's clear there is a window // boundary. if (lastwin->w_p_pvw) { above_row -= lastwin->w_height + lastwin->w_status_height + 1; } // Figure out the size and position of the pum. if (size < PUM_DEF_HEIGHT) { pum_height = size; } else { pum_height = PUM_DEF_HEIGHT; } if ((p_ph > 0) && (pum_height > p_ph)) { pum_height = (int)p_ph; } // Put the pum below "row" if possible. If there are few lines decide on // where there is more room. if ((row + 2 >= above_row - pum_height) && (row > (above_row - top_clear) / 2)) { // pum above "row" // Leave two lines of context if possible if (curwin->w_wrow - curwin->w_cline_row >= 2) { context_lines = 2; } else { context_lines = curwin->w_wrow - curwin->w_cline_row; } if (row >= size + context_lines) { pum_row = row - size - context_lines; pum_height = size; } else { pum_row = 0; pum_height = row - context_lines; } if ((p_ph > 0) && (pum_height > p_ph)) { pum_row += pum_height - (int)p_ph; pum_height = (int)p_ph; } } else { // pum below "row" // Leave two lines of context if possible if (curwin->w_cline_row + curwin->w_cline_height - curwin->w_wrow >= 3) { context_lines = 3; } else { context_lines = curwin->w_cline_row + curwin->w_cline_height - curwin->w_wrow; } pum_row = row + context_lines; if (size > above_row - pum_row) { pum_height = above_row - pum_row; } else { pum_height = size; } if ((p_ph > 0) && (pum_height > p_ph)) { pum_height = (int)p_ph; } } // don't display when we only have room for one line if ((pum_height < 1) || ((pum_height == 1) && (size > 1))) { return; } // If there is a preview window at the top avoid drawing over it. if (firstwin->w_p_pvw && (pum_row < firstwin->w_height) && (pum_height > firstwin->w_height + 4)) { pum_row += firstwin->w_height; pum_height -= firstwin->w_height; } // Compute the width of the widest match and the widest extra. for (i = 0; i < size; ++i) { w = vim_strsize(array[i].pum_text); if (max_width < w) { max_width = w; } if (array[i].pum_kind != NULL) { w = vim_strsize(array[i].pum_kind) + 1; if (kind_width < w) { kind_width = w; } } if (array[i].pum_extra != NULL) { w = vim_strsize(array[i].pum_extra) + 1; if (extra_width < w) { extra_width = w; } } } pum_base_width = max_width; pum_kind_width = kind_width; // if there are more items than room we need a scrollbar if (pum_height < size) { pum_scrollbar = 1; max_width++; } else { pum_scrollbar = 0; } if (def_width < max_width) { def_width = max_width; } if ((((col < Columns - PUM_DEF_WIDTH) || (col < Columns - max_width)) && !curwin->w_p_rl) || (curwin->w_p_rl && ((col > PUM_DEF_WIDTH) || (col > max_width)))) { // align pum column with "col" pum_col = col; if (curwin->w_p_rl) { pum_width = pum_col - pum_scrollbar + 1; } else { assert(Columns - pum_col - pum_scrollbar >= INT_MIN && Columns - pum_col - pum_scrollbar <= INT_MAX); pum_width = (int)(Columns - pum_col - pum_scrollbar); } if ((pum_width > max_width + kind_width + extra_width + 1) && (pum_width > PUM_DEF_WIDTH)) { pum_width = max_width + kind_width + extra_width + 1; if (pum_width < PUM_DEF_WIDTH) { pum_width = PUM_DEF_WIDTH; } } } else if (Columns < def_width) { // not enough room, will use what we have if (curwin->w_p_rl) { assert(Columns - 1 >= INT_MIN); pum_col = (int)(Columns - 1); } else { pum_col = 0; } assert(Columns - 1 >= INT_MIN); pum_width = (int)(Columns - 1); } else { if (max_width > PUM_DEF_WIDTH) { // truncate max_width = PUM_DEF_WIDTH; } if (curwin->w_p_rl) { pum_col = max_width - 1; } else { assert(Columns - max_width >= INT_MIN && Columns - max_width <= INT_MAX); pum_col = (int)(Columns - max_width); } pum_width = max_width - pum_scrollbar; } pum_array = array; pum_size = size; // Set selected item and redraw. If the window size changed need to redo // the positioning. Limit this to two times, when there is not much // room the window size will keep changing. if (pum_set_selected(selected, redo_count) && (++redo_count <= 2)) { goto redo; } }
static void remote_ui_inspect(UI *ui, Dictionary *info) { UIData *data = ui->data; PUT(*info, "chan", INTEGER_OBJ((Integer)data->channel_id)); }