|
11 | 11 |
|
12 | 12 | Requires: "pip install ptpython" which brings in pygments and prompt_toolkit
|
13 | 13 | """
|
| 14 | +import builtins |
14 | 15 | import functools
|
15 | 16 | import importlib
|
16 | 17 | import os
|
17 | 18 | import shutil
|
18 | 19 | import sys
|
19 | 20 | from typing import Any, Callable, Dict, Optional, Set
|
20 | 21 |
|
| 22 | +import ptpython.repl |
21 | 23 | from prompt_toolkit.completion import Completion, Completer
|
| 24 | +from prompt_toolkit.document import Document |
22 | 25 | from prompt_toolkit.formatted_text import PygmentsTokens
|
23 | 26 | from prompt_toolkit.formatted_text import fragment_list_to_text, to_formatted_text
|
24 | 27 | from ptpython import embed
|
25 | 28 | from ptpython.completer import DictionaryCompleter
|
26 |
| -from ptpython.repl import run_config |
| 29 | +from ptpython.repl import PythonRepl, run_config |
| 30 | +from ptpython.validator import PythonValidator |
27 | 31 | from pygments.lexers.c_cpp import CLexer
|
28 | 32 |
|
29 | 33 | import drgn
|
30 | 34 | import drgn.cli
|
| 35 | +from drgn.cli import all_commands, Command, help_command |
31 | 36 |
|
32 | 37 |
|
33 | 38 | class DummyForRepr:
|
@@ -124,10 +129,40 @@ def _format_result_output(result: object):
|
124 | 129 | repl.completer = ReorderDrgnObjectCompleter(repl.completer)
|
125 | 130 |
|
126 | 131 |
|
| 132 | +class DrgnPythonValidator(PythonValidator): |
| 133 | + |
| 134 | + def validate(self, document: Document) -> None: |
| 135 | + if document.text.lstrip().startswith("."): |
| 136 | + return |
| 137 | + return super().validate(document) |
| 138 | + |
| 139 | + |
| 140 | +class DrgnPythonRepl(PythonRepl): |
| 141 | + |
| 142 | + def __init__(self, *args: Any, **kwargs: Any): |
| 143 | + super().__init__(*args, **kwargs, _validator=DrgnPythonValidator()) |
| 144 | + |
| 145 | + def __run_command(self, line: str) -> object: |
| 146 | + cmd_name = line.split(maxsplit=1)[0][1:] |
| 147 | + if cmd_name not in self._commands: |
| 148 | + print(f"{cmd_name}: drgn command not found") |
| 149 | + return None |
| 150 | + cmd = self._commands[cmd_name] |
| 151 | + locals = self.get_locals() |
| 152 | + prog = locals["prog"] |
| 153 | + setattr(builtins, "_", cmd(prog, line, locals)) |
| 154 | + |
| 155 | + def eval(self, line: str) -> object: |
| 156 | + if line.lstrip().startswith('.'): |
| 157 | + return self.__run_command(line) |
| 158 | + return super().eval(line) |
| 159 | + |
| 160 | + |
127 | 161 | def run_interactive(
|
128 | 162 | prog: drgn.Program,
|
129 | 163 | banner_func: Optional[Callable[[str], str]] = None,
|
130 | 164 | globals_func: Optional[Callable[[Dict[str, Any]], Dict[str, Any]]] = None,
|
| 165 | + commands_func: Optional[Callable[[Dict[str, Command]], Dict[str, Command]]] = None, |
131 | 166 | quiet: bool = False,
|
132 | 167 | ) -> None:
|
133 | 168 | """
|
@@ -184,6 +219,12 @@ def run_interactive(
|
184 | 219 | if globals_func:
|
185 | 220 | init_globals = globals_func(init_globals)
|
186 | 221 |
|
| 222 | + commands = all_commands() |
| 223 | + if commands_func: |
| 224 | + commands = commands_func(commands) |
| 225 | + commands["help"] = help_command(commands) |
| 226 | + DrgnPythonRepl._commands = commands |
| 227 | + |
187 | 228 | old_path = list(sys.path)
|
188 | 229 | try:
|
189 | 230 | old_default_prog = drgn.get_default_prog()
|
@@ -212,6 +253,7 @@ def run_interactive(
|
212 | 253 |
|
213 | 254 |
|
214 | 255 | if __name__ == "__main__":
|
| 256 | + ptpython.repl.PythonRepl = DrgnPythonRepl |
215 | 257 | # Muck around with the internals of drgn: swap out run_interactive() with our
|
216 | 258 | # ptpython version, and then call main as if nothing happened.
|
217 | 259 | drgn.cli.run_interactive = run_interactive
|
|
0 commit comments