1""" 2Abstraction of CLI Input. 3""" 4from __future__ import unicode_literals 5 6from .utils import DummyContext, is_windows 7from abc import ABCMeta, abstractmethod 8from six import with_metaclass 9 10import io 11import os 12import sys 13 14if is_windows(): 15 from .terminal.win32_input import raw_mode, cooked_mode 16else: 17 from .terminal.vt100_input import raw_mode, cooked_mode 18 19__all__ = ( 20 'Input', 21 'StdinInput', 22 'PipeInput', 23) 24 25 26class Input(with_metaclass(ABCMeta, object)): 27 """ 28 Abstraction for any input. 29 30 An instance of this class can be given to the constructor of a 31 :class:`~prompt_toolkit.interface.CommandLineInterface` and will also be 32 passed to the :class:`~prompt_toolkit.eventloop.base.EventLoop`. 33 """ 34 @abstractmethod 35 def fileno(self): 36 """ 37 Fileno for putting this in an event loop. 38 """ 39 40 @abstractmethod 41 def read(self): 42 """ 43 Return text from the input. 44 """ 45 46 @abstractmethod 47 def raw_mode(self): 48 """ 49 Context manager that turns the input into raw mode. 50 """ 51 52 @abstractmethod 53 def cooked_mode(self): 54 """ 55 Context manager that turns the input into cooked mode. 56 """ 57 58 59class StdinInput(Input): 60 """ 61 Simple wrapper around stdin. 62 """ 63 def __init__(self, stdin=None): 64 self.stdin = stdin or sys.stdin 65 66 # The input object should be a TTY. 67 assert self.stdin.isatty() 68 69 # Test whether the given input object has a file descriptor. 70 # (Idle reports stdin to be a TTY, but fileno() is not implemented.) 71 try: 72 # This should not raise, but can return 0. 73 self.stdin.fileno() 74 except io.UnsupportedOperation: 75 if 'idlelib.run' in sys.modules: 76 raise io.UnsupportedOperation( 77 'Stdin is not a terminal. Running from Idle is not supported.') 78 else: 79 raise io.UnsupportedOperation('Stdin is not a terminal.') 80 81 def __repr__(self): 82 return 'StdinInput(stdin=%r)' % (self.stdin,) 83 84 def raw_mode(self): 85 return raw_mode(self.stdin.fileno()) 86 87 def cooked_mode(self): 88 return cooked_mode(self.stdin.fileno()) 89 90 def fileno(self): 91 return self.stdin.fileno() 92 93 def read(self): 94 return self.stdin.read() 95 96 97class PipeInput(Input): 98 """ 99 Input that is send through a pipe. 100 This is useful if we want to send the input programatically into the 101 interface, but still use the eventloop. 102 103 Usage:: 104 105 input = PipeInput() 106 input.send('inputdata') 107 """ 108 def __init__(self): 109 self._r, self._w = os.pipe() 110 111 def fileno(self): 112 return self._r 113 114 def read(self): 115 return os.read(self._r) 116 117 def send_text(self, data): 118 " Send text to the input. " 119 os.write(self._w, data.encode('utf-8')) 120 121 # Deprecated alias for `send_text`. 122 send = send_text 123 124 def raw_mode(self): 125 return DummyContext() 126 127 def cooked_mode(self): 128 return DummyContext() 129 130 def close(self): 131 " Close pipe fds. " 132 os.close(self._r) 133 os.close(self._w) 134 self._r = None 135 self._w = None 136