make progress on rlcompleter, still broken
This commit is contained in:
parent
1b5a0289a8
commit
07a49bfaca
|
@ -232,7 +232,7 @@ helper to do tab completion of wormhole codes:
|
|||
```python
|
||||
from wormhole import create, rlcompleter_helper
|
||||
w = create(appid, relay_url, reactor)
|
||||
rlcompleter_helper("Wormhole code:", w.input_code())
|
||||
rlcompleter_helper("Wormhole code:", w.input_code(), reactor)
|
||||
d = w.when_code()
|
||||
```
|
||||
|
||||
|
|
|
@ -5,6 +5,9 @@ from attr.validators import provides
|
|||
from automat import MethodicalMachine
|
||||
from . import _interfaces
|
||||
|
||||
def first(outputs):
|
||||
return list(outputs)[0]
|
||||
|
||||
@attrs
|
||||
@implementer(_interfaces.ICode)
|
||||
class Code(object):
|
||||
|
@ -79,7 +82,7 @@ class Code(object):
|
|||
|
||||
S0_idle.upon(set_code, enter=S4_known, outputs=[do_set_code])
|
||||
S0_idle.upon(input_code, enter=S1_inputting_nameplate,
|
||||
outputs=[do_start_input])
|
||||
outputs=[do_start_input], collector=first)
|
||||
S1_inputting_nameplate.upon(got_nameplate, enter=S2_inputting_words,
|
||||
outputs=[do_middle_input])
|
||||
S2_inputting_words.upon(finished_input, enter=S4_known,
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
from __future__ import print_function, unicode_literals
|
||||
import sys
|
||||
import six
|
||||
from attr import attrs, attrib
|
||||
from twisted.internet.defer import inlineCallbacks, returnValue
|
||||
from twisted.internet.threads import deferToThread, blockingCallFromThread
|
||||
|
||||
@attrs
|
||||
class CodeInputter:
|
||||
class CodeInputter(object):
|
||||
_input_helper = attrib()
|
||||
_reactor = attrib()
|
||||
def __attrs_post_init__(self):
|
||||
|
@ -23,10 +24,14 @@ class CodeInputter:
|
|||
# completer exceptions are normally silently discarded, which
|
||||
# makes debugging challenging
|
||||
print("completer exception: %s" % e)
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
raise e
|
||||
|
||||
def completer(self, text, state):
|
||||
self.used_completion = True
|
||||
# debug
|
||||
#import readline
|
||||
#if state == 0:
|
||||
# print("", file=sys.stderr)
|
||||
#print("completer: '%s' %d '%d'" % (text, state,
|
||||
|
@ -68,10 +73,10 @@ class CodeInputter:
|
|||
#sys.stderr.flush()
|
||||
return self._matches[state]
|
||||
|
||||
def input_code_with_completion(prompt, input_helper, code_length):
|
||||
def input_code_with_completion(prompt, input_helper, reactor):
|
||||
try:
|
||||
import readline
|
||||
c = CodeInputter(input_helper)
|
||||
c = CodeInputter(input_helper, reactor)
|
||||
if readline.__doc__ and "libedit" in readline.__doc__:
|
||||
readline.parse_and_bind("bind ^I rl_complete")
|
||||
else:
|
||||
|
@ -89,12 +94,45 @@ def input_code_with_completion(prompt, input_helper, code_length):
|
|||
used_completion = c.used_completion if c else False
|
||||
return (code, used_completion)
|
||||
|
||||
def warn_readline():
|
||||
# When our process receives a SIGINT, Twisted's SIGINT handler will
|
||||
# stop the reactor and wait for all threads to terminate before the
|
||||
# process exits. However, if we were waiting for
|
||||
# input_code_with_completion() when SIGINT happened, the readline
|
||||
# thread will be blocked waiting for something on stdin. Trick the
|
||||
# user into satisfying the blocking read so we can exit.
|
||||
print("\nCommand interrupted: please press Return to quit",
|
||||
file=sys.stderr)
|
||||
|
||||
# Other potential approaches to this problem:
|
||||
# * hard-terminate our process with os._exit(1), but make sure the
|
||||
# tty gets reset to a normal mode ("cooked"?) first, so that the
|
||||
# next shell command the user types is echoed correctly
|
||||
# * track down the thread (t.p.threadable.getThreadID from inside the
|
||||
# thread), get a cffi binding to pthread_kill, deliver SIGINT to it
|
||||
# * allocate a pty pair (pty.openpty), replace sys.stdin with the
|
||||
# slave, build a pty bridge that copies bytes (and other PTY
|
||||
# things) from the real stdin to the master, then close the slave
|
||||
# at shutdown, so readline sees EOF
|
||||
# * write tab-completion and basic editing (TTY raw mode,
|
||||
# backspace-is-erase) without readline, probably with curses or
|
||||
# twisted.conch.insults
|
||||
# * write a separate program to get codes (maybe just "wormhole
|
||||
# --internal-get-code"), run it as a subprocess, let it inherit
|
||||
# stdin/stdout, send it SIGINT when we receive SIGINT ourselves. It
|
||||
# needs an RPC mechanism (over some extra file descriptors) to ask
|
||||
# us to fetch the current nameplate_id list.
|
||||
#
|
||||
# Note that hard-terminating our process with os.kill(os.getpid(),
|
||||
# signal.SIGKILL), or SIGTERM, doesn't seem to work: the thread
|
||||
# doesn't see the signal, and we must still wait for stdin to make
|
||||
# readline finish.
|
||||
|
||||
@inlineCallbacks
|
||||
def rlcompleter_helper(prompt, input_helper, reactor):
|
||||
def warn_readline():
|
||||
pass
|
||||
t = reactor.addSystemEventTrigger("before", "shutdown", warn_readline)
|
||||
res = yield deferToThread(input_code_with_completion, prompt, input_helper)
|
||||
res = yield deferToThread(input_code_with_completion, prompt, input_helper,
|
||||
reactor)
|
||||
(code, used_completion) = res
|
||||
reactor.removeSystemEventTrigger(t)
|
||||
returnValue(used_completion)
|
||||
|
|
|
@ -164,9 +164,13 @@ class TwistedReceiver:
|
|||
if code:
|
||||
w.set_code(code)
|
||||
else:
|
||||
raise NotImplemented
|
||||
yield w.input_code("Enter receive wormhole code: ", # TODO
|
||||
self.args.code_length)
|
||||
from .._rlcompleter import rlcompleter_helper
|
||||
used_completion = yield rlcompleter_helper("Enter receive wormhole code: ",
|
||||
w.input_code(),
|
||||
self._reactor)
|
||||
if not used_completion:
|
||||
print(" (note: you can use <Tab> to complete words)",
|
||||
file=self.args.stderr)
|
||||
yield w.when_code()
|
||||
|
||||
def _show_verifier(self, verifier):
|
||||
|
|
Loading…
Reference in New Issue
Block a user