简体   繁体   中英

How can I create a unique popup menu that I can use alongside the default context_menu?

( Plugin Development ) ( Sublime ) ( Python ) (.sublime-menu)

I am currently looking for a way to create a unique context_menu that does not rely on any of the default '.sublime-menu' files already in existence. I would just use the regular context_menu, but I have that pretty well filled up already. And I would like different buttons for different menus.

This is my current right click menu:

My current context_menu :

我当前的context_menu

I would like to create another dynamic menu similar to this menu, but one that is not dependent on the main/context.sublime-menu, and is activated by using the key/mouse combination ctrl+button4 (which I already have set up).

{
  "button": "button4",
  "count": 1,
  "modifiers": ["ctrl"],
  "command": "quick_click"
}

I have looked at show_popup_menu() as an option and have used the paste_from_history.py file as a sort of reference.

Class PasteFromHistoryCommand(sublime_plugin.TextCommand): from Sublime\\Packages\\Default.sublime-package.zip\\paste_from_history.py

However, the only thing that menu seems to do, is to take the selection which has been highlighted from a list, and pass it to a text variable which is then passed to the text command 'paste'.

ie

g_clipboard_history.push_text(text)
sublime.set_clipboard(text)
self.view.run_command("paste")

show_popup_menu(items, on_done, flags) has the fields ' items ', ' on_done ', ect . And I do not know what these mean or how to use them.

I have tried code like this: (And I get no feedback whatsoever)

class QuickClickCommand(sublime_plugin.TextCommand):
  def run(self, view):
    self.view.show_popup_menu (
      [
        "Select All",
        "Swap Case"
      ],
      [
        self.view.run_command("select_all"),
        self.view.run_command("swap_case")
      ],
      ["1", "2"]  // ← with or without this option
    )

But when I use the following code ►

class QuickClickCommand(sublime_plugin.TextCommand):
  def run(self, view):
    self.view.show_popup_menu (
      ["Item 1", "Item 2"], ["1", "2"]
    )

► I get a context menu with 2 items - neither of which do a single thing when pressed upon.

A type of context menu :

一种上下文菜单

I've tried several combinations - nothing seems to work, and I cannot find information on this topic.

As you can see I have a plugin:

class QuickClickCommand(sublime_plugin.TextCommand)

And I access that plugin by selecting ctrl+button4

{
    "button": "button4",
    "count": 1,
    "modifiers": ["ctrl"],
    "command": "quick_click"
}

Is it possible to create my own quickclick.sublime-menu file or am I stuck using the default context_menu.sublime-menu?

Any links, suggestions, or explanations of how show_popup_menu(items, on_done) is used would be appreciated .

Here is what the user docs say about it:

Shows a pop up menu at the caret, to select an item in a list.

on_done will be called once, with the index of the selected item.

If the pop up menu was cancelled, on_done will be called with an argument of -1.

Items is an array of strings.

Flags currently has no option.

When I use the code below : I get the following result.

class QuickClickCommand(sublime_plugin.TextCommand):
  def run(self, view):
    self.view.show_popup('Hello, <b>World!</b><br>
    <a href="moo">Click Me</a>', on_navigate=print)
    self.view.show_popup_menu (["Item 1", "Item 2"], ["1", "2"]) 

A menu pops up.

Popup Menu :

弹出菜单

Once I select any of these 2 Items, I get a panel with the words 'Hello World' and a 'Click Me' link.

Hello, World! Panel :

你好,世界!面板

Once clicking 'Click Me' - 'Hello, World' - will propagate itself to the console.

Is there a way to make my own custom menu in sublime ( aside from adding content to the 11 other possible menus that are available upon instillation )?

Thank you for your patients in reading this and any time you might spend on replying to me.

The documentation for view.show_popup_menu() says this:

API帮助

That is, the method takes a list of strings to display in the menu as a first argument and a function that will be called when the user picks an item as the second argument; that function will be passed the index of the item that the user selected.

In your example code, your second argument is not a function, it's another list of things. You don't get any direct feedback but that's only because Sublime is eating the error when it tries to invoke the callback and fails.

The third argument has no effect on anything because as outlined in the documentation, even though it's supposed to be flags it is currently ignored.

Your question also references the paste_from_history command that uses this API endpoint, and the relevant code line is this:

self.view.show_popup_menu(keys, lambda choice_index: self.paste_choice(choice_index))

That's a hint that the second argument is a function (in this case a lambda) which gets provided the index that was chosen when the user picked the item.

The takeaway from this is that unlike standard menus, when you use view.show_popup_menu() all it does is open a menu at the caret location in the window to show the user options, and when they pick one, you get told which one they picked. If the menu is dismissed without being selected, you get told that as well (by the selected item being -1 , which is not a valid index).

If you want to run commands from a menu like this, you want something like the following instead:

import sublime
import sublime_plugin


class QuickClickCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        items = [
            {"caption": "Echo stuff", "command": "echo", "args": {"a": True}},
            {"caption": "Select All", "command": "select_all"},
            {"caption": "Swap Case", "command": "swap_case"},
        ]
        self.view.show_popup_menu(
            [item["caption"] for item in items],
            lambda idx: self.pick(idx, items))

    def pick(self, idx, items):
        if idx >= 0:
            command = items[idx].get("command")
            args = items[idx].get("args")
            self.view.window().run_command(command, args)

First, there is a list of the commands that you want to be able to execute, outlined as objects that specify a caption (what you want to see in the menu), the command (the actual command to execute) and the args (any arguments the command might happen to take or require).

We invoke show_popup_menu and pass to it a list of strings that is the captions for all of the items in the list using a list comprehension. The second argument is the callback that will be called when the user cancels the menu or picks an item. We specify that it should be called given the index of the item that the user picked, as well as the original list of items.

When an item is chosen, pick() is invoked and given the index of the item chosen. If that's -1 , then the user closed the menu and so we do nothing. Otherwise, we use the index provided to get the command and arguments (if any) from the original list of items, and then run that command.

This uses self.view.window().run_command() and not self.view.run_command() because a view can only execute commands that modify the buffer; thus it's generally better to use the window to run the command instead because it can run all commands.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM