The ApplicationCommand
, WindowCommand
and TextCommand
classes all have an internal method named run_()
, which is the one that Sublime invokes internally. Part of the implementation of that method is calling the run()
method that is the “usual” entry point for the command.
Since you mentioned looking in sublime_plugin.py
, for reference purposes here’s what the current internal implementation of ApplicationCommand
is (but all of them have similar code):
class ApplicationCommand(Command):
def run_(self, edit_token, args):
args = self.filter_args(args)
try:
if args:
return self.run(**args)
else:
return self.run()
except (TypeError) as e:
if 'required positional argument' in str(e):
if sublime_api.can_accept_input(self.name(), args):
sublime.active_window().run_command(
'show_overlay',
{
'overlay': 'command_palette',
'command': self.name(),
'args': args
}
)
return
raise
def run(self):
pass
If you trace through the code, you can see that the implementation tries to invoke run()
with the arguments that it was given, but if a TypeError
exception is thrown that indicates that a missing argument was provided, that’s what triggers the input handling code.
Note also that it invokes the command from inside that point with the same args
that it called run()
with. Since we know that it only got that far because an argument was missing, we can also infer that input()
is being called with the arguments provided to run when it was executed and not all arguments that it expects, including default values.
Or, TL;DR: input()
is only invoked with the arguments that run()
got, and since you did not provide the argument pattern
to run()
, it’s not given to input()
either.
As such the easiest solution in your case is to not provide a default value for pattern
in run()
and instead add it to the entry in the command palette.
Redesigns of the code to not have default arguments aside, with additional code you can introspect the run()
method to see what it’s default arguments would have been, then apply to that the arguments that were actually provided to come up with what you’re expecting; a full dictionary of all arguments to the command, filled out with known defaults.
Here’s an example of that, although I’m not a Python master so there is probably a better way to achieve the same effect (and runtime introspection may or may not be a good thing to do, etc).
import sublime
import sublime_plugin
import inspect
def _get_cmd_defaults(cmd_class, received=None):
params = inspect.signature(cmd_class.run).parameters
defaults = {p: params[p].default for p in params
if params[p].default != inspect._empty}
if received:
defaults.update(received)
return defaults
class BaseFileInputHandler(sublime_plugin.ListInputHandler):
def __init__(self, pattern):
self.pattern = pattern
def list_items(self):
return sublime.find_resources(self.pattern)
class NewEditSettingsCommand(sublime_plugin.WindowCommand):
def input(self, args):
args = _get_cmd_defaults(self.__class__, args)
if "base_file" not in args:
return BaseFileInputHandler(args["pattern"])
return None
def run(self, base_file, user_file=None, default=None, pattern="*.sublime-settings"):
print("base_file: %s" % base_file)
print("user_file: %s" % user_file)
print("default: %s" % default)
print("pattern: %s" % pattern)