Пример #1
0
/*
 * Given a menu descriptor, e.g. "File.New", find it in the menu hierarchy.
 */
vimmenu_T *gui_find_menu(char_u *path_name)
{
  vimmenu_T   *menu = NULL;
  char_u      *name;
  char_u      *saved_name;
  char_u      *p;

  menu = root_menu;

  saved_name = vim_strsave(path_name);

  name = saved_name;
  while (*name) {
    /* find the end of one dot-separated name and put a NUL at the dot */
    p = menu_name_skip(name);

    while (menu != NULL) {
      if (menu_name_equal(name, menu)) {
        if (menu->children == NULL) {
          /* found a menu item instead of a sub-menu */
          if (*p == NUL)
            EMSG(_("E336: Menu path must lead to a sub-menu"));
          else
            EMSG(_(e_notsubmenu));
          menu = NULL;
          goto theend;
        }
        if (*p == NUL)              /* found a full match */
          goto theend;
        break;
      }
      menu = menu->next;
    }
    if (menu == NULL)           /* didn't find it */
      break;

    /* Found a match, search the sub-menu. */
    menu = menu->children;
    name = p;
  }

  if (menu == NULL)
    EMSG(_("E337: Menu not found - check menu names"));
theend:
  free(saved_name);
  return menu;
}
Пример #2
0
/*
 * Show the mapping associated with a menu item or hierarchy in a sub-menu.
 */
static int show_menus(char_u *path_name, int modes)
{
  char_u      *p;
  char_u      *name;
  vimmenu_T   *menu;
  vimmenu_T   *parent = NULL;

  menu = root_menu;
  name = path_name = vim_strsave(path_name);

  /* First, find the (sub)menu with the given name */
  while (*name) {
    p = menu_name_skip(name);
    while (menu != NULL) {
      if (menu_name_equal(name, menu)) {
        /* Found menu */
        if (*p != NUL && menu->children == NULL) {
          EMSG(_(e_notsubmenu));
          free(path_name);
          return FAIL;
        } else if ((menu->modes & modes) == 0x0) {
          EMSG(_(e_othermode));
          free(path_name);
          return FAIL;
        }
        break;
      }
      menu = menu->next;
    }
    if (menu == NULL) {
      EMSG2(_(e_nomenu), name);
      free(path_name);
      return FAIL;
    }
    name = p;
    parent = menu;
    menu = menu->children;
  }
  free(path_name);

  /* Now we have found the matching menu, and we list the mappings */
  /* Highlight title */
  MSG_PUTS_TITLE(_("\n--- Menus ---"));

  show_menus_recursive(parent, modes, 0);
  return OK;
}
Пример #3
0
/*
 * Set the (sub)menu with the given name to enabled or disabled.
 * Called recursively.
 */
static int menu_nable_recurse(vimmenu_T *menu, char_u *name, int modes, int enable)
{
  char_u      *p;

  if (menu == NULL)
    return OK;                  /* Got to bottom of hierarchy */

  /* Get name of this element in the menu hierarchy */
  p = menu_name_skip(name);

  /* Find the menu */
  while (menu != NULL) {
    if (*name == NUL || *name == '*' || menu_name_equal(name, menu)) {
      if (*p != NUL) {
        if (menu->children == NULL) {
          EMSG(_(e_notsubmenu));
          return FAIL;
        }
        if (menu_nable_recurse(menu->children, p, modes, enable)
            == FAIL)
          return FAIL;
      } else if (enable)
        menu->enabled |= modes;
      else
        menu->enabled &= ~modes;

      /*
       * When name is empty, we are doing all menu items for the given
       * modes, so keep looping, otherwise we are just doing the named
       * menu item (which has been found) so break here.
       */
      if (*name != NUL && *name != '*')
        break;
    }
    menu = menu->next;
  }
  if (*name != NUL && *name != '*' && menu == NULL) {
    EMSG2(_(e_nomenu), name);
    return FAIL;
  }


  return OK;
}
Пример #4
0
/*
 * Work out what to complete when doing command line completion of menu names.
 */
char_u *set_context_in_menu_cmd(expand_T *xp, char_u *cmd, char_u *arg, int forceit)
{
  char_u      *after_dot;
  char_u      *p;
  char_u      *path_name = NULL;
  char_u      *name;
  int unmenu;
  vimmenu_T   *menu;
  int expand_menus;

  xp->xp_context = EXPAND_UNSUCCESSFUL;


  /* Check for priority numbers, enable and disable */
  for (p = arg; *p; ++p)
    if (!VIM_ISDIGIT(*p) && *p != '.')
      break;

  if (!vim_iswhite(*p)) {
    if (STRNCMP(arg, "enable", 6) == 0
        && (arg[6] == NUL ||  vim_iswhite(arg[6])))
      p = arg + 6;
    else if (STRNCMP(arg, "disable", 7) == 0
             && (arg[7] == NUL || vim_iswhite(arg[7])))
      p = arg + 7;
    else
      p = arg;
  }

  while (*p != NUL && vim_iswhite(*p))
    ++p;

  arg = after_dot = p;

  for (; *p && !vim_iswhite(*p); ++p) {
    if ((*p == '\\' || *p == Ctrl_V) && p[1] != NUL)
      p++;
    else if (*p == '.')
      after_dot = p + 1;
  }

  /* ":tearoff" and ":popup" only use menus, not entries */
  expand_menus = !((*cmd == 't' && cmd[1] == 'e') || *cmd == 'p');
  expand_emenu = (*cmd == 'e');
  if (expand_menus && vim_iswhite(*p))
    return NULL;        /* TODO: check for next command? */
  if (*p == NUL) {              /* Complete the menu name */
    /*
     * With :unmenu, you only want to match menus for the appropriate mode.
     * With :menu though you might want to add a menu with the same name as
     * one in another mode, so match menus from other modes too.
     */
    expand_modes = get_menu_cmd_modes(cmd, forceit, NULL, &unmenu);
    if (!unmenu)
      expand_modes = MENU_ALL_MODES;

    menu = root_menu;
    if (after_dot != arg) {
      path_name = xmalloc(after_dot - arg);
      STRLCPY(path_name, arg, after_dot - arg);
    }
    name = path_name;
    while (name != NULL && *name) {
      p = menu_name_skip(name);
      while (menu != NULL) {
        if (menu_name_equal(name, menu)) {
          /* Found menu */
          if ((*p != NUL && menu->children == NULL)
              || ((menu->modes & expand_modes) == 0x0)) {
            /*
             * Menu path continues, but we have reached a leaf.
             * Or menu exists only in another mode.
             */
            free(path_name);
            return NULL;
          }
          break;
        }
        menu = menu->next;
      }
      if (menu == NULL) {
        /* No menu found with the name we were looking for */
        free(path_name);
        return NULL;
      }
      name = p;
      menu = menu->children;
    }
    free(path_name);

    xp->xp_context = expand_menus ? EXPAND_MENUNAMES : EXPAND_MENUS;
    xp->xp_pattern = after_dot;
    expand_menu = menu;
  } else                        /* We're in the mapping part */
    xp->xp_context = EXPAND_NOTHING;
  return NULL;
}
Пример #5
0
/*
 * Remove the (sub)menu with the given name from the menu hierarchy
 * Called recursively.
 */
static int 
remove_menu (
    vimmenu_T **menup,
    char_u *name,
    int modes,
    int silent                     /* don't give error messages */
)
{
  vimmenu_T   *menu;
  vimmenu_T   *child;
  char_u      *p;

  if (*menup == NULL)
    return OK;                  /* Got to bottom of hierarchy */

  /* Get name of this element in the menu hierarchy */
  p = menu_name_skip(name);

  /* Find the menu */
  while ((menu = *menup) != NULL) {
    if (*name == NUL || menu_name_equal(name, menu)) {
      if (*p != NUL && menu->children == NULL) {
        if (!silent)
          EMSG(_(e_notsubmenu));
        return FAIL;
      }
      if ((menu->modes & modes) != 0x0) {
#if defined(FEAT_GUI_W32) & defined(FEAT_TEAROFF)
        /*
         * If we are removing all entries for this menu,MENU_ALL_MODES,
         * Then kill any tearoff before we start
         */
        if (*p == NUL && modes == MENU_ALL_MODES) {
          if (IsWindow(menu->tearoff_handle))
            DestroyWindow(menu->tearoff_handle);
        }
#endif
        if (remove_menu(&menu->children, p, modes, silent) == FAIL)
          return FAIL;
      } else if (*name != NUL) {
        if (!silent)
          EMSG(_(e_othermode));
        return FAIL;
      }

      /*
       * When name is empty, we are removing all menu items for the given
       * modes, so keep looping, otherwise we are just removing the named
       * menu item (which has been found) so break here.
       */
      if (*name != NUL)
        break;

      /* Remove the menu item for the given mode[s].  If the menu item
       * is no longer valid in ANY mode, delete it */
      menu->modes &= ~modes;
      if (modes & MENU_TIP_MODE)
        free_menu_string(menu, MENU_INDEX_TIP);
      if ((menu->modes & MENU_ALL_MODES) == 0)
        free_menu(menup);
      else
        menup = &menu->next;
    } else
      menup = &menu->next;
  }
  if (*name != NUL) {
    if (menu == NULL) {
      if (!silent)
        EMSG2(_(e_nomenu), name);
      return FAIL;
    }


    /* Recalculate modes for menu based on the new updated children */
    menu->modes &= ~modes;
#if defined(FEAT_GUI_W32) & defined(FEAT_TEAROFF)
    if ((s_tearoffs) && (menu->children != NULL))     /* there's a tear bar.. */
      child = menu->children->next;       /* don't count tearoff bar */
    else
#endif
    child = menu->children;
    for (; child != NULL; child = child->next)
      menu->modes |= child->modes;
    if (modes & MENU_TIP_MODE) {
      free_menu_string(menu, MENU_INDEX_TIP);
#if defined(FEAT_TOOLBAR) && !defined(FEAT_GUI_W32) \
      && (defined(FEAT_BEVAL) || defined(FEAT_GUI_GTK))
      /* Need to update the menu tip. */
      if (gui.in_use)
        gui_mch_menu_set_tip(menu);
#endif
    }
    if ((menu->modes & MENU_ALL_MODES) == 0) {
      /* The menu item is no longer valid in ANY mode, so delete it */
#if defined(FEAT_GUI_W32) & defined(FEAT_TEAROFF)
      if (s_tearoffs && menu->children != NULL)       /* there's a tear bar.. */
        free_menu(&menu->children);
#endif
      *menup = menu;
      free_menu(menup);
    }
  }

  return OK;
}
Пример #6
0
/*
 * Add the menu with the given name to the menu hierarchy
 */
static int 
add_menu_path (
    char_u *menu_path,
    vimmenu_T *menuarg,           /* passes modes, iconfile, iconidx,
                                   icon_builtin, silent[0], noremap[0] */
    int *pri_tab,
    char_u *call_data
)
{
  char_u      *path_name;
  int modes = menuarg->modes;
  vimmenu_T   **menup;
  vimmenu_T   *menu = NULL;
  vimmenu_T   *parent;
  vimmenu_T   **lower_pri;
  char_u      *p;
  char_u      *name;
  char_u      *dname;
  char_u      *next_name;
  int i;
  int c;
  int d;
  int pri_idx = 0;
  int old_modes = 0;
  int amenu;
  char_u      *en_name;
  char_u      *map_to = NULL;

  /* Make a copy so we can stuff around with it, since it could be const */
  path_name = vim_strsave(menu_path);
  menup = &root_menu;
  parent = NULL;
  name = path_name;
  while (*name) {
    /* Get name of this element in the menu hierarchy, and the simplified
     * name (without mnemonic and accelerator text). */
    next_name = menu_name_skip(name);
    map_to = menutrans_lookup(name, (int)STRLEN(name));
    if (map_to != NULL) {
      en_name = name;
      name = map_to;
    } else
      en_name = NULL;
    dname = menu_text(name, NULL, NULL);
    if (dname == NULL)
      goto erret;
    if (*dname == NUL) {
      /* Only a mnemonic or accelerator is not valid. */
      EMSG(_("E792: Empty menu name"));
      goto erret;
    }

    /* See if it's already there */
    lower_pri = menup;
    menu = *menup;
    while (menu != NULL) {
      if (menu_name_equal(name, menu) || menu_name_equal(dname, menu)) {
        if (*next_name == NUL && menu->children != NULL) {
          if (!sys_menu)
            EMSG(_("E330: Menu path must not lead to a sub-menu"));
          goto erret;
        }
        if (*next_name != NUL && menu->children == NULL
            ) {
          if (!sys_menu)
            EMSG(_(e_notsubmenu));
          goto erret;
        }
        break;
      }
      menup = &menu->next;

      /* Count menus, to find where this one needs to be inserted.
       * Ignore menus that are not in the menubar (PopUp and Toolbar) */
      if (parent != NULL || menu_is_menubar(menu->name)) {
        if (menu->priority <= pri_tab[pri_idx]) {
          lower_pri = menup;
        }
      }
      menu = menu->next;
    }

    if (menu == NULL) {
      if (*next_name == NUL && parent == NULL) {
        EMSG(_("E331: Must not add menu items directly to menu bar"));
        goto erret;
      }

      if (menu_is_separator(dname) && *next_name != NUL) {
        EMSG(_("E332: Separator cannot be part of a menu path"));
        goto erret;
      }

      /* Not already there, so lets add it */
      menu = xcalloc(1, sizeof(vimmenu_T));

      menu->modes = modes;
      menu->enabled = MENU_ALL_MODES;
      menu->name = vim_strsave(name);
      /* separate mnemonic and accelerator text from actual menu name */
      menu->dname = menu_text(name, &menu->mnemonic, &menu->actext);
      if (en_name != NULL) {
        menu->en_name = vim_strsave(en_name);
        menu->en_dname = menu_text(en_name, NULL, NULL);
      } else {
        menu->en_name = NULL;
        menu->en_dname = NULL;
      }
      menu->priority = pri_tab[pri_idx];
      menu->parent = parent;

      /*
       * Add after menu that has lower priority.
       */
      menu->next = *lower_pri;
      *lower_pri = menu;

      old_modes = 0;

    } else {
      old_modes = menu->modes;

      /*
       * If this menu option was previously only available in other
       * modes, then make sure it's available for this one now
       * Also enable a menu when it's created or changed.
       */
      {
        menu->modes |= modes;
        menu->enabled |= modes;
      }
    }


    menup = &menu->children;
    parent = menu;
    name = next_name;
    free(dname);
    dname = NULL;
    if (pri_tab[pri_idx + 1] != -1)
      ++pri_idx;
  }
  free(path_name);

  /*
   * Only add system menu items which have not been defined yet.
   * First check if this was an ":amenu".
   */
  amenu = ((modes & (MENU_NORMAL_MODE | MENU_INSERT_MODE)) ==
           (MENU_NORMAL_MODE | MENU_INSERT_MODE));
  if (sys_menu)
    modes &= ~old_modes;

  if (menu != NULL && modes) {
    p = (call_data == NULL) ? NULL : vim_strsave(call_data);

    /* loop over all modes, may add more than one */
    for (i = 0; i < MENU_MODES; ++i) {
      if (modes & (1 << i)) {
        /* free any old menu */
        free_menu_string(menu, i);

        /* For "amenu", may insert an extra character.
         * Don't do this if adding a tearbar (addtearoff == FALSE).
         * Don't do this for "<Nop>". */
        c = 0;
        d = 0;
        if (amenu && call_data != NULL && *call_data != NUL
            ) {
          switch (1 << i) {
          case MENU_VISUAL_MODE:
          case MENU_SELECT_MODE:
          case MENU_OP_PENDING_MODE:
          case MENU_CMDLINE_MODE:
            c = Ctrl_C;
            break;
          case MENU_INSERT_MODE:
            c = Ctrl_BSL;
            d = Ctrl_O;
            break;
          }
        }

        if (c != 0) {
          menu->strings[i] = xmalloc(STRLEN(call_data) + 5 );
          menu->strings[i][0] = c;
          if (d == 0)
            STRCPY(menu->strings[i] + 1, call_data);
          else {
            menu->strings[i][1] = d;
            STRCPY(menu->strings[i] + 2, call_data);
          }
          if (c == Ctrl_C) {
            int len = (int)STRLEN(menu->strings[i]);

            /* Append CTRL-\ CTRL-G to obey 'insertmode'. */
            menu->strings[i][len] = Ctrl_BSL;
            menu->strings[i][len + 1] = Ctrl_G;
            menu->strings[i][len + 2] = NUL;
          }
        } else
          menu->strings[i] = p;
        menu->noremap[i] = menuarg->noremap[0];
        menu->silent[i] = menuarg->silent[0];
      }
    }
#if defined(FEAT_TOOLBAR) && !defined(FEAT_GUI_W32) \
    && (defined(FEAT_BEVAL) || defined(FEAT_GUI_GTK))
    /* Need to update the menu tip. */
    if (modes & MENU_TIP_MODE)
      gui_mch_menu_set_tip(menu);
#endif
  }
  return OK;

erret:
  free(path_name);
  free(dname);

  /* Delete any empty submenu we added before discovering the error.  Repeat
   * for higher levels. */
  while (parent != NULL && parent->children == NULL) {
    if (parent->parent == NULL)
      menup = &root_menu;
    else
      menup = &parent->parent->children;
    for (; *menup != NULL && *menup != parent; menup = &((*menup)->next))
      ;
    if (*menup == NULL)     /* safety check */
      break;
    parent = parent->parent;
    free_menu(menup);
  }
  return FAIL;
}
Пример #7
0
/*
 * Given a menu descriptor, e.g. "File.New", find it in the menu hierarchy and
 * execute it.
 */
void ex_emenu(exarg_T *eap)
{
  vimmenu_T   *menu;
  char_u      *name;
  char_u      *saved_name;
  char_u      *p;
  int idx;
  char_u      *mode;

  saved_name = vim_strsave(eap->arg);

  menu = root_menu;
  name = saved_name;
  while (*name) {
    /* Find in the menu hierarchy */
    p = menu_name_skip(name);

    while (menu != NULL) {
      if (menu_name_equal(name, menu)) {
        if (*p == NUL && menu->children != NULL) {
          EMSG(_("E333: Menu path must lead to a menu item"));
          menu = NULL;
        } else if (*p != NUL && menu->children == NULL) {
          EMSG(_(e_notsubmenu));
          menu = NULL;
        }
        break;
      }
      menu = menu->next;
    }
    if (menu == NULL || *p == NUL)
      break;
    menu = menu->children;
    name = p;
  }
  free(saved_name);
  if (menu == NULL) {
    EMSG2(_("E334: Menu not found: %s"), eap->arg);
    return;
  }

  /* Found the menu, so execute.
   * Use the Insert mode entry when returning to Insert mode. */
  if (restart_edit
      && !current_SID
      ) {
    mode = (char_u *)"Insert";
    idx = MENU_INDEX_INSERT;
  } else if (eap->addr_count) {
    pos_T tpos;

    mode = (char_u *)"Visual";
    idx = MENU_INDEX_VISUAL;

    /* GEDDES: This is not perfect - but it is a
     * quick way of detecting whether we are doing this from a
     * selection - see if the range matches up with the visual
     * select start and end.  */
    if ((curbuf->b_visual.vi_start.lnum == eap->line1)
        && (curbuf->b_visual.vi_end.lnum) == eap->line2) {
      /* Set it up for visual mode - equivalent to gv.  */
      VIsual_mode = curbuf->b_visual.vi_mode;
      tpos = curbuf->b_visual.vi_end;
      curwin->w_cursor = curbuf->b_visual.vi_start;
      curwin->w_curswant = curbuf->b_visual.vi_curswant;
    } else {
      /* Set it up for line-wise visual mode */
      VIsual_mode = 'V';
      curwin->w_cursor.lnum = eap->line1;
      curwin->w_cursor.col = 1;
      tpos.lnum = eap->line2;
      tpos.col = MAXCOL;
      tpos.coladd = 0;
    }

    /* Activate visual mode */
    VIsual_active = TRUE;
    VIsual_reselect = TRUE;
    check_cursor();
    VIsual = curwin->w_cursor;
    curwin->w_cursor = tpos;

    check_cursor();

    /* Adjust the cursor to make sure it is in the correct pos
     * for exclusive mode */
    if (*p_sel == 'e' && gchar_cursor() != NUL)
      ++curwin->w_cursor.col;
  } else {
    mode = (char_u *)"Normal";
    idx = MENU_INDEX_NORMAL;
  }

  if (idx != MENU_INDEX_INVALID && menu->strings[idx] != NULL) {
    /* When executing a script or function execute the commands right now.
     * Otherwise put them in the typeahead buffer. */
    if (current_SID != 0)
      exec_normal_cmd(menu->strings[idx], menu->noremap[idx],
          menu->silent[idx]);
    else
      ins_typebuf(menu->strings[idx], menu->noremap[idx], 0,
          TRUE, menu->silent[idx]);
  } else
    EMSG2(_("E335: Menu not defined for %s mode"), mode);
}
Пример #8
0
/*
 * Remove the (sub)menu with the given name from the menu hierarchy
 * Called recursively.
 */
static int
remove_menu (
    vimmenu_T **menup,
    char_u *name,
    int modes,
    bool silent                     /* don't give error messages */
)
{
    vimmenu_T   *menu;
    vimmenu_T   *child;
    char_u      *p;

    if (*menup == NULL)
        return OK;                  /* Got to bottom of hierarchy */

    /* Get name of this element in the menu hierarchy */
    p = menu_name_skip(name);

    /* Find the menu */
    while ((menu = *menup) != NULL) {
        if (*name == NUL || menu_name_equal(name, menu)) {
            if (*p != NUL && menu->children == NULL) {
                if (!silent)
                    EMSG(_(e_notsubmenu));
                return FAIL;
            }
            if ((menu->modes & modes) != 0x0) {
                if (remove_menu(&menu->children, p, modes, silent) == FAIL)
                    return FAIL;
            } else if (*name != NUL) {
                if (!silent)
                    EMSG(_(e_othermode));
                return FAIL;
            }

            /*
             * When name is empty, we are removing all menu items for the given
             * modes, so keep looping, otherwise we are just removing the named
             * menu item (which has been found) so break here.
             */
            if (*name != NUL)
                break;

            /* Remove the menu item for the given mode[s].  If the menu item
             * is no longer valid in ANY mode, delete it */
            menu->modes &= ~modes;
            if (modes & MENU_TIP_MODE)
                free_menu_string(menu, MENU_INDEX_TIP);
            if ((menu->modes & MENU_ALL_MODES) == 0)
                free_menu(menup);
            else
                menup = &menu->next;
        } else
            menup = &menu->next;
    }
    if (*name != NUL) {
        if (menu == NULL) {
            if (!silent)
                EMSG2(_(e_nomenu), name);
            return FAIL;
        }


        /* Recalculate modes for menu based on the new updated children */
        menu->modes &= ~modes;
        child = menu->children;
        for (; child != NULL; child = child->next)
            menu->modes |= child->modes;
        if (modes & MENU_TIP_MODE) {
            free_menu_string(menu, MENU_INDEX_TIP);
        }
        if ((menu->modes & MENU_ALL_MODES) == 0) {
            /* The menu item is no longer valid in ANY mode, so delete it */
            *menup = menu;
            free_menu(menup);
        }
    }

    return OK;
}