Skip to content

Commit 13aafb2

Browse files
authored
Merge pull request #10007 from jimingham/custom-completer-stable
Add the ability to define custom completers to the parsed_cmd template
2 parents c87bc75 + d98dba3 commit 13aafb2

File tree

15 files changed

+844
-82
lines changed

15 files changed

+844
-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/bindings/python/static-binding/LLDBWrapPython.cpp

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

5642+
StructuredData::DictionarySP
5643+
lldb_private::python::SWIGBridge::LLDBSwigPythonHandleArgumentCompletionForScriptedCommand(PyObject *implementor,
5644+
std::vector<llvm::StringRef> &args_vec, size_t args_pos, size_t pos_in_arg) {
5645+
5646+
PyErr_Cleaner py_err_cleaner(true);
5647+
5648+
PythonObject self(PyRefType::Borrowed, implementor);
5649+
auto pfunc = self.ResolveName<PythonCallable>("handle_argument_completion");
5650+
// If this isn't implemented, return an empty dict to signal falling back to default completion:
5651+
if (!pfunc.IsAllocated())
5652+
return {};
5653+
5654+
PythonList args_list(PyInitialValue::Empty);
5655+
for (auto elem : args_vec)
5656+
args_list.AppendItem(PythonString(elem));
5657+
5658+
PythonObject result = pfunc(args_list, PythonInteger(args_pos), PythonInteger(pos_in_arg));
5659+
// Returning None means do the ordinary completion
5660+
if (result.IsNone())
5661+
return {};
5662+
5663+
// Convert the return dictionary to a DictionarySP.
5664+
StructuredData::ObjectSP result_obj_sp = result.CreateStructuredObject();
5665+
if (!result_obj_sp)
5666+
return {};
5667+
5668+
StructuredData::DictionarySP dict_sp(new StructuredData::Dictionary(result_obj_sp));
5669+
if (dict_sp->GetType() == lldb::eStructuredDataTypeInvalid)
5670+
return {};
5671+
return dict_sp;
5672+
}
5673+
5674+
StructuredData::DictionarySP
5675+
lldb_private::python::SWIGBridge::LLDBSwigPythonHandleOptionArgumentCompletionForScriptedCommand(PyObject *implementor,
5676+
llvm::StringRef &long_option, size_t pos_in_arg) {
5677+
5678+
PyErr_Cleaner py_err_cleaner(true);
5679+
5680+
PythonObject self(PyRefType::Borrowed, implementor);
5681+
auto pfunc = self.ResolveName<PythonCallable>("handle_option_argument_completion");
5682+
// If this isn't implemented, return an empty dict to signal falling back to default completion:
5683+
if (!pfunc.IsAllocated())
5684+
return {};
5685+
5686+
PythonObject result = pfunc(PythonString(long_option), PythonInteger(pos_in_arg));
5687+
// Returning None means do the ordinary completion
5688+
if (result.IsNone())
5689+
return {};
5690+
5691+
// Returning a boolean:
5692+
// True means the completion was handled, but there were no completions
5693+
// False means that the completion was not handled, again, do the ordinary completion:
5694+
if (result.GetObjectType() == PyObjectType::Boolean) {
5695+
if (!result.IsTrue())
5696+
return {};
5697+
// Make up a completion dictionary with the right element:
5698+
StructuredData::DictionarySP dict_sp(new StructuredData::Dictionary());
5699+
dict_sp->AddBooleanItem("no-completion", true);
5700+
return dict_sp;
5701+
}
5702+
5703+
5704+
// Convert the return dictionary to a DictionarySP.
5705+
StructuredData::ObjectSP result_obj_sp = result.CreateStructuredObject();
5706+
if (!result_obj_sp)
5707+
return {};
5708+
5709+
StructuredData::DictionarySP dict_sp(new StructuredData::Dictionary(result_obj_sp));
5710+
if (dict_sp->GetType() == lldb::eStructuredDataTypeInvalid)
5711+
return {};
5712+
return dict_sp;
5713+
}
5714+
56425715
#include "lldb/Interpreter/CommandReturnObject.h"
56435716

56445717
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

0 commit comments

Comments
 (0)