From d93775ee30189514c55a88bc6d1d4ef702b1b450 Mon Sep 17 00:00:00 2001 From: Christophe Dufaza Date: Mon, 12 Jun 2023 07:53:52 +0200 Subject: [PATCH] [rfc-dtsh 27/29] rich: session: rich devicetree shell session Rich interactive devicetree shell session. Extend the base session with a few rich TUI elements and support for SVG and HTML command output redirection formats. Signed-off-by: Christophe Dufaza --- scripts/dts/dtsh/src/dtsh/rich/session.py | 119 ++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 scripts/dts/dtsh/src/dtsh/rich/session.py diff --git a/scripts/dts/dtsh/src/dtsh/rich/session.py b/scripts/dts/dtsh/src/dtsh/rich/session.py new file mode 100644 index 000000000000000..4ea48f3f8d8576f --- /dev/null +++ b/scripts/dts/dtsh/src/dtsh/rich/session.py @@ -0,0 +1,119 @@ +# Copyright (c) 2023 Christophe Dufaza +# +# SPDX-License-Identifier: Apache-2.0 + +"""Rich interactive devicetree shell session. + +Extend the base session with a few rich TUI elements +and support for SVG and HTML command output redirection formats. +""" + + +from dtsh.shell import ( + DtSh, + DtShError, + DtShCommandNotFoundError, + DtShUsageError, + DtShCommandError, +) +from dtsh.session import DtShSession +from dtsh.io import DtShOutput, DtShRedirection + +from dtsh.rich.io import DtShRichVT, DtShRichOutputFile +from dtsh.rich.autocomp import DtShRichAutocomp +from dtsh.rich.theme import DtShTheme +from dtsh.rich.text import TextUtil + + +class DtShRichSession(DtShSession): + """Rich interactive devicetree shell session.""" + + def __init__(self, sh: DtSh) -> None: + """Initialize rich session. + + Extend the base session with a few rich TUI elements + and and support for SVG and HTML command output redirection formats. + + Initialized with: + + - a rich VT based on Textualize's rich.Console (DtShRichVT) + - a rich auto-completion display hook (DtShRichAutocomp) + + Args: + sh: The session's shell. + """ + super().__init__(sh, DtShRichVT(), DtShRichAutocomp(sh)) + + def open_redir2(self, redir2: DtShRedirection) -> DtShOutput: + """Open rich redirection output stream. + + This redirection supports SVG and HTML exports. + + Overrides DtShSession.pre_input_hook(). + """ + try: + return DtShRichOutputFile(redir2.path) + except IOError as e: + raise DtShError( + f"output redirection error: {e.filename}: {e.strerror}" + ) from e + + def on_cmd_not_found_error(self, e: DtShCommandNotFoundError) -> None: + """Called when the user's asked for an unknown command. + + Overrides DtShSession.pre_input_hook(). + """ + self._vt.write( + TextUtil.mk_text("command not found: ").join( + ( + TextUtil.mk_text("dtsh: "), + TextUtil.mk_text(e.name, DtShTheme.STYLE_ERROR), + ) + ) + ) + + def on_cmd_usage_error(self, e: DtShUsageError) -> None: + """Called when the user's misused a command. + + Overrides DtShSession.pre_input_hook(). + """ + self._vt.write( + TextUtil.mk_text(": ").join( + ( + TextUtil.mk_text(e.cmd.name), + TextUtil.mk_text(e.msg, DtShTheme.STYLE_ERROR), + ) + ) + ) + + def on_cmd_failed_error(self, e: DtShCommandError) -> None: + """Called when the last command execution has failed. + + Overrides DtShSession.pre_input_hook(). + """ + self._vt.write( + TextUtil.mk_text(": ").join( + ( + TextUtil.mk_text(e.cmd.name), + TextUtil.mk_text(e.msg, DtShTheme.STYLE_ERROR), + ) + ) + ) + + def on_error(self, e: DtShError) -> None: + """Called when a less specific error occurs. + + Overrides DtShSession.pre_input_hook(). + """ + self._vt.write("dtsh:", TextUtil.mk_text(e.msg, DtShTheme.STYLE_ERROR)) + + def pre_exit_hook(self, status: int) -> None: + """Hook called when the user terminates the session. + + Overrides DtShSession.pre_input_hook(). + """ + if status: + txt = TextUtil.mk_text("bye.", DtShTheme.STYLE_ERROR) + else: + txt = TextUtil.mk_text("bye.", DtShTheme.STYLE_DEFAULT) + self._vt.write(TextUtil.italic(txt))