Here’s another method that you can use to get this to work in a more seamless manner and without anything else third party installed. This method still leaves a bit to be desired as a general purpose solution though (see last paragraph), although it could be tweaked further.
First, here is a different plugin, which is a modification of the one that @rwols wrote above (all props to him for the core logic):
import sublime
import sublime_plugin
class InsertHeaderCommand(sublime_plugin.TextCommand):
def run(self, edit, trigger):
rulers = self.view.settings().get("rulers", [])
maxlength = min(rulers) if rulers else 80
# Get the caret location and the whole line the caret is on
caret = self.view.sel()[0]
line = self.view.line(caret.begin())
# Find the region that the trigger text is contained in
t_pos = self.view.find(trigger, line.begin(), sublime.LITERAL)
# Everything from the end of the trigger position to the caret
# position is the text to put into the header
v_text = self.view.substr(sublime.Region(t_pos.end(), caret.begin()))
# Calculate the dash length; we subtract one extra because in the
# replacement text below we force a space between the text and the
# dash line
dashlength = maxlength - len(v_text) - len(trigger) - 1
if dashlength < 0:
return sublime.status_message("Line too long to insert header")
string = "{}{} {}\n* $0\n*/".format(trigger, v_text,
"-" * dashlength)
# Erase from the start of the trigger all the way to the cursor
# to make way, the insert the snippet
self.view.erase(edit, t_pos.cover(caret))
self.view.run_command("insert_snippet", {"contents": string})
With that in place, we then add this key binding:
{
"keys": ["tab"], "command": "insert_header",
"args": {
"trigger": "/**"
},
"context": [
{ "key": "selector", "operator": "equal", "operand": "(source.c, source.c++) & comment"},
{ "key": "preceding_text", "operator": "regex_contains", "operand": "/\\*\\*"},
{ "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
{ "key": "num_selections", "operator": "equal", "operand": 1}
]
},
Now you can enter /**
followed by some text, press Tab and the “snippet” expands out in a more natural manner:

What this does is first implement a command that presupposes that there is only a single caret and no selection, and that somewhere on the line the cursor is currently on there is some text whose value is given by the argument trigger
that appears before the cursor.
The command then finds where on the current line the first instance of the trigger
text is. Everything from that point forward is the text of the header, and erases both parts and inserts a snippet with a dynamically calculated dashed line.
The key binding contains contexts that ensure that all of the preconditions on the command are met, partly so that the command doesn’t have to be smarter and do more checks but also because stealing the Tab key is something you should only do in very specific instances.
To this end, something important to keep in mind is that without that first context that is constraining the locations the expansion can happen in (here in a C or C++ file while inside of a comment) this may trigger in cases where you don’t expect it to.
The downside of this that makes it not great for a general purpose solution is that the key binding needs a regex_contains
that includes the trigger text, and the command also needs to be told what the trigger
is, so you have to modify both of them.