Beispiel #1
0
/*
 * Free the given menu structure and remove it from the linked list.
 */
static void free_menu(vimmenu_T **menup)
{
  int i;
  vimmenu_T   *menu;

  menu = *menup;


  /* Don't change *menup until after calling gui_mch_destroy_menu(). The
   * MacOS code needs the original structure to properly delete the menu. */
  *menup = menu->next;
  free(menu->name);
  free(menu->dname);
  free(menu->en_name);
  free(menu->en_dname);
  free(menu->actext);
  for (i = 0; i < MENU_MODES; i++)
    free_menu_string(menu, i);
  free(menu);

}
Beispiel #2
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;
}
Beispiel #3
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;
}
Beispiel #4
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;
}