diff options
author | Jonathan Slenders <jonathan@slenders.be> | 2017-11-22 21:23:37 +0100 |
---|---|---|
committer | Jonathan Slenders <jonathan@slenders.be> | 2017-11-22 22:09:33 +0100 |
commit | 1a1166828021dea13c80fa940cbd3c362f8427c1 (patch) | |
tree | baafdf8a3ac326bf90f4d5b2263efde4c7d6cdba /docs/pages | |
parent | ca0a33bfad1d82feb34b924302ae87e0ded79fcb (diff) |
More documentation for full screen applications.
Diffstat (limited to 'docs/pages')
-rw-r--r-- | docs/pages/asking_for_input.rst | 2 | ||||
-rw-r--r-- | docs/pages/full_screen_apps.rst | 348 | ||||
-rw-r--r-- | docs/pages/printing_text.rst | 1 | ||||
-rw-r--r-- | docs/pages/reference.rst | 64 |
4 files changed, 196 insertions, 219 deletions
diff --git a/docs/pages/asking_for_input.rst b/docs/pages/asking_for_input.rst index c04a6f69..d0bfa3f8 100644 --- a/docs/pages/asking_for_input.rst +++ b/docs/pages/asking_for_input.rst @@ -478,7 +478,7 @@ filters <filters>`.) Dynamically switch between Emacs and Vi mode ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The :class:`~prompt_toolkit.application.Application` has +The :class:`~prompt_toolkit.application.application.Application` has an ``editing_mode`` attribute. We can change the key bindings by changing this attribute from ``EditingMode.VI`` to ``EditingMode.EMACS``. diff --git a/docs/pages/full_screen_apps.rst b/docs/pages/full_screen_apps.rst index ebde8917..78b5ca25 100644 --- a/docs/pages/full_screen_apps.rst +++ b/docs/pages/full_screen_apps.rst @@ -19,170 +19,118 @@ them together. backwards-incompatible. The refactoring should probably be complete somewhere around half 2017. -A layered layout architecture ------------------------------ - -There are several ways to create a prompt_toolkit layout, depending on how -customizable you want things to be. In fact, there are several layers of -abstraction. - -- The most low-level way of creating a layout is by combining ``Container`` and - ``Control`` objects. - - Examples of ``Container`` objects are ``VSplit``, ``HSplit`` and - ``FloatContainer``. These containers that can split the layout in multiple - regions and can each contain multiple other containers. They can be combined - in any way to define the "shape" of the layout. - - The ``Window`` object is a special kind of container that can contain - ``Control`` object. The ``Control`` object is responsible for the actual - content. The ``Window`` object acts as an adaptor between the - ``Control`` and other containers, but it's also responsible for the scrolling - and line wrapping of the content. - - Examples of ``Control`` objects are ``BufferControl`` for showing the content - of an editable/scrollable buffer, and ``FormattedTextcontrol`` for showing - static text. - -- A higher level abstraction of building a layout is by using "widgets". A - widget is a reusable layout component that can contain multiple containers - and controls. It should have a ``__pt__container__`` function, which is - supposed to return the root container for this widget. - -- The highest level abstractions are in the ``shortcuts`` module. There we - don't have to think about the layout, controls and containers at all. This is - the simplest way to use prompt_toolkit, but is only meant for certain use - cases. - - -Running the application ------------------------ - -To run our final Full screen Application, we need three I/O objects, and -an :class:`~prompt_toolkit.application.Application` instance. These are passed -as arguments to :class:`~prompt_toolkit.interface.CommandLineInterface`. - -The three I/O objects are: - - - An :class:`~prompt_toolkit.eventloop.base.EventLoop` instance. This is - basically a while-true loop that waits for user input, and when it receives - something (like a key press), it will send that to the application. - - An :class:`~prompt_toolkit.input.Input` instance. This is an abstraction - on the input stream (stdin). - - An :class:`~prompt_toolkit.output.Output` instance. This is an - abstraction on the output stream, and is called by the renderer. - -The input and output objects are optional. However, the eventloop is always -required. - -We'll come back to what the :class:`~prompt_toolkit.application.Application` -instance is later. +A simple application +-------------------- -So, the only thing we actually need in order to run an application is the following: +Every prompt_toolkit application is an instance of an +:class:`~prompt_toolkit.application.application.Application` object. The +simplest example would look like this: .. code:: python - from prompt_toolkit.interface import CommandLineInterface - from prompt_toolkit.application import Application - from prompt_toolkit.shortcuts import create_eventloop - - loop = create_eventloop() - application = Application() - cli = CommandLineInterface(application=application, eventloop=loop) - # cli.run() - print('Exiting') - -.. note:: In the example above, we don't run the application yet, as otherwise - it will hang indefinitely waiting for a signal to exit the event loop. This - is why the `cli.run()` part is commented. - - (Actually, it would accept the `Enter` key by default. But that's only - because by default, a buffer called `DEFAULT_BUFFER` has the focus; its - :class:`~prompt_toolkit.buffer.AcceptAction` is configured to return the - result when accepting, and there is a default `Enter` key binding that - calls the :class:`~prompt_toolkit.buffer.AcceptAction` of the currently - focussed buffer. However, the content of the `DEFAULT_BUFFER` buffer is not - yet visible, so it's hard to see what's going on.) + from prompt_toolkit import Application -Let's now bind a keyboard shortcut to exit: - -Key bindings ------------- + app = Application() + app.run() -In order to react to user actions, we need to create a registry of keyboard -shortcuts to pass to our :class:`~prompt_toolkit.application.Application`. The -easiest way to do so, is to create a -:class:`~prompt_toolkit.key_binding.manager.KeyBindingManager`, and then attach -handlers to our desired keys. :class:`~prompt_toolkit.keys.Keys` contains a few -predefined keyboards shortcut that can be useful. - -To create a `registry`, we can simply instantiate a -:class:`~prompt_toolkit.key_binding.manager.KeyBindingManager` and take its -`registry` attribute: +This will display a dummy application that says "No layout specified. Press +ENTER to quit.". We are discussing full screen applications in this section, so +we may as well set the ``full_screen`` flag so that the application runs in +full screen mode (in the alternate screen buffer). .. code:: python - from prompt_toolkit.key_binding.manager import KeyBindingManager - manager = KeyBindingManager() - registry = manager.registry - -Update the `Application` constructor, and pass the registry as one of the -argument. + from prompt_toolkit import Application -.. code:: python + app = Application(full_screen=True) + app.run() - application = Application(key_bindings_registry=registry) +An application consists of several components. The most important are: -To register a new keyboard shortcut, we can use the -:meth:`~prompt_toolkit.key_binding.registry.Registry.add_binding` method as a -decorator of the key handler: +- I/O objects: the event loop, the input and output device. +- The layout: this defines the graphical structure of the application. For + instance, a text box on the left side, and a button on the right side. +- A style: this defines what colors and underline/bold/italic styles are used + everywhere. +- Key bindings. -.. code:: python +We will discuss all of these in more detail them below. - from prompt_toolkit.keys import Keys +Three I/O objects +----------------- - @registry.add_binding(Keys.ControlQ, eager=True) - def exit_(event): - """ - Pressing Ctrl-Q will exit the user interface. +An :class:`~prompt_toolkit.application.application.Application` instance requires three I/O +objects: - Setting a return value means: quit the event loop that drives the user - interface and return this value from the `CommandLineInterface.run()` call. - """ - event.cli.set_return_value(None) + - An :class:`~prompt_toolkit.eventloop.base.EventLoop` instance. This is + basically a while-true loop that waits for user input, and when it + receives something (like a key press), it will send that to the the + appropriate handler, like for instance, a key binding. + - An :class:`~prompt_toolkit.input.base.Input` instance. This is an abstraction + of the input stream (stdin). + - An :class:`~prompt_toolkit.output.base.Output` instance. This is an + abstraction of the output stream, and is called by the renderer. -In this particular example we use ``eager=True`` to trigger the callback as soon -as the shortcut `Ctrl-Q` is pressed. The callback is named ``exit_`` for clarity, -but it could have been named ``_`` (underscore) as well, because the we won't -refer to this name. +All of these three objects are optional, and a default value will be used when +they are absent. Usually, the default works fine. +The layout +---------- -Creating a layout ------------------ +A layered layout architecture +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -A `layout` is a composition of -:class:`~prompt_toolkit.layout.containers.Container` and -:class:`~prompt_toolkit.layout.controls.UIControl` that will describe the -disposition of various element on the user screen. +There are several ways to create a prompt_toolkit layout, depending on how +customizable you want things to be. In fact, there are several layers of +abstraction. -Various Layouts can refer to `Buffers` that have to be created and pass to the -application separately. This allow an application to have its layout changed, -without having to reconstruct buffers. You can imagine for example switching -from an horizontal to a vertical split panel layout and vice versa, +- The most low-level way of creating a layout is by combining + :class:`~prompt_toolkit.layout.containers.Container` and + :class:`~prompt_toolkit.layout.controls.UIControl` objects. + + Examples of :class:`~prompt_toolkit.layout.containers.Container` objects are + :class:`~prompt_toolkit.layout.containers.VSplit` (vertical split), + :class:`~prompt_toolkit.layout.containers.HSplit` (horizontal split) and + :class:`~prompt_toolkit.layout.containers.FloatContainer`. These containers + arrange the layout and can split it in multiple regions. Each container can + recursively contain multiple other containers. They can be combined in any + way to define the "shape" of the layout. + + The :class:`~prompt_toolkit.layout.containers.Window` object is a special + kind of container that can contain + :class:`~prompt_toolkit.layout.controls.UIControl` object. The + :class:`~prompt_toolkit.layout.controls.UIControl` object is responsible for + the actual content. The :class:`~prompt_toolkit.layout.containers.Window` + object acts as an adaptor between the + :class:`~prompt_toolkit.layout.controls.UIControl` and other containers, but + it's also responsible for the scrolling and line wrapping of the content. + + Examples of :class:`~prompt_toolkit.layout.controls.UIControl` objects are + :class:`~prompt_toolkit.layout.controls.BufferControl` for showing the + content of an editable/scrollable buffer, and + :class:`~prompt_toolkit.layout.controls.FormattedTextControl` for displaying static + static (:ref:`formatted <formatted_text>`) text. -There are two types of classes that have to be combined to construct a layout: +- A higher level abstraction of building a layout is by using "widgets". A + widget is a reusable layout component that can contain multiple containers + and controls. It should have a ``__pt__container__`` function, which is + supposed to return the root container for this widget. -- **containers** (:class:`~prompt_toolkit.layout.containers.Container` - instances), which arrange the layout +- The highest level abstractions are in the ``shortcuts`` module. There we + don't have to think about the layout, controls and containers at all. This is + the simplest way to use prompt_toolkit, but is only meant for certain use + cases. -- **user controls** - (:class:`~prompt_toolkit.layout.controls.UIControl` instances), which - generate the actual content +Containers and controls +^^^^^^^^^^^^^^^^^^^^^^^ +The biggest difference between containers and controls is that containers +arrange the layout by splitting the screen in many regions, while controls are +responsible for generating the actual content. .. note:: - An important difference: + Under the hood, the difference is: - containers use *absolute coordinates*, and paint on a :class:`~prompt_toolkit.layout.screen.Screen` instance. @@ -204,16 +152,13 @@ There are two types of classes that have to be combined to construct a layout: | | :class:`~prompt_toolkit.layout.controls.FillControl` | +------------------------------------------------------+-----------------------------------------------------------+ - The :class:`~prompt_toolkit.layout.containers.Window` class itself is particular: it is a :class:`~prompt_toolkit.layout.containers.Container` that can contain a :class:`~prompt_toolkit.layout.controls.UIControl`. Thus, it's the adaptor between the two. The :class:`~prompt_toolkit.layout.containers.Window` class also takes care of -scrolling the content if the user control created a -:class:`~prompt_toolkit.layout.screen.Screen` that is larger than what was -available to the :class:`~prompt_toolkit.layout.containers.Window`. +scrolling the content if needed. Here is an example of a layout that displays the content of the default buffer on the left, and displays ``"Hello world"`` on the right. In between it shows a @@ -221,41 +166,89 @@ vertical line: .. code:: python - from prompt_toolkit.enums import DEFAULT_BUFFER + from prompt_toolkit import Application + from prompt_toolkit.buffer import Buffer from prompt_toolkit.layout.containers import VSplit, Window - from prompt_toolkit.layout.controls import BufferControl, FillControl, TokenListControl - from prompt_toolkit.layout.dimension import LayoutDimension as D + from prompt_toolkit.layout.controls import BufferControl, FormattedTextControl - from pygments.token import Token + buffer1 = Buffer() - layout = VSplit([ + root_container = VSplit([ # One window that holds the BufferControl with the default buffer on the # left. - Window(content=BufferControl(buffer_name=DEFAULT_BUFFER)), + Window(content=BufferControl(buffer=buffer1)), # A vertical line in the middle. We explicitely specify the width, to make # sure that the layout engine will not try to divide the whole width by - # three for all these windows. The `FillControl` will simply fill the whole - # window by repeating this character. - Window(width=D.exact(1), - content=FillControl('|', token=Token.Line)), + # three for all these windows. The window will simply fill its content + # by repeating this character. + Window(width=1, char='|', style='class:line'), # Display the text 'Hello world' on the right. - Window(content=TokenListControl( - get_tokens=lambda cli: [(Token, 'Hello world')])), + Window(content=FormattedTextControl('Hello world')), ]) -The previous section explains how to create an application, you can just pass -the currently created `layout` when you create the ``Application`` instance -using the ``layout=`` keyword argument. + layout = Layout(root_container) + + app = Application(layout=layout, full_screen=True) + app.run() + + +Key bindings +------------ + +In order to react to user actions, we need to create a +:class:`~prompt_toolkit.key_binding.key_bindings.KeyBindings` object and pass +that to our :class:`~prompt_toolkit.application.application.Application`. + +There are two kinds of key bindings: + +- Global key bindings, which are always active. +- Key bindings that belong to a certain + :class:`~prompt_toolkit.layout.controls.UIControl` and are only active when + this control is focussed. + +Global key bindings +^^^^^^^^^^^^^^^^^^^ .. code:: python - app = Application(..., layout=layout, ...) + from prompt_toolkit import Application + from prompt_toolkit.key_binding.key_bindings import KeyBindings + + kb = KeyBindings() + app = Application(key_bindings=kb) + app.run() + +To register a new keyboard shortcut, we can use the +:meth:`~prompt_toolkit.key_binding.key_bindings.KeyBindings.add` method as a +decorator of the key handler: +.. code:: python + + from prompt_toolkit import Application + from prompt_toolkit.key_binding.key_bindings import KeyBindings + + kb = KeyBindings() + + @kb.add('c-q') + def exit_(event): + """ + Pressing Ctrl-Q will exit the user interface. + + Setting a return value means: quit the event loop that drives the user + interface and return this value from the `CommandLineInterface.run()` call. + """ + event.app.set_return_value(None) + + app = Application(key_bindings=kb, full_screen=True) + app.run() + +The callback function is named ``exit_`` for clarity, but it could have been +named ``_`` (underscore) as well, because the we won't refer to this name. The rendering flow -^^^^^^^^^^^^^^^^^^ +------------------ Understanding the rendering flow is important for understanding how :class:`~prompt_toolkit.layout.containers.Container` and @@ -337,7 +330,7 @@ the line is not passed through the processors or even asked from the :class:`~prompt_toolkit.layout.lexers.Lexer`. Input processors -^^^^^^^^^^^^^^^^ +---------------- An :class:`~prompt_toolkit.layout.processors.Processor` is an object that processes the tokens of a line in a @@ -372,14 +365,11 @@ Some build-in processors: -The ``TokenListControl`` -^^^^^^^^^^^^^^^^^^^^^ - Custom user controls -^^^^^^^^^^^^^^^^^^^^ +-------------------- The Window class -^^^^^^^^^^^^^^^^ +---------------- The :class:`~prompt_toolkit.layout.containers.Window` class exposes many interesting functionality that influences the behaviour of user controls. @@ -395,38 +385,6 @@ The focus stack --------------- -The ``Application`` instance ----------------------------- - -The :class:`~prompt_toolkit.application.Application` instance is where all the -components for a prompt_toolkit application come together. - -.. note:: Actually, not *all* the components; just everything that is not - dependent on I/O (i.e. all components except for the eventloop and the - input/output objects). - - This way, it's possible to create an - :class:`~prompt_toolkit.application.Application` instance and later decide - to run it on an asyncio eventloop or in a telnet server. - -.. code:: python - - from prompt_toolkit.application import Application - - application = Application( - layout=layout, - key_bindings_registry=registry, - - # Let's add mouse support as well. - mouse_support=True, - - # For fullscreen: - use_alternate_screen=True) - -We are talking about full screen applications, so it's important to pass -``use_alternate_screen=True``. This switches to the alternate terminal buffer. - - .. _filters: Filters (reactivity) diff --git a/docs/pages/printing_text.rst b/docs/pages/printing_text.rst index b4b77e93..879faf88 100644 --- a/docs/pages/printing_text.rst +++ b/docs/pages/printing_text.rst @@ -29,6 +29,7 @@ The print function can be imported as follows: print_function``. Otherwise, it will not be possible to import a function named ``print``. +.. _formatted_text: Formatted text -------------- diff --git a/docs/pages/reference.rst b/docs/pages/reference.rst index a140d354..a2a7483f 100644 --- a/docs/pages/reference.rst +++ b/docs/pages/reference.rst @@ -7,6 +7,18 @@ Application .. automodule:: prompt_toolkit.application :members: +.. automodule:: prompt_toolkit.application.application + :members: + +.. automodule:: prompt_toolkit.application.current + :members: + +.. automodule:: prompt_toolkit.application.dummy + :members: + +.. automodule:: prompt_toolkit.application.run_in_terminal + :members: + Formatted text -------------- @@ -61,12 +73,6 @@ History .. automodule:: prompt_toolkit.history :members: -Interface ---------- - -.. automodule:: prompt_toolkit.interface - :members: - Keys ---- @@ -112,6 +118,9 @@ Shortcuts .. automodule:: prompt_toolkit.shortcuts.dialogs :members: +.. automodule:: prompt_toolkit.shortcuts.utils + :members: + Validation ---------- @@ -155,21 +164,12 @@ Layout .. automodule:: prompt_toolkit.layout.processors :members: -.. automodule:: prompt_toolkit.layout.toolbars - :members: - .. automodule:: prompt_toolkit.layout.utils :members: .. automodule:: prompt_toolkit.layout.screen :members: -Token ------ - -.. automodule:: prompt_toolkit.token - :members: - Filters ------- @@ -179,22 +179,19 @@ Filters .. autoclass:: prompt_toolkit.filters.Filter :members: -.. autoclass:: prompt_toolkit.filters.CLIFilter - :members: - -.. autoclass:: prompt_toolkit.filters.SimpleFilter +.. autoclass:: prompt_toolkit.filters.Condition :members: -.. autoclass:: prompt_toolkit.filters.Condition +.. automodule:: prompt_toolkit.filters.app :members: Key binding ----------- -.. automodule:: prompt_toolkit.key_binding.registry +.. automodule:: prompt_toolkit.key_binding.key_bindings :members: -.. automodule:: prompt_toolkit.key_binding.manager +.. automodule:: prompt_toolkit.key_binding.defaults :members: .. automodule:: prompt_toolkit.key_binding.vi_state @@ -227,8 +224,29 @@ Eventloop Input and output ---------------- -.. automodule:: prompt_toolkit.input +.. automodule:: prompt_toolkit.input.defaults + :members: + +.. automodule:: prompt_toolkit.input.base + :members: + +.. automodule:: prompt_toolkit.input.vt100 + :members: + +.. automodule:: prompt_toolkit.input.win32 :members: .. automodule:: prompt_toolkit.output :members: + +.. automodule:: prompt_toolkit.output.defaults + :members: + +.. automodule:: prompt_toolkit.output.base + :members: + +.. automodule:: prompt_toolkit.output.vt100 + :members: + +.. automodule:: prompt_toolkit.output.win32 + :members: |