Sublime Forum

Accessing submenus in quick panel

#1

I am working on a plugin that loads text notes from an external resource. The plugin works like this: Launch the command palette and type “open note”. Selecting the “open note” menu item executes ListNotebooks() which displays a list of notebooks. Selecting a notebook executes list_notes() that lists the notes in that notebook. Finally, selecting a specific note opens that note in a new view.

I’m having some issues with the last part, though. After reading some posts here, I ended up creating a seperate ViewNote class, but I’m not having any luck with that either. I’m fairly new to Python, so this is probably due to a misunderstanding on my part. Anyway, I’ve been banging my head against this for a few weeks now with no progress, so I’m hoping someone can help. I am able to select a notebook to view the notes in that notebook, but the plugin stops when I select a particular note. I get no errors when I run the plugin, but it seems to stop at the run_command() in the on_done() function.

class ListNotebooksCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        paper = PaperworkAPI()
        notebooklist = paper.list_notebooks()
        sublime.active_window().show_quick_panel(notebooklist, self.list_notes, sublime.KEEP_OPEN_ON_FOCUS_LOST)

    def list_notes(self, index):
        if index == -1:
            return 

        paper = PaperworkAPI()
        notebooklist = paper.list_notebooks()
        notebooktitle = notebooklist[index]
        self.notebookid = paper.notebook_to_id(notebooktitle)
        self.notelist = paper.list_notes(self.notebookid)
        sublime.active_window().show_quick_panel(self.notelist, self.on_done, sublime.KEEP_OPEN_ON_FOCUS_LOST, 0)

    def on_done(self, index):
        paper = PaperworkAPI()
        notelist = paper.list_notes(self.notebookid)
        notetitle = notelist[index]
        noteid = paper.note_to_id(notetitle)
        # This isn't being executed, or if it is, it's not throwing any errors
        # This should open a note with noteid that resides in notebook with notebookid
       self.view.run_command("View_Note", {'noteid': noteid})

class ViewNoteCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        print("test")
       paper = PaperworkAPI()
       # Get list of notes in notebookid
       notelist = paper.list_notes(self.notebookid)
       # Get title of note selected in quick panel
       notetitle = notelist[index]
       # Get noteid for note with title notetitle
       noteid = paper.note_to_id(notetitle)
       # Get note with id noteid in notebook with id notebookid
       note = paper.get_note(self.notebookid, noteid)
       # Convert HTML in note to plain text
       note = paper.html2text(note)
       self.view = self.view.window().new_file()
       windowtitle = paper.get_note_title(self.notebookid, noteid)
       self.view.set_name(windowtitle)
       # Display note in new view with title windowtitle
       self.view.insert(edit, self.view.sel()[0].begin(), note)
0 Likes

#2

View_Note may not exist… From what I’ve seen ViewNoteCommand would be translated to view_note - case may matter for run_command… It’s odd there is no error though…

You can also name it how it would be translated… class view_note( sublime_plugin.TextCommand ): … - It’s how I do mine for simplicity…

Also, PaperworkAPI - why are you creating a new object each time it runs? - If it is a library you can define the classes without the self argument then simply call them without…

For instance I have class AcecoolSublime: which acts as a library… tons of helper functions - I simply call them using AcecoolSublime.FindView( _name ) - defined as def FindView( _name, _window = None ): …

You don’t need to use ‘classes’ as objects - they can be used as namespaces to organize functions ( Although it is probably better to use a file that way - ie import PaperworkAPI and all of the functions within not part of any class would mean def Blah( ) would need to be called as PaperworkAPI.Blah( )…

0 Likes

#3

Commands are indeed case sensitive; for example insert inserts characters, but Insert does nothing. Sublime doesn’t complain about missing commands, they’re just silently dropped.

Other potential reasons for a command not being executed include it being disabled, or doing something like telling a window to execute a TextCommand or telling view to run a WindowCommand.

3 Likes

#4

Do you know if there is a way to disable silently dropping commands? This would help a lot of developers to get feedback for commands which don’t exist - it’d give them a starting point to look if there is a syntax error ( if they missed it in console and they see that error open up then they can scroll up to find it ), or if they miss-typed then it’d be the same error but with no syntax error in console it should be straight forward where to go next…

Especially since the commands are RENAMED! I see this as a huge issue - which is why I write my class names to be what they’d be translated to to begin with so there is no confusion… There should at least be a debug mode to state : class ListNotebooksCommand( sublime_plugin.TextCommand ) has been renamed for efficiency to: list_notebooks – or something along those lines…

0 Likes

#5

As far as I’m aware there’s no way to stop it from silently dropping commands, no. Actually I mis-spoke on that I think because if I recall correctly, you do in fact get an error about a missing command specifically if the target in a sublime-build file can’t be found, but I think that’s the only time that happens.

There shouldn’t be any confusion about what the command name would be as the rules are very distinct; the Command suffix on the class name is discarded if it’s there, the first letter is converted to lower case if it’s upper case, and every other uppercase letter is replaced with an underscore and it’s lowercase version.

For the purposes of debugging, you might find this plugin handy; it introspects all of the commands that are made available via plugin code (so commands in the Sublime core aren’t exposed since they’re presumably written in C++ for speed).

A modified version could output only commands for a specific set of packages, for example, and since it outputs them based on their type that would also help to diagnose problems like trying to run a TextCommand on a window.

Among other things the last method in the plugin file is the code from the sublime_plugin.py command that Sublime uses internally to create command names from class names, for those interested.

1 Like

#6

I can’t believe it came down to case sensitivity. For future readers, I had to change self.view.run_command("View_Note", {'noteid': noteid}) to self.view.run_command("view_note").

I should have spotted that on my own. Thank you, @OdatNurd. @Acecool, thank you for the advice. Like I said, I’m fairly new to Python. I appreciate the constructive criticism and examples for improvement.

1 Like

#7

Case Sensitivity exists everywhere but Windows downplays it for a lot… File-names, etc… it doesn’t matter, but logically they are completely different characters… They have different character identifier codes, etc…

Linux properly ensures file-names with the same text but different case can exist in the same folder… so be wary of that.

Also - try naming the commands what they would be renamed to for simplicity - that’s what I do because I hate that Sublime renames the functions / commands so I just make it what it would be otherwise so if someone looks through my code they won’t get confused, etc…

0 Likes