input_handler class decorator to automatically add and create simple input handlers
I was just thinking that most (text) input handlers are fairly simple and provide mostly static values for their (abstract) methods, which makes creation of a separate class rather decoupled from the command's not as transparent as it needs to.
Furthermore, implementing the command's input seems like busy work most of the time and things become especially complicated once you start using multiple handlers and want them to chain using next_input.
I believe a decorator in ArgumentParser.add_argument style could make this API more streamlined while still allowing for the complex case.
API example:
@input_handler("param", kind="text", placeholder="Replace me", validate=lambda _: True)
@input_handler("param2", kind="list", items=list(range(10)))
@input_handler(Param3InputHandler) # name *can* be determined from handler's `name()`
class TestCommand(sublime_plugin.WindowCommand):
def run(self, explicit_param, param, param2, param3, opt_param=None):
pass
Questions
-
Technically, input handlers don't have access to the command instance, the window/view or any of the previous parameters. Especially for the complex case, I'm unsure how to provide this information since you'd use custom handlers mostly in those situations when that information is needed. How to handle this? Just pass
window/viewand a dict of all args to the handler's__init__? -
The same issue also surfaces when the list items you want to provide are dynamic.
-
For a similar reason, I don't think
confirm,cancel, ordescriptionmake much sense to be supplied in the decorator short-hand form. -
Use the
kindparam to distinguish, decide based on anitemsparameter, or use two decorators usetext_input_handlerandlist_input_handler?
If you have some complex input handler examples, I believe trying to wrap those into such a generator as an example would help with designing the API for this.
I've played around with this recently. The stumbling block for me is that I can't really think of any especially complex examples out in the wild. (Maybe this is a chicken-and-egg thing, and more people would write input handlers if they were easier to work with.)
So I wrote up a quick example implementation of something like PackageResourceViewer's Open Resource command:
class InputTestCommand(sublime_plugin.WindowCommand):
def run(self, path):
content = sublime.load_resource(path)
new_view(
self.window,
name=path,
content=content,
syntax=sublime.find_syntax_for_file(path),
read_only=True,
scratch=True,
)
@fancy_input
def input(self, args):
path = ResourcePath('Packages')
while not path.exists():
path_str = yield GenericListInputHandler(
name='path',
items=[
sublime.ListInputItem(child.name, str(child))
for child in path.children()
]
)
path = ResourcePath(path_str)
It's all done with generators behind the scenes, of course. How does something like this look?
A recursive input handler surely sounds like a complex use case to me and a generator sounds like a good candidate as well (I love generators). Specifying the name of the input handler's parameter as an argument also makes sense and matches my suggestion of using decorators to generate a stub implementation for input.
Would be interested to try this out myself.