Skip to content

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

Description

@semicontinuity

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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions