Skip to content

Commit

Permalink
inputrc for prompt-toolkit...
Browse files Browse the repository at this point in the history
And put more configuration stuff in .config/trepan3k (not trepanpy)
  • Loading branch information
rocky committed Nov 11, 2024
1 parent c580cd3 commit 43223e1
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 53 deletions.
15 changes: 12 additions & 3 deletions trepan/clifns.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2008-2009, 2013, 2023 Rocky Bernstein <[email protected]>
# Copyright (C) 2008-2009, 2013, 2023-2024 Rocky Bernstein <[email protected]>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
Expand All @@ -17,6 +17,16 @@
import os
import os.path as osp

def default_configfile(base_filename: str) -> str:
"""Return fully expanded configuration filename location for
base_filename directory: ~/.config/trepan3k
"""
file_dir = osp.join(os.environ.get("HOME", "~"), ".config", "trepan3k")
file_dir = path_expanduser_abs(file_dir)

if not osp.isdir(file_dir):
os.makedirs(file_dir, mode=0o755)
return osp.join(file_dir, base_filename)

# FIXME: do a better job of this. Live parsing?
def is_ok_line_for_breakpoint(filename, lineno, errmsg_fn):
Expand Down Expand Up @@ -96,5 +106,4 @@ def path_expanduser_abs(filename):
print("\nCan stop at line 1? ", ok)
ok = is_ok_line_for_breakpoint(__file__, 2, sys.stdout.write)
print("\nCan stop at line 2? ", ok)
print(path_expanduser_abs("./.trepan3krc"))
print(path_expanduser_abs("~/.trepan3krc"))
print(path_expanduser_abs("./.trepan3k"))
17 changes: 17 additions & 0 deletions trepan/inout/input.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@
"""Debugger input possibly attached to a user or interactive. """

import io
import os
import os.path as osp
import sys

from trepan.clifns import default_configfile
from trepan.inout import base as Mbase

try:
Expand All @@ -31,6 +34,19 @@
PromptSession = lambda history: None
FileHistory = lambda history: None
HTML = lambda string: string
else:
from trepan.inout.prompt_bindkeys import bindings, read_inputrc, read_init_file

USER_INPUTRC = os.environ.get(
"TREPAN3K_INPUTRC", default_configfile("inputrc")
)

read_inputrc(read_init_file, use_unicode=False)
if osp.isfile(USER_INPUTRC):
if os.access(USER_INPUTRC, os.R_OK):
read_init_file(USER_INPUTRC)
else:
sys.stderr.write(f"Can't read user inputrc file {USER_INPUTRC}; skipping\n")


class DebuggerUserInput(Mbase.DebuggerInputBase):
Expand All @@ -49,6 +65,7 @@ def __init__(self, inp=None, opts=dict()):
editing_mode=prompt_editing_mode,
enable_history_search=True,
history=FileHistory(opts.get("histfile")),
key_bindings=bindings,
)
self.input = self.session.input
self.line_edit = True
Expand Down
80 changes: 80 additions & 0 deletions trepan/inout/prompt_bindkeys.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#
# Copyright (C) 2024 Rocky Bernstein <[email protected]>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

"""
Keyboard input binding routines for prompt_toolkit which are
analogous to GNU Readlines' parse_and_bind().
"""

# NOTE: this same code also exists in mathicsscript. Hopefully in the future
# we will have a way to avoid the duplication.


import pathlib
from prompt_toolkit.key_binding import KeyBindings
from typing import Callable

bindings = KeyBindings()


def read_inputrc(read_init_file_fn: Callable, use_unicode: bool) -> None:
"""
Read GNU Readline style inputrc for prompt_toolkit
"""
# GNU Readline inputrc $include's paths are relative to itself,
# so chdir to its directory before reading the file.
parent_dir = pathlib.Path(__file__).parent.absolute()
with parent_dir:
inputrc = "inputrc-unicode" if use_unicode else "inputrc-no-unicode"
try:
read_init_file_fn(str(parent_dir / "data" / inputrc))
except Exception:
pass


def read_init_file(path: str):
def check_quoted(s: str):
return s[0:1] == '"' and s[-1:] == '"'

def add_binding(alias_expand, replacement: str):
def self_insert(event):
event.current_buffer.insert_text(replacement)

bindings.add(*alias_expand)(self_insert)

for line_no, line in enumerate(open(path, "r").readlines()):
line = line.strip()
if not line or line.startswith("#"):
continue
fields = re.split(r"\s*: ", line)
if len(fields) != 2:
print(f"{line_no+1}: expecting 2 fields, got {len(fields)} in:\n{line}")
continue
alias, replacement = fields
if not check_quoted(alias):
print(f"{line_no+1}: expecting alias to be quoted, got {alias} in:\n{line}")
alias = alias[1:-1]
if not check_quoted(replacement):
print(
f"{line_no+1}: expecting replacement to be quoted, got {replacement} in:\n{line}"
)
continue
replacement = replacement[1:-1]
alias_expand = [
c if c != "\x1b" else "escape" for c in list(alias.replace(r"\e", "\x1b"))
]
add_binding(alias_expand, replacement)
pass
11 changes: 6 additions & 5 deletions trepan/interfaces/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,16 @@
"""Interface when communicating with the user in the same process as
the debugged program."""
import atexit
import os.path as osp

from os import environ

from trepan.clifns import default_configfile
from trepan.inout.input import DebuggerUserInput
from trepan.inout.output import DebuggerUserOutput

# Our local modules
from trepan.interface import TrepanInterface

histfile = osp.expanduser("~/.trepan3k_hist")
histfile = environ.get("TREPAN3KHISTFILE", default_configfile("history"))

# is_pypy = '__pypy__' in sys.builtin_module_names

DEFAULT_USER_SETTINGS = {
Expand All @@ -46,7 +47,6 @@
except ImportError:
pass


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

# Demo
if __name__ == "__main__":
print(f"History file is {histfile}")
intf = UserInterface()
intf.errmsg("Houston, we have a problem here!")
import sys
Expand Down
55 changes: 10 additions & 45 deletions trepan/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,41 +16,24 @@

import codecs
import os
import os.path as osp
import sys
from optparse import OptionParser

from pygments.styles import STYLE_MAP

import trepan.api
from trepan.clifns import path_expanduser_abs
from trepan.clifns import default_configfile
from trepan.inout.output import DebuggerUserOutput
from trepan.lib.file import readable

try:
import prompt_toolkit # NOQA
have_prompt_toolkit = True
except ImportError:
have_prompt_toolkit = False
else:
have_prompt_toolkit = True

try:
import prompt_toolkit # NOQA
have_gnu_readline = True
except ImportError:
have_gnu_readline = False


def default_configfile(base_filename: str) -> str:
"""Return fully expanded configuration filename location for
base_filename. python2 and python3 debuggers share the same
directory: ~/.config/trepan.py
"""
file_dir = osp.join(os.environ.get("HOME", "~"), ".config", "trepanpy")
file_dir = path_expanduser_abs(file_dir)

if not osp.isdir(file_dir):
os.makedirs(file_dir, mode=0o755)
return osp.join(file_dir, base_filename)
have_gnu_readline = False


def add_startup_file(dbg_initfiles: list):
Expand Down Expand Up @@ -334,21 +317,6 @@ def process_options(pkg_version: str, sys_argv: str, option_list=None):
)

readline = None
if have_gnu_readline:
optparser.add_option(
"--gnu-readline",
dest="use_gnu_readline",
action="store_true",
default=True,
help="Try using GNU-Readline",
)
optparser.add_option(
"--no-gnu-readline",
dest="use_gnu_readline",
action="store_false",
default=True,
help="Do not use GNU-Readline",
)
if have_prompt_toolkit:
optparser.add_option(
"--prompt-toolkit",
Expand All @@ -365,7 +333,6 @@ def process_options(pkg_version: str, sys_argv: str, option_list=None):
help="Do not use prompt_toolkit",
)


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


if hasattr(opts, "use_prompt_toolkit") and opts.use_prompt_toolkit:
readline = "prompt_toolkit"
elif hasattr(opts, "use_gnu_readline") and opts.use_gnu_readline:
readline = "gnu_readline"
else:
readline = None
readline = (
"prompt_toolkit"
if hasattr(opts, "use_prompt_toolkit") and opts.use_prompt_toolkit
else "readline"
)

dbg_opts = {
"from_ipython": opts.from_ipython,
"interface_opts": {
"readline": readline,
"debugger_name": "trepan3k",
"edit_mode": opts.edit_mode,
}
},
}

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

0 comments on commit 43223e1

Please sign in to comment.