Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suggestion: use stderr for I/O, or make it configurable #47

Open
semicontinuity opened this issue Dec 12, 2020 · 3 comments
Open

Suggestion: use stderr for I/O, or make it configurable #47

semicontinuity opened this issue Dec 12, 2020 · 3 comments
Labels

Comments

@semicontinuity
Copy link

semicontinuity commented Dec 12, 2020

Hello, here is a suggestion: it would be nice if picotui used stderr for I/O, and not stdin+stdout.
Why? that would free stdio and stdout for other application-specific things: the app can get its input from stdin and write result to stdout, unix-way, and it would allow to use picotui-base app in unix pipes:
echo "input-data" | picotui-app | consumer

I'm doing exactly that in my picotui-based app, and it works great.
Here's the code I had to add to make it work (thanks to python, no need to modify picotui code, can just patch it):

from picotui.screen import Screen

#################################################################################
# Start patching picotui to use STDERR (FD 2)
#################################################################################
FD_IN = 2
FD_OUT = 2


import os


def wr(*args):
    s = args[-1]
    # TODO: When Python is 3.5, update this to use only bytes
    if isinstance(s, str):
        s = bytes(s, "utf-8")
    os.write(FD_OUT, s)


from picotui.basewidget import Widget
from picotui.defs import KEYMAP as _KEYMAP


def get_input(self):
    if self.kbuf:
        key = self.kbuf[0:1]
        self.kbuf = self.kbuf[1:]
    else:
        key = os.read(FD_IN, 32)
        if key[0] != 0x1b:
            key = key.decode()
            self.kbuf = key[1:].encode()
            key = key[0:1].encode()
    key = _KEYMAP.get(key, key)

    if isinstance(key, bytes) and key.startswith(b"\x1b[M") and len(key) == 6:
        row = key[5] - 33
        col = key[4] - 33
        return [col, row]

    return key


def screen_size(*args):
    import select
    wr(b"\x1b[18t")
    res = select.select([FD_IN], [], [], 0.2)[0]
    if not res:
        return (80, 24)
    resp = os.read(FD_IN, 32)
    assert resp.startswith(b"\x1b[8;") and resp[-1:] == b"t"
    vals = resp[:-1].split(b";")
    return (int(vals[2]), int(vals[1]))


def init_tty(*args):
    import tty, termios
    global ttyattr
    ttyattr = termios.tcgetattr(FD_IN)
    tty.setraw(FD_IN)


def deinit_tty(*args):
    import termios
    termios.tcsetattr(FD_IN, termios.TCSANOW, ttyattr)


def patch_picotui():
    Screen.wr = wr
    Screen.init_tty = init_tty
    Screen.deinit_tty = deinit_tty
    Screen.screen_size = screen_size
    Widget.get_input = get_input

#################################################################################
# End patching picotui
#################################################################################

.. that's it, just introduced constants instead of hard-coded FD 0 and 1

@pfalcon
Copy link
Owner

pfalcon commented Dec 12, 2020

Thanks for the feedback and suggestion. I'll keep it in mind, but arguments for doing it like that would be that it's customary to do it at all. Do other TUI applications do it like that? Does curses lib do it like that by default?

As a random quick test, I tried Midnight Commander with:

mc >/dev/null

That doesn't produce any output, so it clearly does TUI operations on stdout.

@semicontinuity
Copy link
Author

I agree, by very nature TUI must interact with console. Most likely, there are no conventions on FD usage for TUI.
In shell, FD 0 and 1 can participate in pipe, and 2 cannot be piped, and supposed to be attached to "debug console".
Anyway, if you would just introduce constants FD_IN=0 and FD_OUT=1, so that it behaves the same way and give the possibility to modify them and attach to different FD - that would be really nice

@pfalcon
Copy link
Owner

pfalcon commented Dec 15, 2020

Anyway, if you would just introduce constants FD_IN=0 and FD_OUT=1

I'll keep that in mind. I have a queue of things I'd like to do, including to that part of the code, so it may need to wait some time, but I'm not against it in principle.

@pfalcon pfalcon changed the title Suggestion: use stderr for I/O, or meake it configurable Suggestion: use stderr for I/O, or make it configurable Jan 31, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants