Esempio n. 1
0
/// Creates a deep clone of an object
static Object copy_object(Object obj)
{
  switch (obj.type) {
    case kObjectTypeNil:
    case kObjectTypeBoolean:
    case kObjectTypeInteger:
    case kObjectTypeFloat:
      return obj;

    case kObjectTypeString:
      return STRING_OBJ(cstr_to_string(obj.data.string.data));

    case kObjectTypeArray: {
      Array rv = ARRAY_DICT_INIT;
      for (size_t i = 0; i < obj.data.array.size; i++) {
        ADD(rv, copy_object(obj.data.array.items[i]));
      }
      return ARRAY_OBJ(rv);
    }

    case kObjectTypeDictionary: {
      Dictionary rv = ARRAY_DICT_INIT;
      for (size_t i = 0; i < obj.data.dictionary.size; i++) {
        KeyValuePair item = obj.data.dictionary.items[i];
        PUT(rv, item.key.data, copy_object(item.value));
      }
      return DICTIONARY_OBJ(rv);
    }
    default:
      abort();
  }
}
Esempio n. 2
0
static void ui_bridge_mode_info_set(UI *b, bool enabled, Array modes)
{
  bool *enabledp = xmalloc(sizeof(*enabledp));
  Object *modesp = xmalloc(sizeof(*modesp));
  *enabledp = enabled;
  *modesp = copy_object(ARRAY_OBJ(modes));
  UI_CALL(b, mode_info_set, 3, b, enabledp, modesp);
}
Esempio n. 3
0
File: ui.c Progetto: roxma/neovim
static Array translate_firstarg(UI *ui, Array args)
{
  Array new_args = ARRAY_DICT_INIT;
  Array contents = args.items[0].data.array;

  ADD(new_args, ARRAY_OBJ(translate_contents(ui, contents)));
  for (size_t i = 1; i < args.size; i++) {
    ADD(new_args, copy_object(args.items[i]));
  }
  return new_args;
}
Esempio n. 4
0
File: ui.c Progetto: roxma/neovim
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);
}
Esempio n. 5
0
File: ui.c Progetto: fatbird/neovim
static void push_call(UI *ui, char *name, Array args)
{
  Array call = ARRAY_DICT_INIT;
  UIData *data = ui->data;

  // To optimize data transfer(especially for "put"), we bundle adjacent
  // calls to same method together, so only add a new call entry if the last
  // method call is different from "name"
  if (kv_size(data->buffer)) {
    call = kv_A(data->buffer, kv_size(data->buffer) - 1).data.array;
  }

  if (!kv_size(call) || strcmp(kv_A(call, 0).data.string.data, name)) {
    call = (Array)ARRAY_DICT_INIT;
    ADD(data->buffer, ARRAY_OBJ(call));
    ADD(call, STRING_OBJ(cstr_to_string(name)));
  }

  ADD(call, ARRAY_OBJ(args));
  kv_A(data->buffer, kv_size(data->buffer) - 1).data.array = call;
}
Esempio n. 6
0
File: ui.c Progetto: roxma/neovim
static void remote_ui_event(UI *ui, char *name, Array args, bool *args_consumed)
{
  if (!ui->ui_ext[kUILinegrid]) {
    // the representation of highlights in cmdline changed, translate back
    // never consumes args
    if (strequal(name, "cmdline_show")) {
      Array new_args = translate_firstarg(ui, args);
      push_call(ui, name, new_args);
      return;
    } else if (strequal(name, "cmdline_block_show")) {
      Array new_args = ARRAY_DICT_INIT;
      Array block = args.items[0].data.array;
      Array new_block = ARRAY_DICT_INIT;
      for (size_t i = 0; i < block.size; i++) {
        ADD(new_block,
            ARRAY_OBJ(translate_contents(ui, block.items[i].data.array)));
      }
      ADD(new_args, ARRAY_OBJ(new_block));
      push_call(ui, name, new_args);
      return;
    } else if (strequal(name, "cmdline_block_append")) {
      Array new_args = translate_firstarg(ui, args);
      push_call(ui, name, new_args);
      return;
    }
  }

  Array my_args = ARRAY_DICT_INIT;
  // Objects are currently single-reference
  // make a copy, but only if necessary
  if (*args_consumed) {
    for (size_t i = 0; i < args.size; i++) {
      ADD(my_args, copy_object(args.items[i]));
    }
  } else {
    my_args = args;
    *args_consumed = true;
  }
  push_call(ui, name, my_args);
}
Esempio n. 7
0
static void remote_ui_cmdline_show(UI *ui, Array args)
{
  Array new_args = ARRAY_DICT_INIT;
  Array contents = args.items[0].data.array;
  Array new_contents = ARRAY_DICT_INIT;
  for (size_t i = 0; i < contents.size; i++) {
    Array item = contents.items[i].data.array;
    Array new_item = ARRAY_DICT_INIT;
    int attr = (int)item.items[0].data.integer;
    if (attr) {
      Dictionary rgb_attrs = hlattrs2dict(syn_attr2entry(attr), ui->rgb);
      ADD(new_item, DICTIONARY_OBJ(rgb_attrs));
    } else {
      ADD(new_item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT));
    }
    ADD(new_item, copy_object(item.items[1]));
    ADD(new_contents, ARRAY_OBJ(new_item));
  }
  ADD(new_args, ARRAY_OBJ(new_contents));
  for (size_t i = 1; i < args.size; i++) {
    ADD(new_args, copy_object(args.items[i]));
  }
  push_call(ui, "cmdline_show", new_args);
}
Esempio n. 8
0
File: ui.c Progetto: roxma/neovim
static Array translate_contents(UI *ui, Array contents)
{
  Array new_contents = ARRAY_DICT_INIT;
  for (size_t i = 0; i < contents.size; i++) {
    Array item = contents.items[i].data.array;
    Array new_item = ARRAY_DICT_INIT;
    int attr = (int)item.items[0].data.integer;
    if (attr) {
      Dictionary rgb_attrs = hlattrs2dict(syn_attr2entry(attr), ui->rgb);
      ADD(new_item, DICTIONARY_OBJ(rgb_attrs));
    } else {
      ADD(new_item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT));
    }
    ADD(new_item, copy_object(item.items[1]));
    ADD(new_contents, ARRAY_OBJ(new_item));
  }
  return new_contents;
}
Esempio n. 9
0
void provider_init_feature_metadata(Dictionary *metadata)
{
  Dictionary md = ARRAY_DICT_INIT;

  for (size_t i = 0; i < FEATURE_COUNT; i++) {
    Array methods = ARRAY_DICT_INIT;
    Feature *f = &features[i];

    size_t j;
    char *method;
    for (method = f->methods[j = 0]; method; method = f->methods[++j]) {
      ADD(methods, STRING_OBJ(cstr_to_string(method)));
    }

    PUT(md, f->name, ARRAY_OBJ(methods));
  }

  PUT(*metadata, "features", DICTIONARY_OBJ(md));
}
Esempio n. 10
0
/// 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;
  }
}
Esempio n. 11
0
File: ui.c Progetto: roxma/neovim
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, " ");
        }
      }
    }
  }
}