Sublime Forum

Nested snippets not expanding

#1

All,

I noticed nested snippets aren’t working.

In an HTML file when I type **ul **it correctly expands to

    . I next type li and normally that would expand to
  • but when it’s the first thing I type after the ul expands it just sits there.

    It appears that the stack that tracks expansions isn’t currently setup to check if the text just entered was a snippet and instead stays within the scope of the first snippet. I’d LOVE to see this fixed.

    Thanks,
    Shawn

  • 0 Likes

    #2

    Hi,

    I don’t know if this is a bug or if this is on purpose but it is kind of annoying in fact.

    For example if I want to quickly type in PHP

    if (!empty(...)) { ... }

    I’d like to be able to insert the if snippet and the empty snippet right after it.

    It would be really great if nested snippets were available :smile:

    0 Likes

    #3

    Is this the keypress sequence you are looking for?

    if<tab><esc>!empty<tab>
    0 Likes

    #4

    Nope.
    In this example the perfect thing would be :

    • I type if
      /*]
      ]the “if” parentheses appear, I directly type empty/]
      ]the “empty” parentheses appear, I type what I want in it and press /]
      ]the prompt is now outside the “empty” parentheses (it gets out of the "empty’ snippet) but still inside the “if”/]
      ]if I press tab again it goes inside the if { } to type the rest of the code/]

    This kind of behavior is already available by accessing to “sub snippets” with ctrl+space instead of tab but it’s kind of annoying.
    For example in php I can have an “array” snippet that I want to trigger when I’m already in the process of a snippet:

    *]I type array<ctrl+space>

    ]the list of all possible snippets and functions appear/]
    ]I potentially have to go through the list for a while before finding my snippet between similarly named functions/]
    ]I type enter, the “array” snippet appears/]
    ]I can tab in it as usual and after going out of it I can continue to tab in the “parent” snippet./]

    So, in one hand you now have “ctrl + space + finding snippet in list” and in other (not existing?) hand you have “tab”. I want that “tab” :stuck_out_tongue:

    0 Likes

    #5

    Hey, thanks for your answer and your code snippet!

    I changed the keys to ctrl+space and set the exact parameter to false. This enables me to stop having to go through a list of possible snippets when I want to trigger one. So in the end I trigger normal snippets with tab, I trigger nested snippets with ctrl+space and go through all of them normally with tab. I didn’t have lots of time to test but right now it seems the best option for me :smile:

    I couldn’t find a way to have something that works perfectly only by using “tab” based on your code though.
    With the code given, I can trigger snippets in other snippets, but I can’t go through the snippets anymore with tab: tab just inserts a real tab.

    I’m all ears if you have any other idea to find something perfect, otherwise this is already more productive than before, thanks :wink:

    0 Likes

    #6

    I’m going to bump this as well with two questions:

    Is there a command like insert_best_completion that only does snippet expansion?

    Is there a good place to request a new condition? I’d like to be able to write:

    	{ "keys": "tab"], "command": "insert_best_completion", "args": {"exact": true}, "context":
    		
    			{ "key": "has_next_field", "operator": "equal", "operand": true, "match_all": true },
    			{ "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
    			{ "key": "at_tab_trigger", "operator": "equal", "operand": true, "match_all": true }
    			//{ "key": "preceding_text", "operator": "regex_contains", "operand": "\\<(?i:a|b)\\>$", "match_all": true } // workaround
    		]
    	}

    I’m guessing I could hack around it at the scripting level, but it seems like something that’d be relatively easy to add and the smallest change to the system to get tab working as expected. I’m currently working around it by hard coding my nested snippets as shown above but that’s obviously not ideal. Kudos to Jon for allowing the expansion system to work with non-tab characters (I like ; for snippet expansion/jumping) without me having to hack around in the system.

    0 Likes

    #7

    I’m aware this is an extremely old discussion, but it’s a problem I’m still having and which I assume others are too. I’ve written a little plugin to make nested snippets work naturally with <tab> as the key for both inserting snippets and advancing fields. Basically it just tries to trigger a snippet to insert, and if nothing happens, then advances to the next field instead.

    complete_or_advance.py:

    import sublime
    import sublime_plugin
    
    
    # Attempt to trigger an exact completion (such as a snippet) and if no text was
    # subsequently inserted, then advance to the next field instead. In order to
    # only take precedence once already inside of a snippet, the key binding should
    # appear as follows:
    #   { "keys": ["tab"], "command": "complete_or_advance", "context":
    #     [
    #       { "key": "has_next_field", "operator": "equal", "operand": true }
    #     ]
    #   },
    
    
    def build_context(view):
      w = 3
      return [view.substr(sublime.Region(r.begin() - w, r.end() + w)) for r in 
        view.sel()]
    
    
    class CompleteOrAdvanceCommand(sublime_plugin.TextCommand):
      def run(self, edit):
        before = build_context(self.view)
        self.view.run_command("insert_best_completion", args = {"exact": True})
        after = build_context(self.view)
        if before == after:
          self.view.run_command("next_field")
    

    This might not be based on the most efficient way to test if a snippet has been inserted, but it’s the best I could figure out which worked. View.command_history() didn’t seem to register commands that have been run inside of a text command, so I couldn’t use it to test if the insert_best_completion did anything.

    So that it only applies once already within a snippet, you should add the command to your keymap as follows:

    { "keys": ["tab"], "command": "complete_or_advance", "context":
      [
        { "key": "has_next_field", "operator": "equal", "operand": true }
      ]
    },
    
    1 Like