diff --git a/CHANGELOG b/CHANGELOG index 98acbea18..ee4e00835 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -20,9 +20,8 @@ Changes: are two different keys that can be handled independently. This is a big backward-incompatibility, because the `Enter` key is `ControlM`, not `ControlJ`. So, now that we stopped translating \r into \n, it could be that - custom key bindings for `Enter` don't work anymore. Make sure to use - `Keys.Enter` instead of `Keys.ControlJ` in the key bindings for handling the - `Enter` key. + custom key bindings for `Enter` don't work anymore. Make sure to bind + `Keys.Enter` instead of `Keys.ControlJ` for handling the `Enter` key. - The `CommandLineInterface` and the `Application` classes are merged. First, `CommandLineInterface` contained all the I/O objects (like the input, output @@ -30,22 +29,25 @@ Changes: no practical reason to keep this separation. (`CommandLineInterface` was mostly a proxy to `Application`.) - A consequence is that all almost code which received a + A consequence is that all almost code which used to received a `CommandLineInterface`, will now receive an `Application`. Usually, where we had an attribute `cli`, we'll now have an attribute `app`. * `CLIFilter` will now take an `Application`, so it was renamed to `AppFilter`. * `to_cli_filter` was renamed to `to_app_filter`. + (For backwards-compatibility, we have aliases to the old names, whenever + possible.) + - The `buffers` dictionary (`CommandLineInterface.buffers`) does not exist anymore. Further, `buffers` was a `BufferMapping` that keeps track of which buffer has the focus. This significantly reduces the freedom for creating complex applications. We wanted to move toward a layout that can be defined - as a collection of and relation between user widgets. A user widget does not - need to have a `Buffer` underneath and any widget should be focussable. + as a (hierarchical) collection of user widgets. A user widget does not need + to have a `Buffer` underneath and any widget should be focusable. - * `layout.focus.Focus` was introduced and `Application.focussed_control` was - added. + * `layout.Layout` was introduced to contain the root layout widget and keep + track of the focus. - The key bindings were refactored. It became much more flexible to combine sets of key bindings. @@ -63,6 +65,15 @@ Changes: * `KeyBindingManager` has been removed completely. * `input_processor` was renamed to `key_processor`. + Further: + + * The `Key` class does not exist anymore. Every key is a string and it's + considered fine to use string literals in the key bindings. This is more + readible, but we still have run-time validation. The `Keys` enum still + exist (for backwards-compatibility, but also to have an overview of which + keys are supported.) + * 'enter' and 'tab' are key aliases for 'c-m' and 'c-i'. + - User controls can define key bindings, which are active when the user control is focussed. @@ -76,7 +87,7 @@ Changes: (TOP/CENTER/BOTTOM/JUSTIFY) or (LEFT/CENTER/RIGHT/JUSTIFY). * `Float` now takes `allow_cover_cursor` and `attach_to_window` arguments. * `Window` got an `Align` argument. This can be used for the alignment of the - content. `TokenListControl` does not have an allignment argument anymore. + content. `TokenListControl` does not have an alignment argument anymore. * `Window` got a `token` and `get_token` argument. This is used to fill the window's background using the given `Token`. That way, a window can for instance be given a background color. @@ -90,17 +101,31 @@ Changes: * `BufferControl` now takes a `input_processor` as argument. (Singular instead of plural). If you want to combine multiple, they have to be merged - together using `merge_input_processors`. + together using `merge_input_processors`. (Similar to `merge_key_bindings`.) * The `InputProcessor` class has been refactored. The `apply_transformation` - method should now accept a `TransformationInput` object. + method should now takes a `TransformationInput` object as input. * The text `(reverse-i-search)` is now displayed through a processor. (See the `shortcuts` module for an example of the usage.) +- `widgets` and `dialogs` modules: + + * A small collection of widgets was added. These are more complex collections + of user controls that are ready to embed in a layout. A `shortcuts.dialogs` + module was added with shortcuts for displaying input, confirmation and + message dialogs. + + * Every class that exposes a ``__pt_container__`` method (which is supposed + to return a ``Container`` instance) is considered a widget. The + ``to_container`` shortcut will call this method in situations where a + ``Container`` object is expected. This avoids inheritance from other + ``Container`` types, but also having to unpack the container object from + the widget, in case we would have used composition. + - Changes related to `shortcuts.prompt`: - * There is now a class `Prompt` that which has a method `prompt`. Both the + * There is now a class `Prompt` which also has a method `prompt`. Both the class and the method take about the same arguments. This can be used to create a session. Every `prompt` call of the same instance will reuse all the arguments given to the class itself. This can be used for instance to @@ -111,6 +136,7 @@ Changes: * The `prompt` function now takes an `extra_key_bindings` argument instead of `key_bindings_registry`. This should only contain the additional bindings. + (The default bindings are always included.) - Changes to the event loops: @@ -123,9 +149,9 @@ Changes: event loop until the `Future` is set and returns that result. * The asyncio adaptors (like the asyncio event loop integration) now require - Python 3.5. + Python 3.5. (We use the async/await syntax internally.) - * The `Input` and `Output` classes has some changes. (Not really important.) + * The `Input` and `Output` classes have some changes. (Not really important.) - Changes to the `filters` module: @@ -153,14 +179,9 @@ Changes: * `to_container` and `to_window` utilities were added. - * Added a small collection of widgets. These are more complex collections of - user controls that are ready to embed in a layout. - **** - `run_sub_applications` returns a future instead of taking a callback. -- Key() object does not exist anymore. Keys are all strings. - - Deprecated diff --git a/prompt_toolkit/application.py b/prompt_toolkit/application.py index 0aaac313b..a3234d449 100644 --- a/prompt_toolkit/application.py +++ b/prompt_toolkit/application.py @@ -457,17 +457,19 @@ def read_from_input(): def auto_flush_input(): # Flush input after timeout. + # (Used for flushing the enter key.) time.sleep(self.input_timeout) loop.call_from_executor(flush_input) def flush_input(): - # Get keys, and feed to key processor. - keys = self.input.flush_keys() - self.key_processor.feed_multiple(keys) - self.key_processor.process_keys() - - if self.input.closed: - f.set_exception(EOFError) + if not self.is_done: + # Get keys, and feed to key processor. + keys = self.input.flush_keys() + self.key_processor.feed_multiple(keys) + self.key_processor.process_keys() + + if self.input.closed: + f.set_exception(EOFError) # Set event loop handlers. previous_input, previous_cb = loop.set_input(self.input, read_from_input) diff --git a/prompt_toolkit/layout/containers.py b/prompt_toolkit/layout/containers.py index c082570d9..2dc9dde92 100644 --- a/prompt_toolkit/layout/containers.py +++ b/prompt_toolkit/layout/containers.py @@ -1038,9 +1038,9 @@ class Window(Container): if `cursorcolumn` is True. :param align: alignment of content. :param token: If given, apply this token to all of the cells in this window. - :param char: Character to be used for filling the background. :param get_token: Callable that takes an `Application` and returns the token to be applied to all the cells in this window. + :param char: Character to be used for filling the background. :param transparent: When `False`, first erase everything underneath. (This is mainly useful if this Window is displayed inside a `Float`.) (when `char` or `get_char` is geven, it will never be transparant diff --git a/prompt_toolkit/layout/widgets/base.py b/prompt_toolkit/layout/widgets/base.py index acab5e839..5dd673b10 100644 --- a/prompt_toolkit/layout/widgets/base.py +++ b/prompt_toolkit/layout/widgets/base.py @@ -85,7 +85,7 @@ def __init__(self, text='', multiline=True, password=False, focussable=True, wrap_lines=True, width=None, height=None, dont_extend_height=False, dont_extend_width=False, - scrollbar=False, token=Token, loop=None): + scrollbar=False, token=Token, loop=None, _label=False): assert isinstance(text, six.text_type) assert loop is None or isinstance(loop, EventLoop) @@ -117,13 +117,17 @@ def __init__(self, text='', multiline=True, password=False, height = D.exact(1) margins = [] + if not _label: + # (In case of a Label, we don't want to apply the TextArea token.) + token = Token.TextArea | token + self.window = Window( height=height, width=width, dont_extend_height=dont_extend_height, dont_extend_width=dont_extend_width, content=self.control, - token=Token.TextArea|token, + token=token, wrap_lines=wrap_lines, right_margins=margins) @@ -158,7 +162,6 @@ def __init__(self, text, token=Token, width=None, loop=None, longest_line = max(get_cwidth(line) for line in text.splitlines()) width = D(preferred=longest_line) - self.text_area = TextArea( text=text, width=width, @@ -166,10 +169,19 @@ def __init__(self, text, token=Token, width=None, loop=None, focussable=False, dont_extend_height=dont_extend_height, dont_extend_width=dont_extend_width, - loop=loop) + loop=loop, + _label=True) loop = loop or get_event_loop() + @property + def text(self): + return self.text_area.buffer.text + + @text.setter + def text(self, value): + self.text_area.buffer.text = value + def __pt_container__(self): return self.text_area @@ -534,7 +546,7 @@ def percentage(self): def percentage(self, value): assert isinstance(value, int) self._percentage = value - self.label.buffer.text = '{}%'.format(value) + self.label.text = '{}%'.format(value) def __pt_container__(self): return self.container diff --git a/prompt_toolkit/shortcuts/prompt.py b/prompt_toolkit/shortcuts/prompt.py index e8737b07a..769c9d378 100644 --- a/prompt_toolkit/shortcuts/prompt.py +++ b/prompt_toolkit/shortcuts/prompt.py @@ -253,6 +253,7 @@ def __init__( assert extra_key_bindings is None or isinstance(extra_key_bindings, KeyBindingsBase) # Defaults. + self._close_loop = loop is None loop = loop or create_event_loop() output = output or create_output(true_color) @@ -687,7 +688,8 @@ def _get_title(self): return self.get_title() def close(self): - return#self.loop.close() + if self._close_loop: + self.loop.close() def prompt(*a, **kw): diff --git a/tests/test_cli.py b/tests/test_cli.py index b108ba2ce..9fc3ddd6a 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -53,6 +53,7 @@ def _feed_cli_with_input( finally: inp.close() + p.close() def test_simple_text_input():