Skip to content

Commit 43223e1

Browse files
committed
inputrc for prompt-toolkit...
And put more configuration stuff in .config/trepan3k (not trepanpy)
1 parent c580cd3 commit 43223e1

5 files changed

Lines changed: 125 additions & 53 deletions

File tree

trepan/clifns.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# -*- coding: utf-8 -*-
2-
# Copyright (C) 2008-2009, 2013, 2023 Rocky Bernstein <rocky@gnu.org>
2+
# Copyright (C) 2008-2009, 2013, 2023-2024 Rocky Bernstein <rocky@gnu.org>
33
#
44
# This program is free software: you can redistribute it and/or modify
55
# it under the terms of the GNU General Public License as published by
@@ -17,6 +17,16 @@
1717
import os
1818
import os.path as osp
1919

20+
def default_configfile(base_filename: str) -> str:
21+
"""Return fully expanded configuration filename location for
22+
base_filename directory: ~/.config/trepan3k
23+
"""
24+
file_dir = osp.join(os.environ.get("HOME", "~"), ".config", "trepan3k")
25+
file_dir = path_expanduser_abs(file_dir)
26+
27+
if not osp.isdir(file_dir):
28+
os.makedirs(file_dir, mode=0o755)
29+
return osp.join(file_dir, base_filename)
2030

2131
# FIXME: do a better job of this. Live parsing?
2232
def is_ok_line_for_breakpoint(filename, lineno, errmsg_fn):
@@ -96,5 +106,4 @@ def path_expanduser_abs(filename):
96106
print("\nCan stop at line 1? ", ok)
97107
ok = is_ok_line_for_breakpoint(__file__, 2, sys.stdout.write)
98108
print("\nCan stop at line 2? ", ok)
99-
print(path_expanduser_abs("./.trepan3krc"))
100-
print(path_expanduser_abs("~/.trepan3krc"))
109+
print(path_expanduser_abs("./.trepan3k"))

trepan/inout/input.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,11 @@
1818
"""Debugger input possibly attached to a user or interactive. """
1919

2020
import io
21+
import os
22+
import os.path as osp
2123
import sys
2224

25+
from trepan.clifns import default_configfile
2326
from trepan.inout import base as Mbase
2427

2528
try:
@@ -31,6 +34,19 @@
3134
PromptSession = lambda history: None
3235
FileHistory = lambda history: None
3336
HTML = lambda string: string
37+
else:
38+
from trepan.inout.prompt_bindkeys import bindings, read_inputrc, read_init_file
39+
40+
USER_INPUTRC = os.environ.get(
41+
"TREPAN3K_INPUTRC", default_configfile("inputrc")
42+
)
43+
44+
read_inputrc(read_init_file, use_unicode=False)
45+
if osp.isfile(USER_INPUTRC):
46+
if os.access(USER_INPUTRC, os.R_OK):
47+
read_init_file(USER_INPUTRC)
48+
else:
49+
sys.stderr.write(f"Can't read user inputrc file {USER_INPUTRC}; skipping\n")
3450

3551

3652
class DebuggerUserInput(Mbase.DebuggerInputBase):
@@ -49,6 +65,7 @@ def __init__(self, inp=None, opts=dict()):
4965
editing_mode=prompt_editing_mode,
5066
enable_history_search=True,
5167
history=FileHistory(opts.get("histfile")),
68+
key_bindings=bindings,
5269
)
5370
self.input = self.session.input
5471
self.line_edit = True

trepan/inout/prompt_bindkeys.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#
2+
# Copyright (C) 2024 Rocky Bernstein <rocky@gnu.org>
3+
#
4+
# This program is free software: you can redistribute it and/or modify
5+
# it under the terms of the GNU General Public License as published by
6+
# the Free Software Foundation, either version 3 of the License, or
7+
# (at your option) any later version.
8+
#
9+
# This program is distributed in the hope that it will be useful,
10+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
# GNU General Public License for more details.
13+
#
14+
# You should have received a copy of the GNU General Public License
15+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
17+
"""
18+
Keyboard input binding routines for prompt_toolkit which are
19+
analogous to GNU Readlines' parse_and_bind().
20+
"""
21+
22+
# NOTE: this same code also exists in mathicsscript. Hopefully in the future
23+
# we will have a way to avoid the duplication.
24+
25+
26+
import pathlib
27+
from prompt_toolkit.key_binding import KeyBindings
28+
from typing import Callable
29+
30+
bindings = KeyBindings()
31+
32+
33+
def read_inputrc(read_init_file_fn: Callable, use_unicode: bool) -> None:
34+
"""
35+
Read GNU Readline style inputrc for prompt_toolkit
36+
"""
37+
# GNU Readline inputrc $include's paths are relative to itself,
38+
# so chdir to its directory before reading the file.
39+
parent_dir = pathlib.Path(__file__).parent.absolute()
40+
with parent_dir:
41+
inputrc = "inputrc-unicode" if use_unicode else "inputrc-no-unicode"
42+
try:
43+
read_init_file_fn(str(parent_dir / "data" / inputrc))
44+
except Exception:
45+
pass
46+
47+
48+
def read_init_file(path: str):
49+
def check_quoted(s: str):
50+
return s[0:1] == '"' and s[-1:] == '"'
51+
52+
def add_binding(alias_expand, replacement: str):
53+
def self_insert(event):
54+
event.current_buffer.insert_text(replacement)
55+
56+
bindings.add(*alias_expand)(self_insert)
57+
58+
for line_no, line in enumerate(open(path, "r").readlines()):
59+
line = line.strip()
60+
if not line or line.startswith("#"):
61+
continue
62+
fields = re.split(r"\s*: ", line)
63+
if len(fields) != 2:
64+
print(f"{line_no+1}: expecting 2 fields, got {len(fields)} in:\n{line}")
65+
continue
66+
alias, replacement = fields
67+
if not check_quoted(alias):
68+
print(f"{line_no+1}: expecting alias to be quoted, got {alias} in:\n{line}")
69+
alias = alias[1:-1]
70+
if not check_quoted(replacement):
71+
print(
72+
f"{line_no+1}: expecting replacement to be quoted, got {replacement} in:\n{line}"
73+
)
74+
continue
75+
replacement = replacement[1:-1]
76+
alias_expand = [
77+
c if c != "\x1b" else "escape" for c in list(alias.replace(r"\e", "\x1b"))
78+
]
79+
add_binding(alias_expand, replacement)
80+
pass

trepan/interfaces/user.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,16 @@
1818
"""Interface when communicating with the user in the same process as
1919
the debugged program."""
2020
import atexit
21-
import os.path as osp
2221

22+
from os import environ
23+
24+
from trepan.clifns import default_configfile
2325
from trepan.inout.input import DebuggerUserInput
2426
from trepan.inout.output import DebuggerUserOutput
25-
26-
# Our local modules
2727
from trepan.interface import TrepanInterface
2828

29-
histfile = osp.expanduser("~/.trepan3k_hist")
29+
histfile = environ.get("TREPAN3KHISTFILE", default_configfile("history"))
30+
3031
# is_pypy = '__pypy__' in sys.builtin_module_names
3132

3233
DEFAULT_USER_SETTINGS = {
@@ -46,7 +47,6 @@
4647
except ImportError:
4748
pass
4849

49-
5050
class UserInterface(TrepanInterface):
5151
"""Interface when communicating with the user in the same
5252
process as the debugged program."""
@@ -174,6 +174,7 @@ def readline(self, prompt=""):
174174

175175
# Demo
176176
if __name__ == "__main__":
177+
print(f"History file is {histfile}")
177178
intf = UserInterface()
178179
intf.errmsg("Houston, we have a problem here!")
179180
import sys

trepan/options.py

Lines changed: 10 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -16,41 +16,24 @@
1616

1717
import codecs
1818
import os
19-
import os.path as osp
2019
import sys
2120
from optparse import OptionParser
2221

2322
from pygments.styles import STYLE_MAP
2423

2524
import trepan.api
26-
from trepan.clifns import path_expanduser_abs
25+
from trepan.clifns import default_configfile
2726
from trepan.inout.output import DebuggerUserOutput
2827
from trepan.lib.file import readable
2928

3029
try:
3130
import prompt_toolkit # NOQA
32-
have_prompt_toolkit = True
3331
except ImportError:
3432
have_prompt_toolkit = False
33+
else:
34+
have_prompt_toolkit = True
3535

36-
try:
37-
import prompt_toolkit # NOQA
38-
have_gnu_readline = True
39-
except ImportError:
40-
have_gnu_readline = False
41-
42-
43-
def default_configfile(base_filename: str) -> str:
44-
"""Return fully expanded configuration filename location for
45-
base_filename. python2 and python3 debuggers share the same
46-
directory: ~/.config/trepan.py
47-
"""
48-
file_dir = osp.join(os.environ.get("HOME", "~"), ".config", "trepanpy")
49-
file_dir = path_expanduser_abs(file_dir)
50-
51-
if not osp.isdir(file_dir):
52-
os.makedirs(file_dir, mode=0o755)
53-
return osp.join(file_dir, base_filename)
36+
have_gnu_readline = False
5437

5538

5639
def add_startup_file(dbg_initfiles: list):
@@ -334,21 +317,6 @@ def process_options(pkg_version: str, sys_argv: str, option_list=None):
334317
)
335318

336319
readline = None
337-
if have_gnu_readline:
338-
optparser.add_option(
339-
"--gnu-readline",
340-
dest="use_gnu_readline",
341-
action="store_true",
342-
default=True,
343-
help="Try using GNU-Readline",
344-
)
345-
optparser.add_option(
346-
"--no-gnu-readline",
347-
dest="use_gnu_readline",
348-
action="store_false",
349-
default=True,
350-
help="Do not use GNU-Readline",
351-
)
352320
if have_prompt_toolkit:
353321
optparser.add_option(
354322
"--prompt-toolkit",
@@ -365,7 +333,6 @@ def process_options(pkg_version: str, sys_argv: str, option_list=None):
365333
help="Do not use prompt_toolkit",
366334
)
367335

368-
369336
# Set up to stop on the first non-option because that's the name
370337
# of the script to be debugged on arguments following that are
371338
# that scripts options that should be left untouched. We would
@@ -386,21 +353,19 @@ def process_options(pkg_version: str, sys_argv: str, option_list=None):
386353
)
387354
opts.edit_mode = "emacs"
388355

389-
390-
if hasattr(opts, "use_prompt_toolkit") and opts.use_prompt_toolkit:
391-
readline = "prompt_toolkit"
392-
elif hasattr(opts, "use_gnu_readline") and opts.use_gnu_readline:
393-
readline = "gnu_readline"
394-
else:
395-
readline = None
356+
readline = (
357+
"prompt_toolkit"
358+
if hasattr(opts, "use_prompt_toolkit") and opts.use_prompt_toolkit
359+
else "readline"
360+
)
396361

397362
dbg_opts = {
398363
"from_ipython": opts.from_ipython,
399364
"interface_opts": {
400365
"readline": readline,
401366
"debugger_name": "trepan3k",
402367
"edit_mode": opts.edit_mode,
403-
}
368+
},
404369
}
405370

406371
# Handle debugger startup command files: --nx (-n) and --command.

0 commit comments

Comments
 (0)