예제 #1
0
파일: menu.c 프로젝트: Happy-Dude/neovim
/*
 * Unescape the name in the translate dictionary table.
 */
static void menu_unescape_name(char_u *name)
{
  char_u  *p;

  for (p = name; *p && *p != '.'; mb_ptr_adv(p))
    if (*p == '\\')
      STRMOVE(p, p + 1);
}
예제 #2
0
파일: menu.c 프로젝트: Happy-Dude/neovim
/*
 * Skip over this element of the menu path and return the start of the next
 * element.  Any \ and ^Vs are removed from the current element.
 * "name" may be modified.
 */
char_u *menu_name_skip(char_u *name)
{
  char_u  *p;

  for (p = name; *p && *p != '.'; mb_ptr_adv(p)) {
    if (*p == '\\' || *p == Ctrl_V) {
      STRMOVE(p, p + 1);
      if (*p == NUL)
        break;
    }
  }
  if (*p)
    *p++ = NUL;
  return p;
}
예제 #3
0
파일: mouse.c 프로젝트: hoop33/neovim
///
/// Return length of line "lnum" for horizontal scrolling.
///
static colnr_T scroll_line_len(linenr_T lnum)
{
  colnr_T col = 0;
  char_u *line = ml_get(lnum);
  if (*line != NUL) {
    for (;;) {
      int numchar = chartabsize(line, col);
      mb_ptr_adv(line);
      if (*line == NUL) {    // don't count the last character
        break;
      }
      col += numchar;
    }
  }
  return col;
}
예제 #4
0
파일: mark.c 프로젝트: NOLFXceptMe/neovim
/*
 * Return the line at mark "mp".  Truncate to fit in window.
 * The returned string has been allocated.
 */
static char_u *mark_line(pos_T *mp, int lead_len)
{
  char_u      *s, *p;
  int len;

  if (mp->lnum == 0 || mp->lnum > curbuf->b_ml.ml_line_count)
    return vim_strsave((char_u *)"-invalid-");
  s = vim_strnsave(skipwhite(ml_get(mp->lnum)), (int)Columns);

  /* Truncate the line to fit it in the window */
  len = 0;
  for (p = s; *p != NUL; mb_ptr_adv(p)) {
    len += ptr2cells(p);
    if (len >= Columns - lead_len)
      break;
  }
  *p = NUL;
  return s;
}
예제 #5
0
/// Redraw the popup menu, using "pum_first" and "pum_selected".
void pum_redraw(void)
{
  int row = pum_row;
  int col;
  int attr_norm = highlight_attr[HLF_PNI];
  int attr_select = highlight_attr[HLF_PSI];
  int attr_scroll = highlight_attr[HLF_PSB];
  int attr_thumb = highlight_attr[HLF_PST];
  int attr;
  int i;
  int idx;
  char_u *s;
  char_u *p = NULL;
  int totwidth, width, w;
  int thumb_pos = 0;
  int thumb_heigth = 1;
  int round;
  int n;

  // Never display more than we have
  if (pum_first > pum_size - pum_height) {
    pum_first = pum_size - pum_height;
  }

  if (pum_scrollbar) {
    thumb_heigth = pum_height * pum_height / pum_size;
    if (thumb_heigth == 0) {
      thumb_heigth = 1;
    }
    thumb_pos = (pum_first * (pum_height - thumb_heigth)
                 + (pum_size - pum_height) / 2)
                / (pum_size - pum_height);
  }

  for (i = 0; i < pum_height; ++i) {
    idx = i + pum_first;
    attr = (idx == pum_selected) ? attr_select : attr_norm;

    // prepend a space if there is room
    if (curwin->w_p_rl) {
      if (pum_col < curwin->w_wincol + curwin->w_width - 1) {
        screen_putchar(' ', row, pum_col + 1, attr);
      }
    } else if (pum_col > 0) {
      screen_putchar(' ', row, pum_col - 1, attr);
    }

    // Display each entry, use two spaces for a Tab.
    // Do this 3 times: For the main text, kind and extra info
    col = pum_col;
    totwidth = 0;

    for (round = 1; round <= 3; ++round) {
      width = 0;
      s = NULL;

      switch (round) {
        case 1:
          p = pum_array[idx].pum_text;
          break;

        case 2:
          p = pum_array[idx].pum_kind;
          break;

        case 3:
          p = pum_array[idx].pum_extra;
          break;
      }

      if (p != NULL) {
        for (;; mb_ptr_adv(p)) {
          if (s == NULL) {
            s = p;
          }
          w = ptr2cells(p);

          if ((*p == NUL) || (*p == TAB) || (totwidth + w > pum_width)) {
            // Display the text that fits or comes before a Tab.
            // First convert it to printable characters.
            char_u *st;
            int saved = *p;

            *p = NUL;
            st = transstr(s);
            *p = saved;

            if (curwin->w_p_rl) {
              char_u *rt = reverse_text(st);
              char_u *rt_start = rt;
              int size = vim_strsize(rt);

              if (size > pum_width) {
                do {
                  size -= has_mbyte ? (*mb_ptr2cells)(rt) : 1;
                  mb_ptr_adv(rt);
                } while (size > pum_width);

                if (size < pum_width) {
                  // Most left character requires 2-cells but only 1 cell
                  // is available on screen.  Put a '<' on the left of the 
                  // pum item
                  *(--rt) = '<';
                  size++;
                }
              }
              screen_puts_len(rt, (int)STRLEN(rt), row, col - size + 1,
                              attr);
              free(rt_start);
              free(st);

              col -= width;
            } else {
              if (st != NULL) {
                screen_puts_len(st, (int)STRLEN(st), row, col, attr);
                free(st);
              }
              col += width;
            }

            if (*p != TAB) {
              break;
            }

            // Display two spaces for a Tab.
            if (curwin->w_p_rl) {
              screen_puts_len((char_u *)"  ", 2, row, col - 1, attr);
              col -= 2;
            } else {
              screen_puts_len((char_u *)"  ", 2, row, col, attr);
              col += 2;
            }
            totwidth += 2;
            // start text at next char
            s = NULL;
            width = 0;
          } else {
            width += w;
          }
        }
      }

      if (round > 1) {
        n = pum_kind_width + 1;
      } else {
        n = 1;
      }

      // Stop when there is nothing more to display.
      if ((round == 3)
          || ((round == 2)
              && (pum_array[idx].pum_extra == NULL))
          || ((round == 1)
              && (pum_array[idx].pum_kind == NULL)
              && (pum_array[idx].pum_extra == NULL))
          || (pum_base_width + n >= pum_width)) {
        break;
      }

      if (curwin->w_p_rl) {
        screen_fill(row, row + 1, pum_col - pum_base_width - n + 1,
                    col + 1, ' ', ' ', attr);
        col = pum_col - pum_base_width - n + 1;
      } else {
        screen_fill(row, row + 1, col, pum_col + pum_base_width + n,
                    ' ', ' ', attr);
        col = pum_col + pum_base_width + n;
      }
      totwidth = pum_base_width + n;
    }

    if (curwin->w_p_rl) {
      screen_fill(row, row + 1, pum_col - pum_width + 1, col + 1, ' ', ' ',
                  attr);
    } else {
      screen_fill(row, row + 1, col, pum_col + pum_width, ' ', ' ', attr);
    }

    if (pum_scrollbar > 0) {
      if (curwin->w_p_rl) {
        screen_putchar(' ', row, pum_col - pum_width,
                       i >= thumb_pos && i < thumb_pos + thumb_heigth
                       ? attr_thumb : attr_scroll);
      } else {
        screen_putchar(' ', row, pum_col + pum_width,
                       i >= thumb_pos && i < thumb_pos + thumb_heigth
                       ? attr_thumb : attr_scroll);
      }
    }
    row++;
  }
}
예제 #6
0
파일: menu.c 프로젝트: Happy-Dude/neovim
/*
 * Do the :menu command and relatives.
 */
void 
ex_menu (
    exarg_T *eap                   /* Ex command arguments */
)
{
  char_u      *menu_path;
  int modes;
  char_u      *map_to;
  int noremap;
  int silent = FALSE;
  int special = FALSE;
  int unmenu;
  char_u      *map_buf;
  char_u      *arg;
  char_u      *p;
  int i;
  int pri_tab[MENUDEPTH + 1];
  int enable = MAYBE;               /* TRUE for "menu enable", FALSE for "menu
                                     * disable */
  vimmenu_T menuarg;

  modes = get_menu_cmd_modes(eap->cmd, eap->forceit, &noremap, &unmenu);
  arg = eap->arg;

  for (;; ) {
    if (STRNCMP(arg, "<script>", 8) == 0) {
      noremap = REMAP_SCRIPT;
      arg = skipwhite(arg + 8);
      continue;
    }
    if (STRNCMP(arg, "<silent>", 8) == 0) {
      silent = TRUE;
      arg = skipwhite(arg + 8);
      continue;
    }
    if (STRNCMP(arg, "<special>", 9) == 0) {
      special = TRUE;
      arg = skipwhite(arg + 9);
      continue;
    }
    break;
  }


  /* Locate an optional "icon=filename" argument. */
  if (STRNCMP(arg, "icon=", 5) == 0) {
    arg += 5;
    while (*arg != NUL && *arg != ' ') {
      if (*arg == '\\')
        STRMOVE(arg, arg + 1);
      mb_ptr_adv(arg);
    }
    if (*arg != NUL) {
      *arg++ = NUL;
      arg = skipwhite(arg);
    }
  }

  /*
   * Fill in the priority table.
   */
  for (p = arg; *p; ++p)
    if (!VIM_ISDIGIT(*p) && *p != '.')
      break;
  if (vim_iswhite(*p)) {
    for (i = 0; i < MENUDEPTH && !vim_iswhite(*arg); ++i) {
      pri_tab[i] = getdigits_int(&arg);
      if (pri_tab[i] == 0)
        pri_tab[i] = 500;
      if (*arg == '.')
        ++arg;
    }
    arg = skipwhite(arg);
  } else if (eap->addr_count && eap->line2 != 0) {
    pri_tab[0] = eap->line2;
    i = 1;
  } else
    i = 0;
  while (i < MENUDEPTH)
    pri_tab[i++] = 500;
  pri_tab[MENUDEPTH] = -1;              /* mark end of the table */

  /*
   * Check for "disable" or "enable" argument.
   */
  if (STRNCMP(arg, "enable", 6) == 0 && vim_iswhite(arg[6])) {
    enable = TRUE;
    arg = skipwhite(arg + 6);
  } else if (STRNCMP(arg, "disable", 7) == 0 && vim_iswhite(arg[7])) {
    enable = FALSE;
    arg = skipwhite(arg + 7);
  }

  /*
   * If there is no argument, display all menus.
   */
  if (*arg == NUL) {
    show_menus(arg, modes);
    return;
  }


  menu_path = arg;
  if (*menu_path == '.') {
    EMSG2(_(e_invarg2), menu_path);
    goto theend;
  }

  map_to = menu_translate_tab_and_shift(arg);

  /*
   * If there is only a menu name, display menus with that name.
   */
  if (*map_to == NUL && !unmenu && enable == MAYBE) {
    show_menus(menu_path, modes);
    goto theend;
  } else if (*map_to != NUL && (unmenu || enable != MAYBE)) {
    EMSG(_(e_trailing));
    goto theend;
  }

  if (enable != MAYBE) {
    /*
     * Change sensitivity of the menu.
     * For the PopUp menu, remove a menu for each mode separately.
     * Careful: menu_nable_recurse() changes menu_path.
     */
    if (STRCMP(menu_path, "*") == 0)            /* meaning: do all menus */
      menu_path = (char_u *)"";

    if (menu_is_popup(menu_path)) {
      for (i = 0; i < MENU_INDEX_TIP; ++i)
        if (modes & (1 << i)) {
          p = popup_mode_name(menu_path, i);
          menu_nable_recurse(root_menu, p, MENU_ALL_MODES, enable);
          free(p);
        }
    }
    menu_nable_recurse(root_menu, menu_path, modes, enable);
  } else if (unmenu) {
    /*
     * Delete menu(s).
     */
    if (STRCMP(menu_path, "*") == 0)            /* meaning: remove all menus */
      menu_path = (char_u *)"";

    /*
     * For the PopUp menu, remove a menu for each mode separately.
     */
    if (menu_is_popup(menu_path)) {
      for (i = 0; i < MENU_INDEX_TIP; ++i)
        if (modes & (1 << i)) {
          p = popup_mode_name(menu_path, i);
          remove_menu(&root_menu, p, MENU_ALL_MODES, TRUE);
          free(p);
        }
    }

    /* Careful: remove_menu() changes menu_path */
    remove_menu(&root_menu, menu_path, modes, FALSE);
  } else {
    /*
     * Add menu(s).
     * Replace special key codes.
     */
    if (STRICMP(map_to, "<nop>") == 0) {        /* "<Nop>" means nothing */
      map_to = (char_u *)"";
      map_buf = NULL;
    } else if (modes & MENU_TIP_MODE)
      map_buf = NULL;           /* Menu tips are plain text. */
    else
      map_to = replace_termcodes(map_to, &map_buf, FALSE, TRUE, special);
    menuarg.modes = modes;
    menuarg.noremap[0] = noremap;
    menuarg.silent[0] = silent;
    add_menu_path(menu_path, &menuarg, pri_tab, map_to
        );

    /*
     * For the PopUp menu, add a menu for each mode separately.
     */
    if (menu_is_popup(menu_path)) {
      for (i = 0; i < MENU_INDEX_TIP; ++i)
        if (modes & (1 << i)) {
          p = popup_mode_name(menu_path, i);
          // Include all modes, to make ":amenu" work
          menuarg.modes = modes;
          add_menu_path(p, &menuarg, pri_tab, map_to);
          free(p);
        }
    }

    free(map_buf);
  }


theend:
  ;
}
예제 #7
0
파일: cursor.c 프로젝트: 1100110/neovim
static int coladvance2(
    pos_T *pos,
    bool addspaces,                /* change the text to achieve our goal? */
    bool finetune,                 /* change char offset for the exact column */
    colnr_T wcol                   /* column to move to */
)
{
  int idx;
  char_u      *ptr;
  char_u      *line;
  colnr_T col = 0;
  int csize = 0;
  int one_more;
  int head = 0;

  one_more = (State & INSERT)
             || restart_edit != NUL
             || (VIsual_active && *p_sel != 'o')
             || ((ve_flags & VE_ONEMORE) && wcol < MAXCOL);
  line = ml_get_buf(curbuf, pos->lnum, false);

  if (wcol >= MAXCOL) {
    idx = (int)STRLEN(line) - 1 + one_more;
    col = wcol;

    if ((addspaces || finetune) && !VIsual_active) {
      curwin->w_curswant = linetabsize(line) + one_more;
      if (curwin->w_curswant > 0)
        --curwin->w_curswant;
    }
  } else {
    int width = W_WIDTH(curwin) - win_col_off(curwin);

    if (finetune
        && curwin->w_p_wrap
        && curwin->w_width != 0
        && wcol >= (colnr_T)width) {
      csize = linetabsize(line);
      if (csize > 0)
        csize--;

      if (wcol / width > (colnr_T)csize / width
          && ((State & INSERT) == 0 || (int)wcol > csize + 1)) {
        /* In case of line wrapping don't move the cursor beyond the
         * right screen edge.  In Insert mode allow going just beyond
         * the last character (like what happens when typing and
         * reaching the right window edge). */
        wcol = (csize / width + 1) * width - 1;
      }
    }

    ptr = line;
    while (col <= wcol && *ptr != NUL) {
      /* Count a tab for what it's worth (if list mode not on) */
      csize = win_lbr_chartabsize(curwin, ptr, col, &head);
      mb_ptr_adv(ptr);
      col += csize;
    }
    idx = (int)(ptr - line);
    /*
     * Handle all the special cases.  The virtual_active() check
     * is needed to ensure that a virtual position off the end of
     * a line has the correct indexing.  The one_more comparison
     * replaces an explicit add of one_more later on.
     */
    if (col > wcol || (!virtual_active() && one_more == 0)) {
      idx -= 1;
      /* Don't count the chars from 'showbreak'. */
      csize -= head;
      col -= csize;
    }

    if (virtual_active()
        && addspaces
        && ((col != wcol && col != wcol + 1) || csize > 1)) {
      /* 'virtualedit' is set: The difference between wcol and col is
       * filled with spaces. */

      if (line[idx] == NUL) {
        /* Append spaces */
        int correct = wcol - col;
        char_u *newline = xmallocz((size_t)(idx + correct));
        memcpy(newline, line, (size_t)idx);
        memset(newline + idx, ' ', (size_t)correct);

        ml_replace(pos->lnum, newline, false);
        changed_bytes(pos->lnum, (colnr_T)idx);
        idx += correct;
        col = wcol;
      } else {
        /* Break a tab */
        int linelen = (int)STRLEN(line);
        int correct = wcol - col - csize + 1;             /* negative!! */
        char_u  *newline;

        if (-correct > csize)
          return FAIL;

        newline = xmallocz((size_t)(linelen - 1 + csize));
        // Copy first idx chars
        memcpy(newline, line, (size_t)idx);
        // Replace idx'th char with csize spaces
        memset(newline + idx, ' ', (size_t)csize);
        // Copy the rest of the line
        memcpy(newline + idx + csize, line + idx + 1,
               (size_t)(linelen - idx - 1));

        ml_replace(pos->lnum, newline, false);
        changed_bytes(pos->lnum, idx);
        idx += (csize - 1 + correct);
        col += correct;
      }
    }
  }

  if (idx < 0)
    pos->col = 0;
  else
    pos->col = idx;

  pos->coladd = 0;

  if (finetune) {
    if (wcol == MAXCOL) {
      /* The width of the last character is used to set coladd. */
      if (!one_more) {
        colnr_T scol, ecol;

        getvcol(curwin, pos, &scol, NULL, &ecol);
        pos->coladd = ecol - scol;
      }
    } else {
      int b = (int)wcol - (int)col;

      /* The difference between wcol and col is used to set coladd. */
      if (b > 0 && b < (MAXCOL - 2 * W_WIDTH(curwin)))
        pos->coladd = b;

      col += b;
    }
  }

  /* prevent from moving onto a trail byte */
  if (has_mbyte)
    mb_adjustpos(curbuf, pos);

  if (col < wcol)
    return FAIL;
  return OK;
}
예제 #8
0
파일: popupmnu.c 프로젝트: pthrasher/neovim
/*
 * Redraw the popup menu, using "pum_first" and "pum_selected".
 */
void pum_redraw(void)          {
    int row = pum_row;
    int col;
    int attr_norm = highlight_attr[HLF_PNI];
    int attr_select = highlight_attr[HLF_PSI];
    int attr_scroll = highlight_attr[HLF_PSB];
    int attr_thumb = highlight_attr[HLF_PST];
    int attr;
    int i;
    int idx;
    char_u      *s;
    char_u      *p = NULL;
    int totwidth, width, w;
    int thumb_pos = 0;
    int thumb_heigth = 1;
    int round;
    int n;

    /* Never display more than we have */
    if (pum_first > pum_size - pum_height)
        pum_first = pum_size - pum_height;

    if (pum_scrollbar) {
        thumb_heigth = pum_height * pum_height / pum_size;
        if (thumb_heigth == 0)
            thumb_heigth = 1;
        thumb_pos = (pum_first * (pum_height - thumb_heigth)
                     + (pum_size - pum_height) / 2)
                    / (pum_size - pum_height);
    }

    for (i = 0; i < pum_height; ++i) {
        idx = i + pum_first;
        attr = (idx == pum_selected) ? attr_select : attr_norm;

        /* prepend a space if there is room */
        if (curwin->w_p_rl) {
            if (pum_col < W_WINCOL(curwin) + W_WIDTH(curwin) - 1)
                screen_putchar(' ', row, pum_col + 1, attr);
        } else if (pum_col > 0)
            screen_putchar(' ', row, pum_col - 1, attr);

        /* Display each entry, use two spaces for a Tab.
         * Do this 3 times: For the main text, kind and extra info */
        col = pum_col;
        totwidth = 0;
        for (round = 1; round <= 3; ++round) {
            width = 0;
            s = NULL;
            switch (round) {
            case 1:
                p = pum_array[idx].pum_text;
                break;
            case 2:
                p = pum_array[idx].pum_kind;
                break;
            case 3:
                p = pum_array[idx].pum_extra;
                break;
            }
            if (p != NULL)
                for (;; mb_ptr_adv(p)) {
                    if (s == NULL)
                        s = p;
                    w = ptr2cells(p);
                    if (*p == NUL || *p == TAB || totwidth + w > pum_width) {
                        /* Display the text that fits or comes before a Tab.
                         * First convert it to printable characters. */
                        char_u  *st;
                        int saved = *p;

                        *p = NUL;
                        st = transstr(s);
                        *p = saved;
                        if (curwin->w_p_rl) {
                            if (st != NULL) {
                                char_u  *rt = reverse_text(st);

                                if (rt != NULL) {
                                    char_u      *rt_start = rt;
                                    int size;

                                    size = vim_strsize(rt);
                                    if (size > pum_width) {
                                        do {
                                            size -= has_mbyte
                                                    ? (*mb_ptr2cells)(rt) : 1;
                                            mb_ptr_adv(rt);
                                        } while (size > pum_width);

                                        if (size < pum_width) {
                                            /* Most left character requires
                                             * 2-cells but only 1 cell is
                                             * available on screen.  Put a
                                             * '<' on the left of the pum
                                             * item */
                                            *(--rt) = '<';
                                            size++;
                                        }
                                    }
                                    screen_puts_len(rt, (int)STRLEN(rt),
                                                    row, col - size + 1, attr);
                                    vim_free(rt_start);
                                }
                                vim_free(st);
                            }
                            col -= width;
                        } else   {
                            if (st != NULL) {
                                screen_puts_len(st, (int)STRLEN(st), row, col,
                                                attr);
                                vim_free(st);
                            }
                            col += width;
                        }

                        if (*p != TAB)
                            break;

                        /* Display two spaces for a Tab. */
                        if (curwin->w_p_rl) {
                            screen_puts_len((char_u *)"  ", 2, row, col - 1,
                                            attr);
                            col -= 2;
                        } else   {
                            screen_puts_len((char_u *)"  ", 2, row, col, attr);
                            col += 2;
                        }
                        totwidth += 2;
                        s = NULL;                       /* start text at next char */
                        width = 0;
                    } else
                        width += w;
                }

            if (round > 1)
                n = pum_kind_width + 1;
            else
                n = 1;

            /* Stop when there is nothing more to display. */
            if (round == 3
                    || (round == 2 && pum_array[idx].pum_extra == NULL)
                    || (round == 1 && pum_array[idx].pum_kind == NULL
                        && pum_array[idx].pum_extra == NULL)
                    || pum_base_width + n >= pum_width)
                break;
            if (curwin->w_p_rl) {
                screen_fill(row, row + 1, pum_col - pum_base_width - n + 1,
                            col + 1, ' ', ' ', attr);
                col = pum_col - pum_base_width - n + 1;
            } else   {
                screen_fill(row, row + 1, col, pum_col + pum_base_width + n,
                            ' ', ' ', attr);
                col = pum_col + pum_base_width + n;
            }
            totwidth = pum_base_width + n;
        }

        if (curwin->w_p_rl)
            screen_fill(row, row + 1, pum_col - pum_width + 1, col + 1, ' ',
                        ' ', attr);
        else
            screen_fill(row, row + 1, col, pum_col + pum_width, ' ', ' ',
                        attr);
        if (pum_scrollbar > 0) {
            if (curwin->w_p_rl)
                screen_putchar(' ', row, pum_col - pum_width,
                               i >= thumb_pos && i < thumb_pos + thumb_heigth
                               ? attr_thumb : attr_scroll);
            else
                screen_putchar(' ', row, pum_col + pum_width,
                               i >= thumb_pos && i < thumb_pos + thumb_heigth
                               ? attr_thumb : attr_scroll);
        }

        ++row;
    }
}