trigger tab completion for python batch process bu

2019-07-24 18:49发布

问题:

Background: I have a python program that imports and uses the readline module to build a homemade command line interface. I have a second python program (built around bottle, a web micro-framework) that acts as a front-end for that CLI. The second python program opens a pipe-like interface to the first, essentially passing user input and CLI output back and forth between the two.

Problem: In the outer wrapper program (the web interface), whenever the end-user presses the TAB key (or any other key that I bind the readline completer function), that key is inserted into the CLI's stdin without firing the readline completer function. I need this to trigger readline's command completion function instead, as normally occurs during an interactive CLI session.

Possible Solution #1: Is there some way to send the TAB key to a subprocess' stdin, so that a batch usage works the same as an interactive usage?

Possible Solution #2: Or, if there was some way to trigger the entire completion process manually (including matches generation and display), I could insert and scan for a special text sequence, like "<TAB_KEY_HERE>", firing the possible completion matches display function manually. (I wrote the completer function, which generates the possible matches, so all I really need is access to readline's function to display the possible matches.)

Possible Solution #3: I guess, if I cannot access readline's matches-display function, the last option is to rewrite readline's built-in display-completion function, so I can call it directly. :(

Is there a better solution? Any suggestions on following the paths presented by any of the above solutions? I am stuck on #1 and #2, and I'm trying to avoid #3.

Thanks!

回答1:

Solution #1 proved to be a workable approach. The key was to not connect the web socket directly to the CLI app. Apparently, readline was falling back into some simpler mode, which filtered out all TAB's, since it was not connected to a real PTY/TTY. (I may not be remembering this exactly right. Many cobwebs have formed.) Instead, a PTY/TTY pair needed to be opened and inserted in between the CLI app and web-sockets app, which tricked the CLI app into thinking it was connected to a real keyboard-based terminal, like so:

import pty
masterPTY, slaveTTY = pty.openpty()
appHandle = subprocess.Popen(
    ['/bin/python', 'myapp.py'],
    shell=False,
    stdin=slaveTTY,
    stdout=slaveTTY,
    stderr=slaveTTY,
    )
...
while True
    # read output from CLI app
    output = os.read(masterPTY, 1024)
    ...
    # write output to CLI app
    while input_data:
        chars_written = os.write(masterPTY, input_data)
        input_data = input_data[chars_written:]
    ...
appHandle.terminate()
os.close(masterPTY)
os.close(slaveTTY)

HTH someone else. :)

See this answer to a related question for more background:

https://stackoverflow.com/a/14565848/538418