From fcfa89902a48fa230624bdcec6ca8991297bf9ef Mon Sep 17 00:00:00 2001 From: Paul Nameless Date: Sat, 4 Jul 2020 13:01:17 +0800 Subject: [PATCH 1/3] Allow to open current msg with custom cmd --- tg/controllers.py | 39 +++++++++++++++++++++++++++------------ tg/utils.py | 28 +++++++++++++++++++--------- tg/views.py | 2 +- 3 files changed, 47 insertions(+), 22 deletions(-) diff --git a/tg/controllers.py b/tg/controllers.py index a38901a..bb560b5 100644 --- a/tg/controllers.py +++ b/tg/controllers.py @@ -392,15 +392,14 @@ class Controller: chat = self.model.chats.chats[self.model.current_chat] return chat["permissions"]["can_send_messages"] - @bind(msg_handler, ["l", "^J"]) - def open_current_msg(self) -> None: - msg = MsgProxy(self.model.current_msg) + def _open_msg(self, msg: MsgProxy, cmd: str = None) -> None: if msg.is_text: with NamedTemporaryFile("w", suffix=".txt") as f: f.write(msg.text_content) f.flush() with suspend(self.view) as s: - s.open_file(f.name) + if err_msg := s.open_file(f.name, cmd): + self.present_error(err_msg) return path = msg.local_path @@ -412,7 +411,20 @@ class Controller: return self.tg.open_message_content(chat_id, msg.msg_id) with suspend(self.view) as s: - s.open_file(path) + if err_msg := s.open_file(path, cmd): + self.present_error(err_msg) + + @bind(msg_handler, ["!"]) + def open_msg_with_cmd(self) -> None: + """Open msg or file with cmd: less %s""" + msg = MsgProxy(self.model.current_msg) + if cmd := self.view.status.get_input(): + return self._open_msg(msg, cmd) + + @bind(msg_handler, ["l", "^J"]) + def open_current_msg(self) -> None: + msg = MsgProxy(self.model.current_msg) + self._open_msg(msg) @bind(msg_handler, ["e"]) def edit_msg(self) -> None: @@ -526,13 +538,16 @@ class Controller: self.resize() while True: - repeat_factor, keys = self.view.get_keys() - fun = handlers.get(keys, lambda *_: None) - res = fun(self, repeat_factor) # type: ignore - if res == "QUIT": - return res - elif res == "BACK": - return res + try: + repeat_factor, keys = self.view.get_keys() + fun = handlers.get(keys, lambda *_: None) + res = fun(self, repeat_factor) # type: ignore + if res == "QUIT": + return res + elif res == "BACK": + return res + except Exception: + log.exception("Error happend in key handle loop") def resize_handler(self, signum: int, frame: Any) -> None: curses.endwin() diff --git a/tg/utils.py b/tg/utils.py index 0e1f03e..f74eb9b 100644 --- a/tg/utils.py +++ b/tg/utils.py @@ -15,6 +15,7 @@ import sys from datetime import datetime from functools import lru_cache from logging.handlers import RotatingFileHandler +from subprocess import CompletedProcess from types import TracebackType from typing import Any, Optional, Tuple, Type @@ -71,10 +72,11 @@ def setup_log() -> None: logging.captureWarnings(True) -def get_file_handler(file_path: str, default: str = None) -> Optional[str]: +def get_file_handler(file_path: str) -> str: mtype, _ = mimetypes.guess_type(file_path) if not mtype: - return default + return config.DEFAULT_OPEN.format(file_path=shlex.quote(file_path)) + caps = mailcap.getcaps() handler, view = mailcap.findmatch(caps, mtype, filename=file_path) if not handler: @@ -181,17 +183,25 @@ class suspend: def __init__(self, view: Any) -> None: self.view = view - def call(self, cmd: str) -> None: - subprocess.call(cmd, shell=True) + def call(self, cmd: str) -> CompletedProcess: + return subprocess.run(cmd, shell=True, stderr=subprocess.PIPE) def run_with_input(self, cmd: str, text: str) -> None: subprocess.run(cmd, universal_newlines=True, input=text, shell=True) - def open_file(self, file_path: str) -> None: - cmd = get_file_handler(file_path) - if not cmd: - return - self.call(cmd) + def open_file(self, file_path: str, cmd: str = None) -> str: + if cmd: + try: + cmd = cmd % shlex.quote(file_path) + except TypeError: + return "command should contain <%s> which will be replaced by file path" + else: + cmd = get_file_handler(file_path) + + proc = self.call(cmd) + if proc.returncode: + return proc.stderr.decode() + return "" def __enter__(self) -> "suspend": for view in (self.view.chats, self.view.msgs, self.view.status): diff --git a/tg/views.py b/tg/views.py index 114c074..e9931e9 100644 --- a/tg/views.py +++ b/tg/views.py @@ -102,7 +102,7 @@ class StatusView: self.win.clear() if not msg: return - self.win.addstr(0, 0, msg[: self.w]) + self.win.addstr(0, 0, msg.replace("\n", " ")[: self.w]) self._refresh() def get_input(self, msg: str = "") -> str: From af7f1ee2026a7dd4d37841fdc331415bcf185fdd Mon Sep 17 00:00:00 2001 From: Paul Nameless Date: Sat, 4 Jul 2020 13:23:16 +0800 Subject: [PATCH 2/3] Update README key bindings --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f615e9b..da23bb3 100644 --- a/README.md +++ b/README.md @@ -230,3 +230,4 @@ For navigation arrow keys also can be used. - `]`: next chat - `[`: prev chat - `?`: show help +- `!`: open msg with custom cmd From 453cdbcc45022d2de9090068d0c0427a1a642c76 Mon Sep 17 00:00:00 2001 From: Paul Nameless Date: Sat, 4 Jul 2020 14:14:05 +0800 Subject: [PATCH 3/3] Improve logging (add filename) and add help string for open_current_msg --- tg/controllers.py | 1 + tg/utils.py | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tg/controllers.py b/tg/controllers.py index bb560b5..14dbcf1 100644 --- a/tg/controllers.py +++ b/tg/controllers.py @@ -423,6 +423,7 @@ class Controller: @bind(msg_handler, ["l", "^J"]) def open_current_msg(self) -> None: + """Open msg or file with cmd in mailcap""" msg = MsgProxy(self.model.current_msg) self._open_msg(msg) diff --git a/tg/utils.py b/tg/utils.py index f74eb9b..82277e5 100644 --- a/tg/utils.py +++ b/tg/utils.py @@ -64,7 +64,7 @@ def setup_log() -> None: handlers.append(handler) logging.basicConfig( - format="%(levelname)-8s [%(asctime)s] %(name)s %(message)s", + format="%(levelname)s [%(asctime)s] %(filename)s:%(lineno)s - %(funcName)s | %(message)s", handlers=handlers, ) logging.getLogger().setLevel(config.LOG_LEVEL) @@ -200,7 +200,9 @@ class suspend: proc = self.call(cmd) if proc.returncode: - return proc.stderr.decode() + stderr = proc.stderr.decode() + log.error("Error happened executing <%s>:\n%s", cmd, stderr) + return stderr return "" def __enter__(self) -> "suspend":