def _get_asyncio_loop_cls(): # Inline import, to make sure the rest doesn't break on Python 2. (Where # asyncio is not available.) if is_windows(): from polymorph.deps.prompt_toolkit.eventloop.asyncio_win32 import Win32AsyncioEventLoop as AsyncioEventLoop else: from polymorph.deps.prompt_toolkit.eventloop.asyncio_posix import PosixAsyncioEventLoop as AsyncioEventLoop return AsyncioEventLoop
def height_is_known(self): """ True when the height from the cursor until the bottom of the terminal is known. (It's often nicer to draw bottom toolbars only if the height is known, in order to avoid flickering when the CPR response arrives.) """ return self.full_screen or self._min_available_height > 0 or \ is_windows() # On Windows, we don't have to wait for a CPR.
def create_input(stdin=None): stdin = stdin or sys.stdin if is_windows(): from .win32 import Win32Input return Win32Input(stdin) else: from .vt100 import Vt100Input return Vt100Input(stdin)
def create_event_loop(recognize_win32_paste=True): """ Create and return an :class:`~prompt_toolkit.eventloop.base.EventLoop` instance. """ if is_windows(): from .win32 import Win32EventLoop return Win32EventLoop(recognize_paste=recognize_win32_paste) else: from .posix import PosixEventLoop return PosixEventLoop()
def call_inputhook(self, input_is_ready_func, inputhook): """ Call the inputhook. (Called by a prompt-toolkit eventloop.) :param input_is_ready_func: A callable which returns True when there is input ready for the main event loop to process. This means that we should quit our input hook. This callable takes a boolean `wait`. Wen `True` this needs to be a blocking call which only returns when there is input ready. :param inputhook: This is a callable that runs the inputhook. This function should take this object (the `InputHookContext`) as input. """ assert callable(input_is_ready_func) assert callable(inputhook) self._input_is_ready = input_is_ready_func # Start thread that activates this pipe when there is input to process. def thread(): input_is_ready_func(wait=True) os.write(self._w, b'x') threading.Thread(target=thread).start() # Call inputhook. inputhook(self) # Flush the read end of the pipe. try: # Before calling 'os.read', call select.select. This is required # when the gevent monkey patch has been applied. 'os.read' is never # monkey patched and won't be cooperative, so that would block all # other select() calls otherwise. # See: http://www.gevent.org/gevent.os.html # Note: On Windows, this is apparently not an issue. # However, if we would ever want to add a select call, it # should use `windll.kernel32.WaitForMultipleObjects`, # because `select.select` can't wait for a pipe on Windows. if not is_windows(): select_fds([self._r], timeout=None) os.read(self._r, 1024) except OSError: # This happens when the window resizes and a SIGWINCH was received. # We get 'Error: [Errno 4] Interrupted system call' # Just ignore. pass self._input_is_ready = None
def request_absolute_cursor_position(self): """ Get current cursor position. For vt100: Do CPR request. (answer will arrive later.) For win32: Do API call. (Answer comes immediately.) """ # Only do this request when the cursor is at the top row. (after a # clear or reset). We will rely on that in `report_absolute_cursor_row`. assert self._cursor_pos.y == 0 # For Win32, we have an API call to get the number of rows below the # cursor. if is_windows(): self._min_available_height = self.output.get_rows_below_cursor_position( ) else: if self.full_screen: self._min_available_height = self.output.get_size().rows elif self.cpr_support == CPR_Support.NOT_SUPPORTED: return else: # Asks for a cursor position report (CPR). self._waiting_for_cpr_futures.append(Future()) self.output.ask_for_cpr() # If we don't know whether CPR is supported, test using timer. if self.cpr_support == CPR_Support.UNKNOWN: def timer(): time.sleep(self.CPR_TIMEOUT) # Not set in the meantime -> not supported. if self.cpr_support == CPR_Support.UNKNOWN: self.cpr_support = CPR_Support.NOT_SUPPORTED if self.cpr_not_supported_callback: # Make sure to call this callback in the main thread. get_event_loop().call_from_executor( self.cpr_not_supported_callback) t = threading.Thread(target=timer) t.daemon = True t.start()
def default(cls, term=''): """ If the user doesn't specify a color depth, use this as a default. """ if term in ('linux', 'eterm-color'): return cls.DEPTH_4_BIT # For now, always use 4 bit color on Windows 10 by default, even when # vt100 escape sequences with ENABLE_VIRTUAL_TERMINAL_PROCESSING are # supported. We don't have a reliable way yet to know whether our # console supports true color or only 4-bit. if is_windows() and 'PROMPT_TOOLKIT_COLOR_DEPTH' not in os.environ: return cls.DEPTH_4_BIT # Check the `PROMPT_TOOLKIT_COLOR_DEPTH` environment variable. if os.environ.get('PROMPT_TOOLKIT_COLOR_DEPTH') in cls._ALL: return os.environ['PROMPT_TOOLKIT_COLOR_DEPTH'] return cls.DEPTH_8_BIT
def _(event): """ Handling of mouse events for Windows. """ assert is_windows() # This key binding should only exist for Windows. # Parse data. event_type, x, y = event.data.split(';') x = int(x) y = int(y) # Make coordinates absolute to the visible part of the terminal. screen_buffer_info = event.app.renderer.output.get_win32_screen_buffer_info( ) rows_above_cursor = screen_buffer_info.dwCursorPosition.Y - event.app.renderer._cursor_pos.y y -= rows_above_cursor # Call the mouse event handler. handler = event.app.renderer.mouse_handlers.mouse_handlers[x, y] handler(MouseEvent(position=Point(x=x, y=y), event_type=event_type))
def reset(self, _scroll=False, leave_alternate_screen=True): # Reset position self._cursor_pos = Point(x=0, y=0) # Remember the last screen instance between renderers. This way, # we can create a `diff` between two screens and only output the # difference. It's also to remember the last height. (To show for # instance a toolbar at the bottom position.) self._last_screen = None self._last_size = None self._last_style = None # Default MouseHandlers. (Just empty.) self.mouse_handlers = MouseHandlers() #: Space from the top of the layout, until the bottom of the terminal. #: We don't know this until a `report_absolute_cursor_row` call. self._min_available_height = 0 # In case of Windows, also make sure to scroll to the current cursor # position. (Only when rendering the first time.) if is_windows() and _scroll: self.output.scroll_buffer_to_prompt() # Quit alternate screen. if self._in_alternate_screen and leave_alternate_screen: self.output.quit_alternate_screen() self._in_alternate_screen = False # Disable mouse support. if self._mouse_support_enabled: self.output.disable_mouse_support() self._mouse_support_enabled = False # Disable bracketed paste. if self._bracketed_paste_enabled: self.output.disable_bracketed_paste() self._bracketed_paste_enabled = False # Flush output. `disable_mouse_support` needs to write to stdout. self.output.flush()
def is_win_vt100_enabled(): """ Returns True when we're running Windows and VT100 escape sequences are supported. """ if not is_windows(): return False hconsole = windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE) # Get original console mode. original_mode = DWORD(0) windll.kernel32.GetConsoleMode(hconsole, byref(original_mode)) try: # Try to enable VT100 sequences. result = windll.kernel32.SetConsoleMode( hconsole, DWORD(ENABLE_PROCESSED_INPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING)) return result == 1 finally: windll.kernel32.SetConsoleMode(hconsole, original_mode)
def create_output(stdout=None): """ Return an :class:`~prompt_toolkit.output.Output` instance for the command line. :param stdout: The stdout object """ stdout = stdout or sys.__stdout__ if is_windows(): from .conemu import ConEmuOutput from .win32 import Win32Output from .windows10 import is_win_vt100_enabled, Windows10_Output if is_win_vt100_enabled(): return Windows10_Output(stdout) if is_conemu_ansi(): return ConEmuOutput(stdout) else: return Win32Output(stdout) else: from .vt100 import Vt100_Output return Vt100_Output.from_pty(stdout, term=get_term_environment_variable())