Skip to content

Commit e5c1c75

Browse files
committed
Add the ability to define custom completers to the parsed_cmd template. (llvm#109062)
If your arguments or option values are of a type that naturally uses one of our common completion mechanisms, you will get completion for free. But if you have your own custom values or if you want to do fancy things like have `break set -s foo.dylib -n ba<TAB>` only complete on symbols in foo.dylib, you can use this new mechanism to achieve that. (cherry picked from commit 04b443e)
1 parent 77c0016 commit e5c1c75

File tree

14 files changed

+771
-82
lines changed

14 files changed

+771
-82
lines changed

lldb/bindings/python/python-wrapper.swig

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -752,6 +752,79 @@ lldb_private::python::SWIGBridge::LLDBSwigPythonGetRepeatCommandForScriptedComma
752752
return result.Str().GetString().str();
753753
}
754754

755+
StructuredData::DictionarySP
756+
lldb_private::python::SWIGBridge::LLDBSwigPythonHandleArgumentCompletionForScriptedCommand(PyObject *implementor,
757+
std::vector<llvm::StringRef> &args_vec, size_t args_pos, size_t pos_in_arg) {
758+
759+
PyErr_Cleaner py_err_cleaner(true);
760+
761+
PythonObject self(PyRefType::Borrowed, implementor);
762+
auto pfunc = self.ResolveName<PythonCallable>("handle_argument_completion");
763+
// If this isn't implemented, return an empty dict to signal falling back to default completion:
764+
if (!pfunc.IsAllocated())
765+
return {};
766+
767+
PythonList args_list(PyInitialValue::Empty);
768+
for (auto elem : args_vec)
769+
args_list.AppendItem(PythonString(elem));
770+
771+
PythonObject result = pfunc(args_list, PythonInteger(args_pos), PythonInteger(pos_in_arg));
772+
// Returning None means do the ordinary completion
773+
if (result.IsNone())
774+
return {};
775+
776+
// Convert the return dictionary to a DictionarySP.
777+
StructuredData::ObjectSP result_obj_sp = result.CreateStructuredObject();
778+
if (!result_obj_sp)
779+
return {};
780+
781+
StructuredData::DictionarySP dict_sp(new StructuredData::Dictionary(result_obj_sp));
782+
if (dict_sp->GetType() == lldb::eStructuredDataTypeInvalid)
783+
return {};
784+
return dict_sp;
785+
}
786+
787+
StructuredData::DictionarySP
788+
lldb_private::python::SWIGBridge::LLDBSwigPythonHandleOptionArgumentCompletionForScriptedCommand(PyObject *implementor,
789+
llvm::StringRef &long_option, size_t pos_in_arg) {
790+
791+
PyErr_Cleaner py_err_cleaner(true);
792+
793+
PythonObject self(PyRefType::Borrowed, implementor);
794+
auto pfunc = self.ResolveName<PythonCallable>("handle_option_argument_completion");
795+
// If this isn't implemented, return an empty dict to signal falling back to default completion:
796+
if (!pfunc.IsAllocated())
797+
return {};
798+
799+
PythonObject result = pfunc(PythonString(long_option), PythonInteger(pos_in_arg));
800+
// Returning None means do the ordinary completion
801+
if (result.IsNone())
802+
return {};
803+
804+
// Returning a boolean:
805+
// True means the completion was handled, but there were no completions
806+
// False means that the completion was not handled, again, do the ordinary completion:
807+
if (result.GetObjectType() == PyObjectType::Boolean) {
808+
if (!result.IsTrue())
809+
return {};
810+
// Make up a completion dictionary with the right element:
811+
StructuredData::DictionarySP dict_sp(new StructuredData::Dictionary());
812+
dict_sp->AddBooleanItem("no-completion", true);
813+
return dict_sp;
814+
}
815+
816+
817+
// Convert the return dictionary to a DictionarySP.
818+
StructuredData::ObjectSP result_obj_sp = result.CreateStructuredObject();
819+
if (!result_obj_sp)
820+
return {};
821+
822+
StructuredData::DictionarySP dict_sp(new StructuredData::Dictionary(result_obj_sp));
823+
if (dict_sp->GetType() == lldb::eStructuredDataTypeInvalid)
824+
return {};
825+
return dict_sp;
826+
}
827+
755828
#include "lldb/Interpreter/CommandReturnObject.h"
756829

757830
bool lldb_private::python::SWIGBridge::LLDBSwigPythonCallParsedCommandObject(

lldb/docs/use/python-reference.rst

Lines changed: 179 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -551,7 +551,7 @@ command definition form can't do the right thing.
551551
Since lldb 3.7, Python commands can also be implemented by means of a class
552552
which should implement the following interface:
553553

554-
::
554+
.. code-block:: python
555555
556556
class CommandObjectType:
557557
def __init__(self, debugger, internal_dict):
@@ -580,20 +580,193 @@ which should implement the following interface:
580580
As a convenience, you can treat the result object as a Python file object, and
581581
say
582582
583-
::
583+
.. code-block:: python
584584
585585
print >>result, "my command does lots of cool stuff"
586586
587587
SBCommandReturnObject and SBStream both support this file-like behavior by
588588
providing write() and flush() calls at the Python layer.
589589
590+
The commands that are added using this class definition are what lldb calls
591+
"raw" commands. The command interpreter doesn't attempt to parse the command,
592+
doesn't handle option values, neither generating help for them, or their
593+
completion. Raw commands are useful when the arguments passed to the command
594+
are unstructured, and having to protect them against lldb command parsing would
595+
be onerous. For instance, "expr" is a raw command.
596+
597+
You can also add scripted commands that implement the "parsed command", where
598+
the options and their types are specified, as well as the argument and argument
599+
types. These commands look and act like the majority of lldb commands, and you
600+
can also add custom completions for the options and/or the arguments if you have
601+
special needs.
602+
603+
The easiest way to do this is to derive your new command from the lldb.ParsedCommand
604+
class. That responds in the same way to the help & repeat command interfaces, and
605+
provides some convenience methods, and most importantly an LLDBOptionValueParser,
606+
accessed throught lldb.ParsedCommand.get_parser(). The parser is used to set
607+
your command definitions, and to retrieve option values in the __call__ method.
608+
609+
To set up the command definition, implement the ParsedCommand abstract method:
610+
611+
.. code-block:: python
612+
613+
def setup_command_definition(self):
614+
615+
This is called when your command is added to lldb. In this method you add the
616+
options and their types, the option help strings, etc. to the command using the API:
617+
618+
.. code-block:: python
619+
620+
def add_option(self, short_option, long_option, help, default,
621+
dest = None, required=False, groups = None,
622+
value_type=lldb.eArgTypeNone, completion_type=None,
623+
enum_values=None):
624+
"""
625+
short_option: one character, must be unique, not required
626+
long_option: no spaces, must be unique, required
627+
help: a usage string for this option, will print in the command help
628+
default: the initial value for this option (if it has a value)
629+
dest: the name of the property that gives you access to the value for
630+
this value. Defaults to the long option if not provided.
631+
required: if true, this option must be provided or the command will error out
632+
groups: Which "option groups" does this option belong to. This can either be
633+
a simple list (e.g. [1, 3, 4, 5]) or you can specify ranges by sublists:
634+
so [1, [3,5]] is the same as [1, 3, 4, 5].
635+
value_type: one of the lldb.eArgType enum values. Some of the common arg
636+
types also have default completers, which will be applied automatically.
637+
completion_type: currently these are values form the lldb.CompletionType enum. If
638+
you need custom completions, implement handle_option_argument_completion.
639+
enum_values: An array of duples: ["element_name", "element_help"]. If provided,
640+
only one of the enum elements is allowed. The value will be the
641+
element_name for the chosen enum element as a string.
642+
"""
643+
644+
Similarly, you can add argument types to the command:
645+
646+
.. code-block:: python
647+
648+
def make_argument_element(self, arg_type, repeat = "optional", groups = None):
649+
"""
650+
arg_type: The argument type, one of the lldb.eArgType enum values.
651+
repeat: Choose from the following options:
652+
"plain" - one value
653+
"optional" - zero or more values
654+
"plus" - one or more values
655+
groups: As with add_option.
656+
"""
657+
658+
Then implement the body of the command by defining:
659+
660+
.. code-block:: python
661+
662+
def __call__(self, debugger, args_array, exe_ctx, result):
663+
"""This is the command callback. The option values are
664+
provided by the 'dest' properties on the parser.
665+
666+
args_array: This is the list of arguments provided.
667+
exe_ctx: Gives the SBExecutionContext on which the
668+
command should operate.
669+
result: Any results of the command should be
670+
written into this SBCommandReturnObject.
671+
"""
672+
673+
This differs from the "raw" command's __call__ in that the arguments are already
674+
parsed into the args_array, and the option values are set in the parser, and
675+
can be accessed using their property name. The LLDBOptionValueParser class has
676+
a couple of other handy methods:
677+
678+
.. code-block:: python
679+
def was_set(self, long_option_name):
680+
681+
returns True if the option was specified on the command line.
682+
683+
.. code-block:: python
684+
685+
def dest_for_option(self, long_option_name):
686+
"""
687+
This will return the value of the dest variable you defined for opt_name.
688+
Mostly useful for handle_completion where you get passed the long option.
689+
"""
690+
691+
lldb will handle completing your option names, and all your enum values
692+
automatically. If your option or argument types have associated built-in completers,
693+
then lldb will also handle that completion for you. But if you have a need for
694+
custom completions, either in your arguments or option values, you can handle
695+
completion by hand as well. To handle completion of option value arguments,
696+
your lldb.ParsedCommand subclass should implement:
697+
698+
.. code-block:: python
699+
700+
def handle_option_argument_completion(self, long_option, cursor_pos):
701+
"""
702+
long_option: The long option name of the option whose value you are
703+
asked to complete.
704+
cursor_pos: The cursor position in the value for that option - which
705+
you can get from the option parser.
706+
"""
707+
708+
And to handle the completion of arguments:
709+
710+
.. code-block:: python
711+
712+
def handle_argument_completion(self, args, arg_pos, cursor_pos):
713+
"""
714+
args: A list of the arguments to the command
715+
arg_pos: An index into the args list of the argument with the cursor
716+
cursor_pos: The cursor position in the arg specified by arg_pos
717+
"""
718+
719+
When either of these API's is called, the command line will have been parsed up to
720+
the word containing the cursor, and any option values set in that part of the command
721+
string are available from the option value parser. That's useful for instance
722+
if you have a --shared-library option that would constrain the completions for,
723+
say, a symbol name option or argument.
724+
725+
The return value specifies what the completion options are. You have four
726+
choices:
727+
728+
- `True`: the completion was handled with no completions.
729+
730+
- `False`: the completion was not handled, forward it to the regular
731+
completion machinery.
732+
733+
- A dictionary with the key: "completion": there is one candidate,
734+
whose value is the value of the "completion" key. Optionally you can pass a
735+
"mode" key whose value is either "partial" or "complete". Return partial if
736+
the "completion" string is a prefix for all the completed value.
737+
738+
For instance, if the string you are completing is "Test" and the available completions are:
739+
"Test1", "Test11" and "Test111", you should return the dictionary:
740+
741+
.. code-block:: python
742+
743+
return {"completion": "Test1", "mode" : "partial"}
744+
745+
and then lldb will add the "1" at the curson and advance it after the added string,
746+
waiting for more completions. But if "Test1" is the only completion, return:
747+
748+
.. code-block:: python
749+
750+
{"completion": "Test1", "mode": "complete"}
751+
752+
and lldb will add "1 " at the cursor, indicating the command string is complete.
753+
754+
The default is "complete", you don't need to specify a "mode" in that case.
755+
756+
- A dictionary with the key: "values" whose value is a list of candidate completion
757+
strings. The command interpreter will present those strings as the available choices.
758+
You can optionally include a "descriptions" key, whose value is a parallel array
759+
of description strings, and the completion will show the description next to
760+
each completion.
761+
762+
590763
One other handy convenience when defining lldb command-line commands is the
591-
command command script import which will import a module specified by file
764+
command "command script import" which will import a module specified by file
592765
path, so you don't have to change your PYTHONPATH for temporary scripts. It
593766
also has another convenience that if your new script module has a function of
594767
the form:
595768

596-
::
769+
.. code-block python
597770
598771
def __lldb_init_module(debugger, internal_dict):
599772
# Command Initialization code goes here
@@ -609,7 +782,7 @@ creating scripts that can be run from the command line. However, for command
609782
line scripts, the debugger instance must be created manually. Sample code would
610783
look like:
611784

612-
::
785+
.. code-block:: python
613786
614787
if __name__ == '__main__':
615788
# Initialize the debugger before making any API calls.
@@ -632,7 +805,7 @@ look like:
632805
Now we can create a module called ls.py in the file ~/ls.py that will implement
633806
a function that can be used by LLDB's python command code:
634807

635-
::
808+
.. code-block:: python
636809
637810
#!/usr/bin/env python
638811

lldb/examples/python/cmdtemplate.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ def register_lldb_command(cls, debugger, module_name):
2626
)
2727

2828
def setup_command_definition(self):
29-
30-
self.ov_parser.add_option(
29+
ov_parser = self.get_parser()
30+
ov_parser.add_option(
3131
"i",
3232
"in-scope",
3333
help = "in_scope_only = True",
@@ -36,7 +36,7 @@ def setup_command_definition(self):
3636
default = True,
3737
)
3838

39-
self.ov_parser.add_option(
39+
ov_parser.add_option(
4040
"i",
4141
"in-scope",
4242
help = "in_scope_only = True",
@@ -45,7 +45,7 @@ def setup_command_definition(self):
4545
default=True,
4646
)
4747

48-
self.ov_parser.add_option(
48+
ov_parser.add_option(
4949
"a",
5050
"arguments",
5151
help = "arguments = True",
@@ -54,7 +54,7 @@ def setup_command_definition(self):
5454
default = True,
5555
)
5656

57-
self.ov_parser.add_option(
57+
ov_parser.add_option(
5858
"l",
5959
"locals",
6060
help = "locals = True",
@@ -63,7 +63,7 @@ def setup_command_definition(self):
6363
default = True,
6464
)
6565

66-
self.ov_parser.add_option(
66+
ov_parser.add_option(
6767
"s",
6868
"statics",
6969
help = "statics = True",
@@ -100,8 +100,9 @@ def __call__(self, debugger, command, exe_ctx, result):
100100
result.SetError("invalid frame")
101101
return
102102

103+
ov_parser = self.get_parser()
103104
variables_list = frame.GetVariables(
104-
self.ov_parser.arguments, self.ov_parser.locals, self.ov_parser.statics, self.ov_parser.inscope
105+
ov_parser.arguments, ov_parser.locals, ov_parser.statics, ov_parser.inscope
105106
)
106107
variables_count = variables_list.GetSize()
107108
if variables_count == 0:

0 commit comments

Comments
 (0)