Remove python toolkit from lib, install from pypi

This commit is contained in:
Mariano Sorgente 2020-01-13 21:26:57 +09:00
parent 102cae6f9e
commit cc7a12ef1a
No known key found for this signature in database
GPG Key ID: 0F866338C369278C
345 changed files with 2 additions and 50227 deletions

View File

@ -1 +0,0 @@
comment: off

View File

@ -1,46 +0,0 @@
*.py[cod]
# C extensions
*.so
# Packages
*.egg
*.egg-info
dist
build
eggs
parts
bin
var
sdist
develop-eggs
.installed.cfg
lib
lib64
__pycache__
# Python 3rd Party
Pipfile*
# Installer logs
pip-log.txt
# Unit test / coverage reports
.coverage
.tox
nosetests.xml
.pytest_cache
# Translations
*.mo
# Mr Developer
.mr.developer.cfg
.project
.pydevproject
# Generated documentation
docs/_build
# pycharm metadata
.idea

View File

@ -1,30 +0,0 @@
sudo: false
cache: pip
language: python
matrix:
include:
- python: 3.7
dist: xenial
sudo: required
- python: 3.6
install:
- pip install . pytest coverage codecov flake8 mypy
- pip install isort
- pip list
script:
- echo "$TRAVIS_PYTHON_VERSION"
- flake8 prompt_toolkit
- coverage run -m pytest
# Run type checker.
- mypy prompt_toolkit | grep -v "Name '_' already defined" | true
# Check wheather the imports were sorted correctly.
# When this fails, please run ./tools/sort-imports.sh
- isort -c -rc prompt_toolkit
after_success:
- codecov

View File

@ -1,11 +0,0 @@
Authors
=======
Creator
-------
Jonathan Slenders <jonathan AT slenders.be>
Contributors
------------
- Amjith Ramanujam <amjith.r AT gmail.com>

File diff suppressed because it is too large Load Diff

View File

@ -1,27 +0,0 @@
Copyright (c) 2014, Jonathan Slenders
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
* Neither the name of the {organization} nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,4 +0,0 @@
include *rst LICENSE CHANGELOG MANIFEST.in
recursive-include examples *.py
recursive-include tests *.py
prune examples/sample?/build

View File

@ -1,62 +0,0 @@
Projects using `prompt_toolkit`
===============================
Shells:
- `ptpython <http://github.com/prompt-toolkit/ptpython/>`_: Python REPL
- `ptpdb <http://github.com/jonathanslenders/ptpdb/>`_: Python debugger (pdb replacement)
- `pgcli <https://www.pgcli.com/>`_: Postgres client.
- `mycli <https://www.mycli.net/>`_: MySql client.
- `litecli <https://litecli.com/>`_: SQLite client.
- `wharfee <http://wharfee.com/>`_: A Docker command line.
- `xonsh <http://xon.sh/>`_: A Python-ish, BASHwards-compatible shell.
- `saws <https://github.com/donnemartin/saws>`_: A Supercharged AWS Command Line Interface.
- `cycli <https://github.com/nicolewhite/cycli>`_: A Command Line Interface for Cypher.
- `crash <https://github.com/crate/crash>`_: Crate command line client.
- `vcli <https://github.com/dbcli/vcli>`_: Vertica client.
- `aws-shell <https://github.com/awslabs/aws-shell>`_: An integrated shell for working with the AWS CLI.
- `softlayer-python <https://github.com/softlayer/softlayer-python>`_: A command-line interface to manage various SoftLayer products and services.
- `ipython <http://github.com/ipython/ipython/>`_: The IPython REPL
- `click-repl <https://github.com/click-contrib/click-repl>`_: Subcommand REPL for click apps.
- `haxor-news <https://github.com/donnemartin/haxor-news>`_: A Hacker News CLI.
- `gitsome <https://github.com/donnemartin/gitsome>`_: A Git/Shell Autocompleter with GitHub Integration.
- `http-prompt <https://github.com/eliangcs/http-prompt>`_: An interactive command-line HTTP client.
- `coconut <http://coconut-lang.org/>`_: Functional programming in Python.
- `Ergonomica <https://github.com/ergonomica/ergonomica>`_: A Bash alternative written in Python.
- `Kube-shell <https://github.com/cloudnativelabs/kube-shell>`_: Kubernetes shell: An integrated shell for working with the Kubernetes CLI
- `mssql-cli <https://github.com/dbcli/mssql-cli>`_: A command-line client for Microsoft SQL Server.
- `robotframework-debuglibrary <https://github.com/xyb/robotframework-debuglibrary>`_: A debug library and REPL for RobotFramework.
- `ptrepl <https://github.com/imomaliev/ptrepl>`_: Run any command as REPL
- `clipwdmgr <https://github.com/samisalkosuo/clipasswordmgr>`_: Command Line Password Manager.
- `slacker <https://github.com/netromdk/slacker>`_: Easy access to the Slack API and admin of workspaces via REPL.
- `EdgeDB <https://edgedb.com/>`_: The next generation object-relational database.
- `pywit <https://github.com/wit-ai/pywit>`_: Python library for Wit.ai.
- `objection <https://github.com/sensepost/objection>`_: Runtime Mobile Exploration.
- `habu <https://github.com/portantier/habu>`_: Python Network Hacking Toolkit.
- `nawano <https://github.com/rbw/nawano>`_: Nano cryptocurrency wallet
- `athenacli <https://github.com/dbcli/athenacli>`_: A CLI for AWS Athena.
- `vulcano <https://github.com/dgarana/vulcano>`_: A framework for creating command-line applications that also runs in REPL mode.
- `kafka-shell <https://github.com/devshawn/kafka-shell>`_: A supercharged shell for Apache Kafka.
Full screen applications:
- `pymux <http://github.com/prompt-toolkit/pymux/>`_: A terminal multiplexer (like tmux) in pure Python.
- `pyvim <http://github.com/prompt-toolkit/pyvim/>`_: A Vim clone in pure Python.
- `freud <http://github.com/stloma/freud/>`_: REST client backed by SQLite for storing servers
- `pypager <https://github.com/prompt-toolkit/pypager>`_: A $PAGER in pure Python (like "less").
- `kubeterminal <https://github.com/samisalkosuo/kubeterminal>`_: Kubectl helper tool.
- `pydoro <https://github.com/JaDogg/pydoro>`_: Pomodoro timer.
Libraries:
- `ptterm <https://github.com/prompt-toolkit/ptterm>`_: A terminal emulator widget for prompt_toolkit.
- `PyInquirer <https://github.com/CITGuru/PyInquirer/>`_: A Python library that wants to make it easy for existing Inquirer.js users to write immersive command line applications in Python.
Other libraries and implementations in other languages
******************************************************
- `go-prompt <https://github.com/c-bata/go-prompt>`_: building a powerful
interactive prompt in Go, inspired by python-prompt-toolkit.
- `urwid <http://urwid.org/>`_: Console user interface library for Python.
(Want your own project to be listed here? Please create a GitHub issue.)

View File

@ -1,161 +0,0 @@
Python Prompt Toolkit
=====================
|Build Status| |AppVeyor| |PyPI| |RTD| |License| |Codecov|
.. image :: https://github.com/prompt-toolkit/python-prompt-toolkit/raw/master/docs/images/logo_400px.png
``prompt_toolkit`` *is a library for building powerful interactive command line applications in Python.*
Read the `documentation on readthedocs
<http://python-prompt-toolkit.readthedocs.io/en/stable/>`_.
NOTICE: prompt_toolkit 3.0
**************************
Please notice that this branch is the ``prompt_toolkit`` **3.0** branch. For most
users, it should be compatible with ``prompt_toolkit`` **2.0**, but it requires at
least **Python 3.6**. On the plus side, ``prompt_toolkit`` **3.0** is completly type
annotated and uses asyncio natively.
Gallery
*******
`ptpython <http://github.com/prompt-toolkit/ptpython/>`_ is an interactive
Python Shell, build on top of ``prompt_toolkit``.
.. image :: https://github.com/prompt-toolkit/python-prompt-toolkit/raw/master/docs/images/ptpython.png
`More examples <https://python-prompt-toolkit.readthedocs.io/en/stable/pages/gallery.html>`_
^^^^
prompt_toolkit features
***********************
``prompt_toolkit`` could be a replacement for `GNU readline
<https://tiswww.case.edu/php/chet/readline/rltop.html>`_, but it can be much
more than that.
Some features:
- **Pure Python**.
- Syntax highlighting of the input while typing. (For instance, with a Pygments lexer.)
- Multi-line input editing.
- Advanced code completion.
- Both Emacs and Vi key bindings. (Similar to readline.)
- Even some advanced Vi functionality, like named registers and digraphs.
- Reverse and forward incremental search.
- Works well with Unicode double width characters. (Chinese input.)
- Selecting text for copy/paste. (Both Emacs and Vi style.)
- Support for `bracketed paste <https://cirw.in/blog/bracketed-paste>`_.
- Mouse support for cursor positioning and scrolling.
- Auto suggestions. (Like `fish shell <http://fishshell.com/>`_.)
- Multiple input buffers.
- No global state.
- Lightweight, the only dependencies are Pygments, six and wcwidth.
- Runs on Linux, OS X, FreeBSD, OpenBSD and Windows systems.
- And much more...
Feel free to create tickets for bugs and feature requests, and create pull
requests if you have nice patches that you would like to share with others.
Installation
************
::
pip install prompt_toolkit
For Conda, do:
::
conda install -c https://conda.anaconda.org/conda-forge prompt_toolkit
About Windows support
*********************
``prompt_toolkit`` is cross platform, and everything that you build on top
should run fine on both Unix and Windows systems. Windows support is best on
recent Windows 10 builds, for which the command line window supports vt100
escape sequences. (If not supported, we fall back to using Win32 APIs for color
and cursor movements).
It's worth noting that the implementation is a "best effort of what is
possible". Both Unix and Windows terminals have their limitations. But in
general, the Unix experience will still be a little better.
For Windows, it's recommended to use either `cmder
<http://cmder.net/>`_ or `conemu <https://conemu.github.io/>`_.
Getting started
***************
The most simple example of the library would look like this:
.. code:: python
from prompt_toolkit import prompt
if __name__ == '__main__':
answer = prompt('Give me some input: ')
print('You said: %s' % answer)
For more complex examples, have a look in the ``examples`` directory. All
examples are chosen to demonstrate only one thing. Also, don't be afraid to
look at the source code. The implementation of the ``prompt`` function could be
a good start.
Note for Python 2: all strings are expected to be unicode strings. So, either
put a small ``u`` in front of every string or put ``from __future__ import
unicode_literals`` at the start of the above example.
Philosophy
**********
The source code of ``prompt_toolkit`` should be **readable**, **concise** and
**efficient**. We prefer short functions focusing each on one task and for which
the input and output types are clearly specified. We mostly prefer composition
over inheritance, because inheritance can result in too much functionality in
the same object. We prefer immutable objects where possible (objects don't
change after initialization). Reusability is important. We absolutely refrain
from having a changing global state, it should be possible to have multiple
independent instances of the same code in the same process. The architecture
should be layered: the lower levels operate on primitive operations and data
structures giving -- when correctly combined -- all the possible flexibility;
while at the higher level, there should be a simpler API, ready-to-use and
sufficient for most use cases. Thinking about algorithms and efficiency is
important, but avoid premature optimization.
`Projects using prompt_toolkit <PROJECTS.rst>`_
***********************************************
Special thanks to
*****************
- `Pygments <http://pygments.org/>`_: Syntax highlighter.
- `wcwidth <https://github.com/jquast/wcwidth>`_: Determine columns needed for a wide characters.
.. |Build Status| image:: https://api.travis-ci.org/prompt-toolkit/python-prompt-toolkit.svg?branch=master
:target: https://travis-ci.org/prompt-toolkit/python-prompt-toolkit#
.. |PyPI| image:: https://img.shields.io/pypi/v/prompt_toolkit.svg
:target: https://pypi.python.org/pypi/prompt-toolkit/
:alt: Latest Version
.. |AppVeyor| image:: https://ci.appveyor.com/api/projects/status/32r7s2skrgm9ubva?svg=true
:target: https://ci.appveyor.com/project/prompt-toolkit/python-prompt-toolkit/
.. |RTD| image:: https://readthedocs.org/projects/python-prompt-toolkit/badge/
:target: https://python-prompt-toolkit.readthedocs.io/en/master/
.. |License| image:: https://img.shields.io/github/license/prompt-toolkit/python-prompt-toolkit.svg
:target: https://github.com/prompt-toolkit/python-prompt-toolkit/blob/master/LICENSE
.. |Codecov| image:: https://codecov.io/gh/prompt-toolkit/python-prompt-toolkit/branch/master/graphs/badge.svg?style=flat
:target: https://codecov.io/gh/prompt-toolkit/python-prompt-toolkit/

View File

@ -1,45 +0,0 @@
environment:
matrix:
- PYTHON: "C:\\Python36"
PYTHON_VERSION: "3.6"
- PYTHON: "C:\\Python36-x64"
PYTHON_VERSION: "3.6"
- PYTHON: "C:\\Python35"
PYTHON_VERSION: "3.5"
- PYTHON: "C:\\Python35-x64"
PYTHON_VERSION: "3.5"
- PYTHON: "C:\\Python34"
PYTHON_VERSION: "3.4"
- PYTHON: "C:\\Python34-x64"
PYTHON_VERSION: "3.4"
- PYTHON: "C:\\Python33"
PYTHON_VERSION: "3.3"
- PYTHON: "C:\\Python33-x64"
PYTHON_VERSION: "3.3"
- PYTHON: "C:\\Python27"
PYTHON_VERSION: "2.7"
- PYTHON: "C:\\Python27-x64"
PYTHON_VERSION: "2.7"
- PYTHON: "C:\\Python26"
PYTHON_VERSION: "2.6"
- PYTHON: "C:\\Python27-x64"
PYTHON_VERSION: "2.6"
install:
- "set PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
- pip install . pytest coverage codecov flake8
- pip list
build: false
test_script:
- If not ($env:PYTHON_VERSION==2.6) flake8 prompt_toolkit
- coverage run -m pytest
after_test:
- codecov

View File

@ -1,177 +0,0 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
endif
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " xml to make Docutils-native XML files"
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/prompt_toolkit.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/prompt_toolkit.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/prompt_toolkit"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/prompt_toolkit"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
latexpdfja:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through platex and dvipdfmx..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
xml:
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
@echo
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
pseudoxml:
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
@echo
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."

View File

@ -1,269 +0,0 @@
# -*- coding: utf-8 -*-
#
# prompt_toolkit documentation build configuration file, created by
# sphinx-quickstart on Thu Jul 31 14:17:08 2014.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import os
import sys
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.graphviz' ]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'prompt_toolkit'
copyright = u'2014-2018, Jonathan Slenders'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '3.0.0'
# The full version, including alpha/beta/rc tags.
release = '3.0.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all
# documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
#keep_warnings = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
if on_rtd:
html_theme = 'default'
else:
try:
import sphinx_rtd_theme
html_theme = 'sphinx_rtd_theme'
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
except ImportError:
html_theme = 'pyramid'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
html_logo = 'images/logo_400px.png'
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
#html_extra_path = []
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'prompt_toolkitdoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
('index', 'prompt_toolkit.tex', u'prompt_toolkit Documentation',
u'Jonathan Slenders', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'prompt_toolkit', u'prompt_toolkit Documentation',
[u'Jonathan Slenders'], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'prompt_toolkit', u'prompt_toolkit Documentation',
u'Jonathan Slenders', 'prompt_toolkit', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

View File

@ -1,93 +0,0 @@
Python Prompt Toolkit 3.0
=========================
.. warning::
Notice that this is the prompt_toolkit 3.0 documentation. Prompt_toolkit
3.0 is still in beta. It is mostly compatible with the 2.0 branch. The
difference is that prompt_toolkit 3.0 requires at least Python 3.6. On the
plus side, it uses asyncio natively (rather than it's own event loop), and
we have type annotations everywhere.
`prompt_toolkit` is a library for building powerful interactive command line
and terminal applications in Python.
It can be a very advanced pure Python replacement for `GNU readline
<http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html>`_, but it can also be
used for building full screen applications.
.. image:: images/ptpython-2.png
Some features:
- Syntax highlighting of the input while typing. (For instance, with a Pygments lexer.)
- Multi-line input editing.
- Advanced code completion.
- Selecting text for copy/paste. (Both Emacs and Vi style.)
- Mouse support for cursor positioning and scrolling.
- Auto suggestions. (Like `fish shell <http://fishshell.com/>`_.)
- No global state.
Like readline:
- Both Emacs and Vi key bindings.
- Reverse and forward incremental search.
- Works well with Unicode double width characters. (Chinese input.)
Works everywhere:
- Pure Python. Runs on all Python versions from 2.6 up to 3.4.
- Runs on Linux, OS X, OpenBSD and Windows systems.
- Lightweight, the only dependencies are Pygments, six and wcwidth.
- No assumptions about I/O are made. Every prompt_toolkit application should
also run in a telnet/ssh server or an `asyncio
<https://docs.python.org/3/library/asyncio.html>`_ process.
Have a look at :ref:`the gallery <gallery>` to get an idea of what is possible.
Getting started
---------------
Go to :ref:`getting started <getting_started>` and build your first prompt.
Thanks to:
----------
A special thanks to `all the contributors
<https://github.com/jonathanslenders/python-prompt-toolkit/graphs/contributors>`_
for making prompt_toolkit possible.
Also, a special thanks to the `Pygments <http://pygments.org/>`_ and `wcwidth
<https://github.com/jquast/wcwidth>`_ libraries.
Table of contents
-----------------
.. toctree::
:maxdepth: 2
pages/gallery
pages/getting_started
pages/upgrading/index
pages/printing_text
pages/asking_for_input
pages/dialogs
pages/progress_bars
pages/full_screen_apps
pages/tutorials/index
pages/advanced_topics/index
pages/reference
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
Prompt_toolkit was created by `Jonathan Slenders
<http://github.com/jonathanslenders/>`_.

View File

@ -1,242 +0,0 @@
@ECHO OFF
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set BUILDDIR=_build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
set I18NSPHINXOPTS=%SPHINXOPTS% .
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files
echo. man to make manual pages
echo. texinfo to make Texinfo files
echo. gettext to make PO message catalogs
echo. changes to make an overview over all changed/added/deprecated items
echo. xml to make Docutils-native XML files
echo. pseudoxml to make pseudoxml-XML files for display purposes
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
%SPHINXBUILD% 2> nul
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\xline.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\xline.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdf" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf
cd %BUILDDIR%/..
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdfja" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf-ja
cd %BUILDDIR%/..
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "texinfo" (
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
goto end
)
if "%1" == "gettext" (
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
if "%1" == "xml" (
%SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The XML files are in %BUILDDIR%/xml.
goto end
)
if "%1" == "pseudoxml" (
%SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
goto end
)
:end

View File

@ -1,97 +0,0 @@
.. _architecture:
Architecture
============
TODO: this is a little outdated.
::
+---------------------------------------------------------------+
| InputStream |
| =========== |
| - Parses the input stream coming from a VT100 |
| compatible terminal. Translates it into data input |
| and control characters. Calls the corresponding |
| handlers of the `InputStreamHandler` instance. |
| |
| e.g. Translate '\x1b[6~' into "Keys.PageDown", call |
| the `feed_key` method of `InputProcessor`. |
+---------------------------------------------------------------+
|
v
+---------------------------------------------------------------+
| InputStreamHandler |
| ================== |
| - Has a `Registry` of key bindings, it calls the |
| bindings according to the received keys and the |
| input mode. |
| |
| We have Vi and Emacs bindings.
+---------------------------------------------------------------+
|
v
+---------------------------------------------------------------+
| Key bindings |
| ============ |
| - Every key binding consists of a function that |
| receives an `Event` and usually it operates on |
| the `Buffer` object. (It could insert data or |
| move the cursor for example.) |
+---------------------------------------------------------------+
|
| Most of the key bindings operate on a `Buffer` object, but
| they don't have to. They could also change the visibility
| of a menu for instance, or change the color scheme.
|
v
+---------------------------------------------------------------+
| Buffer |
| ====== |
| - Contains a data structure to hold the current |
| input (text and cursor position). This class |
| implements all text manipulations and cursor |
| movements (Like e.g. cursor_forward, insert_char |
| or delete_word.) |
| |
| +-----------------------------------------------+ |
| | Document (text, cursor_position) | |
| | ================================ | |
| | Accessed as the `document` property of the | |
| | `Buffer` class. This is a wrapper around the | |
| | text and cursor position, and contains | |
| | methods for querying this data , e.g. to give | |
| | the text before the cursor. | |
| +-----------------------------------------------+ |
+---------------------------------------------------------------+
|
| Normally after every key press, the output will be
| rendered again. This happens in the event loop of
| the `Application` where `Renderer.render` is called.
v
+---------------------------------------------------------------+
| Layout |
| ====== |
| - When the renderer should redraw, the renderer |
| asks the layout what the output should look like. |
| - The layout operates on a `Screen` object that he |
| received from the `Renderer` and will put the |
| toolbars, menus, highlighted content and prompt |
| in place. |
| |
| +-----------------------------------------------+ |
| | Menus, toolbars, prompt | |
| | ======================= | |
| | | |
| +-----------------------------------------------+ |
+---------------------------------------------------------------+
|
v
+---------------------------------------------------------------+
| Renderer |
| ======== |
| - Calculates the difference between the last output |
| and the new one and writes it to the terminal |
| output. |
+---------------------------------------------------------------+

View File

@ -1,30 +0,0 @@
.. _asyncio:
Running on top of the `asyncio` event loop
==========================================
.. note::
New in prompt_toolkit 3.0. (In prompt_toolkit 2.0 this was possible using a
work-around).
Prompt_toolkit 3.0 uses asyncio natively. Calling ``Application.run()`` will
automatically run the asyncio event loop.
If however you want to run a prompt_toolkit ``Application`` within an asyncio
environment, you have to call the ``prompt_async`` method, like this:
.. code:: python
from prompt_toolkit.application import Application
async def main():
# Define application.
application = Application(
...
)
result = await application.run_async()
print(result)
asyncio.get_event_loop().run_until_complete(main())

View File

@ -1,169 +0,0 @@
.. _filters:
Filters
=======
Many places in `prompt_toolkit` require a boolean value that can change over
time. For instance:
- to specify whether a part of the layout needs to be visible or not;
- or to decide whether a certain key binding needs to be active or not;
- or the ``wrap_lines`` option of
:class:`~prompt_toolkit.layout.BufferControl`;
- etcetera.
These booleans are often dynamic and can change at runtime. For instance, the
search toolbar should only be visible when the user is actually searching (when
the search buffer has the focus). The ``wrap_lines`` option could be changed
with a certain key binding. And that key binding could only work when the
default buffer got the focus.
In `prompt_toolkit`, we decided to reduce the amount of state in the whole
framework, and apply a simple kind of reactive programming to describe the flow
of these booleans as expressions. (It's one-way only: if a key binding needs to
know whether it's active or not, it can follow this flow by evaluating an
expression.)
The (abstract) base class is :class:`~prompt_toolkit.filters.Filter`, which
wraps an expression that takes no input and evaluates to a boolean. Getting the
state of a filter is done by simply calling it.
An example
----------
The most obvious way to create such a :class:`~prompt_toolkit.filters.Filter`
instance is by creating a :class:`~prompt_toolkit.filters.Condition` instance
from a function. For instance, the following condition will evaluate to
``True`` when the user is searching:
.. code:: python
from prompt_toolkit.application.current import get_app
from prompt_toolkit.filters import Condition
is_searching = Condition(lambda: get_app().is_searching)
A different way of writing this, is by using the decorator syntax:
.. code:: python
from prompt_toolkit.application.current import get_app
from prompt_toolkit.filters import Condition
@Condition
def is_searching():
return get_app().is_searching
This filter can then be used in a key binding, like in the following snippet:
.. code:: python
from prompt_toolkit.key_binding import KeyBindings
kb = KeyBindings()
@kb.add('c-t', filter=is_searching)
def _(event):
# Do, something, but only when searching.
pass
If we want to know the boolean value of this filter, we have to call it like a
function:
.. code:: python
print(is_searching())
Built-in filters
----------------
There are many built-in filters, ready to use. All of them have a lowercase
name, because they represent the wrapped function underneath, and can be called
as a function.
- :class:`~prompt_toolkit.filters.app.has_arg`
- :class:`~prompt_toolkit.filters.app.has_completions`
- :class:`~prompt_toolkit.filters.app.has_focus`
- :class:`~prompt_toolkit.filters.app.buffer_has_focus`
- :class:`~prompt_toolkit.filters.app.has_selection`
- :class:`~prompt_toolkit.filters.app.has_validation_error`
- :class:`~prompt_toolkit.filters.app.is_aborting`
- :class:`~prompt_toolkit.filters.app.is_done`
- :class:`~prompt_toolkit.filters.app.is_read_only`
- :class:`~prompt_toolkit.filters.app.is_multiline`
- :class:`~prompt_toolkit.filters.app.renderer_height_is_known`
- :class:`~prompt_toolkit.filters.app.in_editing_mode`
- :class:`~prompt_toolkit.filters.app.in_paste_mode`
- :class:`~prompt_toolkit.filters.app.vi_mode`
- :class:`~prompt_toolkit.filters.app.vi_navigation_mode`
- :class:`~prompt_toolkit.filters.app.vi_insert_mode`
- :class:`~prompt_toolkit.filters.app.vi_insert_multiple_mode`
- :class:`~prompt_toolkit.filters.app.vi_replace_mode`
- :class:`~prompt_toolkit.filters.app.vi_selection_mode`
- :class:`~prompt_toolkit.filters.app.vi_waiting_for_text_object_mode`
- :class:`~prompt_toolkit.filters.app.vi_digraph_mode`
- :class:`~prompt_toolkit.filters.app.emacs_mode`
- :class:`~prompt_toolkit.filters.app.emacs_insert_mode`
- :class:`~prompt_toolkit.filters.app.emacs_selection_mode`
- :class:`~prompt_toolkit.filters.app.is_searching`
- :class:`~prompt_toolkit.filters.app.control_is_searchable`
- :class:`~prompt_toolkit.filters.app.vi_search_direction_reversed`
Combining filters
-----------------
Filters can be chained with the ``&`` (AND) and ``|`` (OR) operators and
negated with the ``~`` (negation) operator.
Some examples:
.. code:: python
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.filters import has_selection, has_selection
kb = KeyBindings()
@kb.add('c-t', filter=~is_searching)
def _(event):
" Do something, but not while searching. "
pass
@kb.add('c-t', filter=has_search | has_selection)
def _(event):
" Do something, but only when searching or when there is a selection. "
pass
to_filter
---------
Finally, in many situations you want your code to expose an API that is able to
deal with both booleans as well as filters. For instance, when for most users a
boolean works fine because they don't need to change the value over time, while
some advanced users want to be able this value to a certain setting or event
that does changes over time.
In order to handle both use cases, there is a utility called
:func:`~prompt_toolkit.filters.utils.to_filter`.
This is a function that takes
either a boolean or an actual :class:`~prompt_toolkit.filters.Filter`
instance, and always returns a :class:`~prompt_toolkit.filters.Filter`.
.. code:: python
from prompt_toolkit.filters.utils import to_filter
# In each of the following three examples, 'f' will be a `Filter`
# instance.
f = to_filter(True)
f = to_filter(False)
f = to_filter(Condition(lambda: True))
f = to_filter(has_search | has_selection)

View File

@ -1,17 +0,0 @@
.. _advanced_topics:
Advanced topics
===============
.. toctree::
:caption: Contents:
:maxdepth: 1
key_bindings
styling
filters
rendering_flow
asyncio
input_hooks
architecture
rendering_pipeline

View File

@ -1,11 +0,0 @@
.. _input_hooks:
Input hooks
===========
Input hooks are a tool for inserting an external event loop into the
prompt_toolkit event loop, so that the other loop can run as long as
prompt_toolkit is idle. This is used in applications like `IPython
<https://ipython.org/>`_, so that GUI toolkits can display their windows while
we wait at the prompt for user input.

View File

@ -1,340 +0,0 @@
.. _key_bindings:
More about key bindings
=======================
This page contains a few additional notes about key bindings.
Key bindings can be defined as follows by creating a
:class:`~prompt_toolkit.key_binding.KeyBindings` instance:
.. code:: python
from prompt_toolkit.key_binding import KeyBindings
bindings = KeyBindings()
@bindings.add('a')
def _(event):
" Do something if 'a' has been pressed. "
...
@bindings.add('c-t')
def _(event):
" Do something if Control-T has been pressed. "
...
.. note::
:kbd:`c-q` (control-q) and :kbd:`c-s` (control-s) are often captured by the
terminal, because they were used traditionally for software flow control.
When this is enabled, the application will automatically freeze when
:kbd:`c-s` is pressed, until :kbd:`c-q` is pressed. It won't be possible to
bind these keys.
In order to disable this, execute type the following in your shell, or even
add it to your `.bashrc`.
.. code::
stty -ixon
Key bindings can even consist of a sequence of multiple keys. The binding is
only triggered when all the keys in this sequence are pressed.
.. code:: python
@bindings.add('a', 'b')
def _(event):
" Do something if 'a' is pressed and then 'b' is pressed. "
...
If the user presses only `a`, then nothing will happen until either a second
key (like `b`) has been pressed or until the timeout expires (see later).
List of special keys
--------------------
Besides literal characters, any of the following keys can be used in a key
binding:
+-------------------+-----------------------------------------+
| Name + Possible keys |
+===================+=========================================+
| Escape | :kbd:`escape` |
+-------------------+-----------------------------------------+
| Arrows | :kbd:`left`, |
| | :kbd:`right`, |
| | :kbd:`up`, |
| | :kbd:`down` |
+-------------------+-----------------------------------------+
| Navigation | :kbd:`home`, |
| | :kbd:`end`, |
| | :kbd:`delete`, |
| | :kbd:`pageup`, |
| | :kbd:`pagedown`, |
| | :kbd:`insert` |
+-------------------+-----------------------------------------+
| Control+lowercase | :kbd:`c-a`, :kbd:`c-b`, :kbd:`c-c`, |
| | :kbd:`c-d`, :kbd:`c-e`, :kbd:`c-f`, |
| | :kbd:`c-g`, :kbd:`c-h`, :kbd:`c-i`, |
| | :kbd:`c-j`, :kbd:`c-k`, :kbd:`c-l`, |
| | |
| | :kbd:`c-m`, :kbd:`c-n`, :kbd:`c-o`, |
| | :kbd:`c-p`, :kbd:`c-q`, :kbd:`c-r`, |
| | :kbd:`c-s`, :kbd:`c-t`, :kbd:`c-u`, |
| | :kbd:`c-v`, :kbd:`c-w`, :kbd:`c-x`, |
| | |
| | :kbd:`c-y`, :kbd:`c-z` |
+-------------------+-----------------------------------------+
| Control+uppercase | :kbd:`c-A`, :kbd:`c-B`, :kbd:`c-C`, |
| | :kbd:`c-D`, :kbd:`c-E`, :kbd:`c-F`, |
| | :kbd:`c-G`, :kbd:`c-H`, :kbd:`c-I`, |
| | :kbd:`c-J`, :kbd:`c-K`, :kbd:`c-L`, |
| | |
| | :kbd:`c-M`, :kbd:`c-N`, :kbd:`c-O`, |
| | :kbd:`c-P`, :kbd:`c-Q`, :kbd:`c-R`, |
| | :kbd:`c-S`, :kbd:`c-T`, :kbd:`c-U`, |
| | :kbd:`c-V`, :kbd:`c-W`, :kbd:`c-X`, |
| | |
| | :kbd:`c-Y`, :kbd:`c-Z` |
+-------------------+-----------------------------------------+
| Control + arrow | :kbd:`c-left`, |
| | :kbd:`c-right`, |
| | :kbd:`c-up`, |
| | :kbd:`c-down` |
+-------------------+-----------------------------------------+
| Other control | :kbd:`c-@`, |
| keys | :kbd:`c-\\`, |
| | :kbd:`c-]`, |
| | :kbd:`c-^`, |
| | :kbd:`c-_`, |
| | :kbd:`c-delete` |
+-------------------+-----------------------------------------+
| Shift + arrow | :kbd:`s-left`, |
| | :kbd:`s-right`, |
| | :kbd:`s-up`, |
| | :kbd:`s-down` |
+-------------------+-----------------------------------------+
| Other shift | :kbd:`s-delete`, |
| keys | :kbd:`s-tab` |
+-------------------+-----------------------------------------+
| F-keys | :kbd:`f1`, :kbd:`f2`, :kbd:`f3`, |
| | :kbd:`f4`, :kbd:`f5`, :kbd:`f6`, |
| | :kbd:`f7`, :kbd:`f8`, :kbd:`f9`, |
| | :kbd:`f10`, :kbd:`f11`, :kbd:`f12`, |
| | |
| | :kbd:`f13`, :kbd:`f14`, :kbd:`f15`, |
| | :kbd:`f16`, :kbd:`f17`, :kbd:`f18`, |
| | :kbd:`f19`, :kbd:`f20`, :kbd:`f21`, |
| | :kbd:`f22`, :kbd:`f23`, :kbd:`f24` |
+-------------------+-----------------------------------------+
There are a couple of useful aliases as well:
+-------------------+-------------------+
| :kbd:`c-h` | :kbd:`backspace` |
+-------------------+-------------------+
| :kbd:`c-@` | :kbd:`c-space` |
+-------------------+-------------------+
| :kbd:`c-m` | :kbd:`enter` |
+-------------------+-------------------+
| :kbd:`c-i` | :kbd:`tab` |
+-------------------+-------------------+
.. note::
Note that the supported keys are limited to what typical VT100 terminals
offer. Binding :kbd:`c-7` (control + number 7) for instance is not
supported.
Binding alt+something, option+something or meta+something
---------------------------------------------------------
Vt100 terminals translate the alt key into a leading :kbd:`escape` key.
For instance, in order to handle :kbd:`alt-f`, we have to handle
:kbd:`escape` + :kbd:`f`. Notice that we receive this as two individual keys.
This means that it's exactly the same as first typing :kbd:`escape` and then
typing :kbd:`f`. Something this alt-key is also known as option or meta.
In code that looks as follows:
.. code:: python
@bindings.add('escape', 'f')
def _(event):
" Do something if alt-f or meta-f have been pressed. "
Wildcards
---------
Sometimes you want to catch any key that follows after a certain key stroke.
This is possible by binding the '<any>' key:
.. code:: python
@bindings.add('a', '<any>')
def _(event):
...
This will handle `aa`, `ab`, `ac`, etcetera. The key binding can check the
`event` object for which keys exactly have been pressed.
Attaching a filter (condition)
------------------------------
In order to enable a key binding according to a certain condition, we have to
pass it a :class:`~prompt_toolkit.filters.Filter`, usually a
:class:`~prompt_toolkit.filters.Condition` instance. (:ref:`Read more about
filters <filters>`.)
.. code:: python
from prompt_toolkit.filters import Condition
@Condition
def is_active():
" Only activate key binding on the second half of each minute. "
return datetime.datetime.now().second > 30
@bindings.add('c-t', filter=is_active)
def _(event):
# ...
pass
The key binding will be ignored when this condition is not satisfied.
ConditionalKeyBindings: Disabling a set of key bindings
-------------------------------------------------------
Sometimes you want to enable or disable a whole set of key bindings according
to a certain condition. This is possible by wrapping it in a
:class:`~prompt_toolkit.key_binding.ConditionalKeyBindings` object.
.. code:: python
from prompt_toolkit.key_binding import ConditionalKeyBindings
@Condition
def is_active():
" Only activate key binding on the second half of each minute. "
return datetime.datetime.now().second > 30
bindings = ConditionalKeyBindings(
key_bindings=my_bindings,
filter=is_active)
If the condition is not satisfied, all the key bindings in `my_bindings` above
will be ignored.
Merging key bindings
--------------------
Sometimes you have different parts of your application generate a collection of
key bindings. It is possible to merge them together through the
:func:`~prompt_toolkit.key_binding.merge_key_bindings` function. This is
preferred above passing a :class:`~prompt_toolkit.key_binding.KeyBindings`
object around and having everyone populate it.
.. code:: python
from prompt_toolkit.key_binding import merge_key_bindings
bindings = merge_key_bindings([
bindings1,
bindings2,
])
Eager
-----
Usually not required, but if ever you have to override an existing key binding,
the `eager` flag can be useful.
Suppose that there is already an active binding for `ab` and you'd like to add
a second binding that only handles `a`. When the user presses only `a`,
prompt_toolkit has to wait for the next key press in order to know which
handler to call.
By passing the `eager` flag to this second binding, we are actually saying that
prompt_toolkit shouldn't wait for longer matches when all the keys in this key
binding are matched. So, if `a` has been pressed, this second binding will be
called, even if there's an active `ab` binding.
.. code:: python
@bindings.add('a', 'b')
def binding_1(event):
...
@bindings.add('a', eager=True)
def binding_2(event):
...
This is mainly useful in order to conditionally override another binding.
Timeouts
--------
There are two timeout settings that effect the handling of keys.
- ``Application.ttimeoutlen``: Like Vim's `ttimeoutlen` option.
When to flush the input (For flushing escape keys.) This is important on
terminals that use vt100 input. We can't distinguish the escape key from for
instance the left-arrow key, if we don't know what follows after "\x1b". This
little timer will consider "\x1b" to be escape if nothing did follow in this
time span. This seems to work like the `ttimeoutlen` option in Vim.
- ``KeyProcessor.timeoutlen``: like Vim's `timeoutlen` option.
This can be `None` or a float. For instance, suppose that we have a key
binding AB and a second key binding A. If the uses presses A and then waits,
we don't handle this binding yet (unless it was marked 'eager'), because we
don't know what will follow. This timeout is the maximum amount of time that
we wait until we call the handlers anyway. Pass `None` to disable this
timeout.
Recording macros
----------------
Both Emacs and Vi mode allow macro recording. By default, all key presses are
recorded during a macro, but it is possible to exclude certain keys by setting
the `record_in_macro` parameter to `False`:
.. code:: python
@bindings.add('c-t', record_in_macro=False)
def _(event):
# ...
pass
Creating new Vi text objects and operators
------------------------------------------
We tried very hard to ship prompt_toolkit with as many as possible Vi text
objects and operators, so that text editing feels as natural as possible to Vi
users.
If you wish to create a new text object or key binding, that is actually
possible. Check the `custom-vi-operator-and-text-object.py` example for more
information.
Processing `.inputrc`
---------------------
GNU readline can be configured using an `.inputrc` configuration file. This can
could key bindings as well as certain settings. Right now, prompt_toolkit
doesn't support `.inputrc` yet, but it should be possible in the future.

View File

@ -1,86 +0,0 @@
.. _rendering_flow:
The rendering flow
==================
Understanding the rendering flow is important for understanding how
:class:`~prompt_toolkit.layout.Container` and
:class:`~prompt_toolkit.layout.UIControl` objects interact. We will demonstrate
it by explaining the flow around a
:class:`~prompt_toolkit.layout.BufferControl`.
.. note::
A :class:`~prompt_toolkit.layout.BufferControl` is a
:class:`~prompt_toolkit.layout.UIControl` for displaying the content of a
:class:`~prompt_toolkit.buffer.Buffer`. A buffer is the object that holds
any editable region of text. Like all controls, it has to be wrapped into a
:class:`~prompt_toolkit.layout.Window`.
Let's take the following code:
.. code:: python
from prompt_toolkit.enums import DEFAULT_BUFFER
from prompt_toolkit.layout.containers import Window
from prompt_toolkit.layout.controls import BufferControl
from prompt_toolkit.buffer import Buffer
b = Buffer(name=DEFAULT_BUFFER)
Window(content=BufferControl(buffer=b))
What happens when a :class:`~prompt_toolkit.renderer.Renderer` objects wants a
:class:`~prompt_toolkit.layout.Container` to be rendered on a certain
:class:`~prompt_toolkit.layout.screen.Screen`?
The visualisation happens in several steps:
1. The :class:`~prompt_toolkit.renderer.Renderer` calls the
:meth:`~prompt_toolkit.layout.Container.write_to_screen` method
of a :class:`~prompt_toolkit.layout.Container`.
This is a request to paint the layout in a rectangle of a certain size.
The :class:`~prompt_toolkit.layout.Window` object then requests
the :class:`~prompt_toolkit.layout.UIControl` to create a
:class:`~prompt_toolkit.layout.UIContent` instance (by calling
:meth:`~prompt_toolkit.layout.UIControl.create_content`).
The user control receives the dimensions of the window, but can still
decide to create more or less content.
Inside the :meth:`~prompt_toolkit.layout.UIControl.create_content`
method of :class:`~prompt_toolkit.layout.UIControl`, there are several
steps:
2. First, the buffer's text is passed to the
:meth:`~prompt_toolkit.lexers.Lexer.lex_document` method of a
:class:`~prompt_toolkit.lexers.Lexer`. This returns a function which
for a given line number, returns a "formatted text list" for that line
(that's a list of ``(style_string, text)`` tuples).
3. This list is passed through a list of
:class:`~prompt_toolkit.layout.processors.Processor` objects.
Each processor can do a transformation for each line.
(For instance, they can insert or replace some text, highlight the
selection or search string, etc...)
4. The :class:`~prompt_toolkit.layout.UIControl` returns a
:class:`~prompt_toolkit.layout.UIContent` instance which
generates such a token lists for each lines.
The :class:`~prompt_toolkit.layout.Window` receives the
:class:`~prompt_toolkit.layout.UIContent` and then:
5. It calculates the horizontal and vertical scrolling, if applicable
(if the content would take more space than what is available).
6. The content is copied to the correct absolute position
:class:`~prompt_toolkit.layout.screen.Screen`, as requested by the
:class:`~prompt_toolkit.renderer.Renderer`. While doing this, the
:class:`~prompt_toolkit.layout.Window` can possible wrap the
lines, if line wrapping was configured.
Note that this process is lazy: if a certain line is not displayed in the
:class:`~prompt_toolkit.layout.Window`, then it is not requested
from the :class:`~prompt_toolkit.layout.UIContent`. And from there, the line is
not passed through the processors or even asked from the
:class:`~prompt_toolkit.lexers.Lexer`.

View File

@ -1,157 +0,0 @@
The rendering pipeline
======================
This document is an attempt to describe how prompt_toolkit applications are
rendered. It's a complex but logical process that happens more or less after
every key stroke. We'll go through all the steps from the point where the user
hits a key, until the character appears on the screen.
Waiting for user input
----------------------
Most of the time when a prompt_toolkit application is running, it is idle. It's
sitting in the event loop, waiting for some I/O to happen. The most important
kind of I/O we're waiting for is user input. So, within the event loop, we have
one file descriptor that represents the input device from where we receive key
presses. The details are a little different between operating systems, but it
comes down to a selector (like select or epoll) which waits for one or more
file descriptor. The event loop is then responsible for calling the appropriate
feedback when one of the file descriptors becomes ready.
It is like that when the user presses a key: the input device becomes ready for
reading, and the appropriate callback is called. This is the `read_from_input`
function somewhere in `application.py`. It will read the input from the
:class:`~prompt_toolkit.input.Input` object, by calling
:meth:`~prompt_toolkit.input.Input.read_keys`.
Reading the user input
----------------------
The actual reading is also operating system dependent. For instance, on a Linux
machine with a vt100 terminal, we read the input from the pseudo terminal
device, by calling `os.read`. This however returns a sequence of bytes. There
are two difficulties:
- The input could be UTF-8 encoded, and there is always the possibility that we
receive only a portion of a multi-byte character.
- vt100 key presses consist of multiple characters. For instance the "left
arrow" would generate something like ``\x1b[D``. It could be that when we
read this input stream, that at some point we only get the first part of such
a key press, and we have to wait for the rest to arrive.
Both problems are implemented using state machines.
- The UTF-8 problem is solved using `codecs.getincrementaldecoder`, which is an
object in which we can feed the incoming bytes, and it will only return the
complete UTF-8 characters that we have so far. The rest is buffered for the
next read operation.
- Vt100 parsing is solved by the
:class:`~prompt_toolkit.input.vt100_parser.Vt100Parser` state machine. The
state machine itself is implemented using a generator. We feed the incoming
characters to the generator, and it will call the appropriate callback for
key presses once they arrive. One thing here to keep in mind is that the
characters for some key presses are a prefix of other key presses, like for
instance, escape (``\x1b``) is a prefix of the left arrow key (``\x1b[D``).
So for those, we don't know what key is pressed until more data arrives or
when the input is flushed because of a timeout.
For Windows systems, it's a little different. Here we use Win32 syscalls for
reading the console input.
Processing the key presses
--------------------------
The ``Key`` objects that we receive are then passed to the
:class:`~prompt_toolkit.key_binding.key_processor.KeyProcessor` for matching
against the currently registered and active key bindings.
This is another state machine, because key bindings are linked to a sequence of
key presses. We cannot call the handler until all of these key presses arrive
and until we're sure that this combination is not a prefix of another
combination. For instance, sometimes people bind ``jj`` (a double ``j`` key
press) to ``esc`` in Vi mode. This is convenient, but we want to make sure that
pressing ``j`` once only, followed by a different key will still insert the
``j`` character as usual.
Now, there are hundreds of key bindings in prompt_toolkit (in ptpython, right
now we have 585 bindings). This is mainly caused by the way that Vi key
bindings are generated. In order to make this efficient, we keep a cache of
handlers which match certain sequences of keys.
Of course, key bindings also have filters attached for enabling/disabling them.
So, if at some point, we get a list of handlers from that cache, we still have
to discard the inactive bindings. Luckily, many bindings share exactly the same
filter, and we have to check every filter only once.
:ref:`Read more about key bindings ...<key_bindings>`
The key handlers
----------------
Once a key sequence is matched, the handler is called. This can do things like
text manipulation, changing the focus or anything else.
After the handler is called, the user interface is invalidated and rendered
again.
Rendering the user interface
----------------------------
The rendering is pretty complex for several reasons:
- We have to compute the dimensions of all user interface elements. Sometimes
they are given, but sometimes this requires calculating the size of
:class:`~prompt_toolkit.layout.UIControl` objects.
- It needs to be very efficient, because it's something that happens on every
single key stroke.
- We should output as little as possible on stdout in order to reduce latency
on slow network connections and older terminals.
Calculating the total UI height
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Unless the application is a full screen application, we have to know how much
vertical space is going to be consumed. The total available width is given, but
the vertical space is more dynamic. We do this by asking the root
:class:`~prompt_toolkit.layout.Container` object to calculate its preferred
height. If this is a :class:`~prompt_toolkit.layout.VSplit` or
:class:`~prompt_toolkit.layout.HSplit` then this involves recursively querying
the child objects for their preferred widths and heights and either summing it
up, or taking maximum values depending on the actual layout.
In the end, we get the preferred height, for which we make sure it's at least
the distance from the cursor position to the bottom of the screen.
Painting to the screen
^^^^^^^^^^^^^^^^^^^^^^
Then we create a :class:`~prompt_toolkit.layout.screen.Screen` object. This is
like a canvas on which user controls can paint their content. The
:meth:`~prompt_toolkit.layout.Container.write_to_screen` method of the root
`Container` is called with the screen dimensions. This will call recursively
:meth:`~prompt_toolkit.layout.Container.write_to_screen` methods of nested
child containers, each time passing smaller dimensions while we traverse what
is a tree of `Container` objects.
The most inner containers are :class:`~prompt_toolkit.layout.Window` objects,
they will do the actual painting of the
:class:`~prompt_toolkit.layout.UIControl` to the screen. This involves line
wrapping the `UIControl`'s text and maybe scrolling the content horizontally or
vertically.
Rendering to stdout
^^^^^^^^^^^^^^^^^^^
Finally, when we have painted the screen, this needs to be rendered to stdout.
This is done by taking the difference of the previously rendered screen and the
new one. The algorithm that we have is heavily optimized to compute this
difference as quickly as possible, and call the appropriate output functions of
the :class:`~prompt_toolkit.output.Output` back-end. At the end, it will
position the cursor in the right place.

View File

@ -1,320 +0,0 @@
.. _styling:
More about styling
==================
This page will attempt to explain in more detail how to use styling in
prompt_toolkit.
To some extent, it is very similar to how `Pygments <http://pygments.org/>`_
styling works.
Style strings
-------------
Many user interface controls, like :class:`~prompt_toolkit.layout.Window`
accept a ``style`` argument which can be used to pass the formatting as a
string. For instance, we can select a foreground color:
- ``"fg:ansired"`` (ANSI color palette)
- ``"fg:ansiblue"`` (ANSI color palette)
- ``"fg:#ffaa33"`` (hexadecimal notation)
- ``"fg:darkred"`` (named color)
Or a background color:
- ``"bg:ansired"`` (ANSI color palette)
- ``"bg:#ffaa33"`` (hexadecimal notation)
Or we can add one of the following flags:
- ``"bold"``
- ``"italic"``
- ``"underline"``
- ``"blink"``
- ``"reverse"`` (reverse foreground and background on the terminal.)
- ``"hidden"``
Or their negative variants:
- ``"nobold"``
- ``"noitalic"``
- ``"nounderline"``
- ``"noblink"``
- ``"noreverse"``
- ``"nohidden"``
All of these formatting options can be combined as well:
- ``"fg:ansiyellow bg:black bold underline"``
The style string can be given to any user control directly, or to a
:class:`~prompt_toolkit.layout.Container` object from where it will propagate
to all its children. A style defined by a parent user control can be overridden
by any of its children. The parent can for instance say ``style="bold
underline"`` where a child overrides this style partly by specifying
``style="nobold bg:ansired"``.
.. note::
These styles are actually compatible with
`Pygments <http://pygments.org/>`_ styles, with additional support for
`reverse` and `blink`. Further, we ignore flags like `roman`, `sans`,
`mono` and `border`.
The following ANSI colors are available (both for foreground and background):
.. code::
# Low intensity, dark. (One or two components 0x80, the other 0x00.)
ansiblack, ansired, ansigreen, ansiyellow, ansiblue
ansimagenta, 'ansicyan, ansigray
# High intensity, bright.
ansibrightblack, ansibrightred, ansibrightgreen, ansibrightyellow
ansibrightblue, ansibrightmagenta, ansibrightcyan, ansiwhite
In order to know which styles are actually used in an application, it is
possible to call :meth:`~Application.get_used_style_strings`, when the
application is done.
Class names
-----------
Like we do for web design, it is not a good habit to specify all styling
inline. Instead, we can attach class names to UI controls and have a style
sheet that refers to these class names. The
:class:`~prompt_toolkit.styles.Style` can be passed as an argument to the
:class:`~prompt_toolkit.application.Application`.
.. code:: python
from prompt_toolkit.layout import VSplit, Window
from prompt_toolkit.styles import Style
layout = VSplit([
Window(BufferControl(...), style='class:left'),
HSplit([
Window(BufferControl(...), style='class:top'),
Window(BufferControl(...), style='class:bottom'),
], style='class:right')
])
style = Style([
('left', 'bg:ansired'),
('top', 'fg:#00aaaa'),
('bottom', 'underline bold'),
])
It is possible to add multiple class names to an element. That way we'll
combine the styling for these class names. Multiple classes can be passed by
using a comma separated list, or by using the ``class:`` prefix twice.
.. code:: python
Window(BufferControl(...), style='class:left,bottom'),
Window(BufferControl(...), style='class:left class:bottom'),
It is possible to combine class names and inline styling. The order in which
the class names and inline styling is specified determines the order of
priority. In the following example for instance, we'll take first the style of
the "header" class, and then override that with a red background color.
.. code:: python
Window(BufferControl(...), style='class:header bg:red'),
Dot notation in class names
---------------------------
The dot operator has a special meaning in a class name. If we write:
``style="class:a.b.c"``, then this will actually expand to the following:
``style="class:a class:a.b class:a.b.c"``.
This is mainly added for `Pygments <http://pygments.org/>`_ lexers, which
specify "Tokens" like this, but it's useful in other situations as well.
Multiple classes in a style sheet
---------------------------------
A style sheet can be more complex as well. We can for instance specify two
class names. The following will underline the left part within the header, or
whatever has both the class "left" and the class "header" (the order doesn't
matter).
.. code:: python
style = Style([
('header left', 'underline'),
])
If you have a dotted class, then it's required to specify the whole path in the
style sheet (just typing ``c`` or ``b.c`` doesn't work if the class is
``a.b.c``):
.. code:: python
style = Style([
('a.b.c', 'underline'),
])
It is possible to combine this:
.. code:: python
style = Style([
('header body left.text', 'underline'),
])
Evaluation order of rules in a style sheet
------------------------------------------
The style is determined as follows:
- First, we concatenate all the style strings from the root control through all
the parents to the child in one big string. (Things at the right take
precedence anyway.)
E.g: ``class:body bg:#aaaaaa #000000 class:header.focused class:left.text.highlighted underline``
- Then we go through this style from left to right, starting from the default
style. Inline styling is applied directly.
If we come across a class name, then we generate all combinations of the
class names that we collected so far (this one and all class names to the
left), and for each combination which includes the new class name, we look
for matching rules in our style sheet. All these rules are then applied
(later rules have higher priority).
If we find a dotted class name, this will be expanded in the individual names
(like ``class:left class:left.text class:left.text.highlighted``), and all
these are applied like any class names.
- Then this final style is applied to this user interface element.
Using a dictionary as a style sheet
-----------------------------------
The order of the rules in a style sheet is meaningful, so typically, we use a
list of tuples to specify the style. But is also possible to use a dictionary
as a style sheet. This makes sense for Python 3.6, where dictionaries remember
their ordering. An ``OrderedDict`` works as well.
.. code:: python
from prompt_toolkit.styles import Style
style = Style.from_dict({
'header body left.text': 'underline',
})
Loading a style from Pygments
-----------------------------
`Pygments <http://pygments.org/>`_ has a slightly different notation for
specifying styles, because it maps styling to Pygments "Tokens". A Pygments
style can however be loaded and used as follows:
.. code:: python
from prompt_toolkit.styles.from_pygments import style_from_pygments_cls
from pygments.styles import get_style_by_name
style = style_from_pygments_cls(get_style_by_name('monokai'))
Merging styles together
-----------------------
Multiple :class:`~prompt_toolkit.styles.Style` objects can be merged together as
follows:
.. code:: python
from prompt_toolkit.styles import merge_styles
style = merge_styles([
style1,
style2,
style3
])
Color depths
------------
There are four different levels of color depths available:
+--------+-----------------+-----------------------------+---------------------------------+
| 1 bit | Black and white | ``ColorDepth.DEPTH_1_BIT`` | ``ColorDepth.MONOCHROME`` |
+--------+-----------------+-----------------------------+---------------------------------+
| 4 bit | ANSI colors | ``ColorDepth.DEPTH_4_BIT`` | ``ColorDepth.ANSI_COLORS_ONLY`` |
+--------+-----------------+-----------------------------+---------------------------------+
| 8 bit | 256 colors | ``ColorDepth.DEPTH_8_BIT`` | ``ColorDepth.DEFAULT`` |
+--------+-----------------+-----------------------------+---------------------------------+
| 24 bit | True colors | ``ColorDepth.DEPTH_24_BIT`` | ``ColorDepth.TRUE_COLOR`` |
+--------+-----------------+-----------------------------+---------------------------------+
By default, 256 colors are used, because this is what most terminals support
these days. If the ``TERM`` enviroment variable is set to ``linux`` or
``eterm-color``, then only ANSI colors are used, because of these terminals. 24
bit true color output needs to be enabled explicitely. When 4 bit color output
is chosen, all colors will be mapped to the closest ANSI color.
Setting the default color depth for any prompt_toolkit application can be done
by setting the ``PROMPT_TOOLKIT_COLOR_DEPTH`` environment variable. You could
for instance copy the following into your `.bashrc` file.
.. code:: shell
# export PROMPT_TOOLKIT_COLOR_DEPTH=DEPTH_1_BIT
export PROMPT_TOOLKIT_COLOR_DEPTH=DEPTH_4_BIT
# export PROMPT_TOOLKIT_COLOR_DEPTH=DEPTH_8_BIT
# export PROMPT_TOOLKIT_COLOR_DEPTH=DEPTH_24_BIT
An application can also decide to set the color depth manually by passing a
:class:`~prompt_toolkit.output.ColorDepth` value to the
:class:`~prompt_toolkit.application.Application` object:
.. code:: python
from prompt_toolkit.output.color_depth import ColorDepth
app = Application(
color_depth=ColorDepth.ANSI_COLORS_ONLY,
# ...
)
Style transformations
---------------------
Prompt_toolkit supports a way to apply certain transformations to the styles
near the end of the rendering pipeline. This can be used for instance to change
certain colors to improve the rendering in some terminals.
One useful example is the
:class:`~prompt_toolkit.styles.AdjustBrightnessStyleTransformation` class,
which takes `min_brightness` and `max_brightness` as arguments which by default
have 0.0 and 1.0 as values. In the following code snippet, we increase the
minimum brightness to improve rendering on terminals with a dark background.
.. code:: python
from prompt_toolkit.styles import AdjustBrightnessStyleTransformation
app = Application(
style_transformation=AdjustBrightnessStyleTransformation(
min_brightness=0.5, # Increase the minimum brightness.
max_brightness=1.0,
)
# ...
)

View File

@ -1,968 +0,0 @@
.. _asking_for_input:
Asking for input (prompts)
==========================
This page is about building prompts. Pieces of code that we can embed in a
program for asking the user for input. Even if you want to use `prompt_toolkit`
for building full screen terminal applications, it is probably still a good
idea to read this first, before heading to the :ref:`building full screen
applications <full_screen_applications>` page.
In this page, we will cover autocompletion, syntax highlighting, key bindings,
and so on.
Hello world
-----------
The following snippet is the most simple example, it uses the
:func:`~prompt_toolkit.shortcuts.prompt` function to asks the user for input
and returns the text. Just like ``(raw_)input``.
.. code:: python
from __future__ import unicode_literals
from prompt_toolkit import prompt
text = prompt('Give me some input: ')
print('You said: %s' % text)
.. image:: ../images/hello-world-prompt.png
What we get here is a simple prompt that supports the Emacs key bindings like
readline, but further nothing special. However,
:func:`~prompt_toolkit.shortcuts.prompt` has a lot of configuration options.
In the following sections, we will discover all these parameters.
.. note::
`prompt_toolkit` expects unicode strings everywhere. If you are using
Python 2, make sure that all strings which are passed to `prompt_toolkit`
are unicode strings (and not bytes). Either use
``from __future__ import unicode_literals`` or explicitly put a small
``'u'`` in front of every string.
The `PromptSession` object
--------------------------
Instead of calling the :func:`~prompt_toolkit.shortcuts.prompt` function, it's
also possible to create a :class:`~prompt_toolkit.shortcuts.PromptSession`
instance followed by calling its
:meth:`~prompt_toolkit.shortcuts.PromptSession.prompt` method for every input
call. This creates a kind of an input session.
.. code:: python
from prompt_toolkit import PromptSession
# Create prompt object.
session = PromptSession()
# Do multiple input calls.
text1 = session.prompt()
text2 = session.prompt()
This has mainly two advantages:
- The input history will be kept between consecutive
:meth:`~prompt_toolkit.shortcuts.PromptSession.prompt` calls.
- The :func:`~prompt_toolkit.shortcuts.PromptSession` instance and its
:meth:`~prompt_toolkit.shortcuts.PromptSession.prompt` method take about the
same arguments, like all the options described below (highlighting,
completion, etc...). So if you want to ask for multiple inputs, but each
input call needs about the same arguments, they can be passed to the
:func:`~prompt_toolkit.shortcuts.PromptSession` instance as well, and they
can be overridden by passing values to the
:meth:`~prompt_toolkit.shortcuts.PromptSession.prompt` method.
Syntax highlighting
-------------------
Adding syntax highlighting is as simple as adding a lexer. All of the `Pygments
<http://pygments.org/>`_ lexers can be used after wrapping them in a
:class:`~prompt_toolkit.lexers.PygmentsLexer`. It is also possible to create a
custom lexer by implementing the :class:`~prompt_toolkit.lexers.Lexer` abstract
base class.
.. code:: python
from pygments.lexers.html import HtmlLexer
from prompt_toolkit.shortcuts import prompt
from prompt_toolkit.lexers import PygmentsLexer
text = prompt('Enter HTML: ', lexer=PygmentsLexer(HtmlLexer))
print('You said: %s' % text)
.. image:: ../images/html-input.png
The default Pygments colorscheme is included as part of the default style in
prompt_toolkit. If you want to use another Pygments style along with the lexer,
you can do the following:
.. code:: python
from pygments.lexers.html import HtmlLexer
from pygments.styles import get_style_by_name
from prompt_toolkit.shortcuts import prompt
from prompt_toolkit.lexers import PygmentsLexer
from prompt_toolkit.styles.pygments import style_from_pygments_cls
style = style_from_pygments_cls(get_style_by_name('monokai'))
text = prompt('Enter HTML: ', lexer=PygmentsLexer(HtmlLexer), style=style,
include_default_pygments_style=False)
print('You said: %s' % text)
We pass ``include_default_pygments_style=False``, because otherwise, both
styles will be merged, possibly giving slightly different colors in the outcome
for cases where where our custom Pygments style doesn't specify a color.
.. _colors:
Colors
------
The colors for syntax highlighting are defined by a
:class:`~prompt_toolkit.styles.Style` instance. By default, a neutral
built-in style is used, but any style instance can be passed to the
:func:`~prompt_toolkit.shortcuts.prompt` function. A simple way to create a
style, is by using the :meth:`~prompt_toolkit.styles.Style.from_dict`
function:
.. code:: python
from pygments.lexers.html import HtmlLexer
from prompt_toolkit.shortcuts import prompt
from prompt_toolkit.styles import Style
from prompt_toolkit.lexers import PygmentsLexer
our_style = Style.from_dict({
'pygments.comment': '#888888 bold',
'pygments.keyword': '#ff88ff bold',
})
text = prompt('Enter HTML: ', lexer=PygmentsLexer(HtmlLexer),
style=our_style)
The style dictionary is very similar to the Pygments ``styles`` dictionary,
with a few differences:
- The `roman`, `sans`, `mono` and `border` options are ignored.
- The style has a few additions: ``blink``, ``noblink``, ``reverse`` and ``noreverse``.
- Colors can be in the ``#ff0000`` format, but they can be one of the built-in
ANSI color names as well. In that case, they map directly to the 16 color
palette of the terminal.
:ref:`Read more about styling <styling>`.
Using a Pygments style
^^^^^^^^^^^^^^^^^^^^^^
All Pygments style classes can be used as well, when they are wrapped through
:func:`~prompt_toolkit.styles.style_from_pygments_cls`.
Suppose we'd like to use a Pygments style, for instance
``pygments.styles.tango.TangoStyle``, that is possible like this:
Creating a custom style could be done like this:
.. code:: python
from prompt_toolkit.shortcuts import prompt
from prompt_toolkit.styles import style_from_pygments_cls, merge_styles
from prompt_toolkit.lexers import PygmentsLexer
from pygments.styles.tango import TangoStyle
from pygments.lexers.html import HtmlLexer
our_style = merge_styles([
style_from_pygments_cls(TangoStyle),
Style.from_dict({
'pygments.comment': '#888888 bold',
'pygments.keyword': '#ff88ff bold',
})
])
text = prompt('Enter HTML: ', lexer=PygmentsLexer(HtmlLexer),
style=our_style)
Coloring the prompt itself
^^^^^^^^^^^^^^^^^^^^^^^^^^
It is possible to add some colors to the prompt itself. For this, we need to
build some :ref:`formatted text <formatted_text>`. One way of doing this is by
creating a list of style/text tuples. In the following example, we use class
names to refer to the style.
.. code:: python
from prompt_toolkit.shortcuts import prompt
from prompt_toolkit.styles import Style
style = Style.from_dict({
# User input (default text).
'': '#ff0066',
# Prompt.
'username': '#884444',
'at': '#00aa00',
'colon': '#0000aa',
'pound': '#00aa00',
'host': '#00ffff bg:#444400',
'path': 'ansicyan underline',
})
message = [
('class:username', 'john'),
('class:at', '@'),
('class:host', 'localhost'),
('class:colon', ':'),
('class:path', '/user/john'),
('class:pound', '# '),
]
text = prompt(message, style=style)
.. image:: ../images/colored-prompt.png
The `message` can be any kind of formatted text, as discussed :ref:`here
<formatted_text>`. It can also be a callable that returns some formatted text.
By default, colors are taking from the 256 color palette. If you want to have
24bit true color, this is possible by adding the ``true_color=True`` option to
the :func:`~prompt_toolkit.shortcuts.prompt.prompt` function.
.. code:: python
text = prompt(message, style=style, true_color=True)
Autocompletion
--------------
Autocompletion can be added by passing a ``completer`` parameter. This should
be an instance of the :class:`~prompt_toolkit.completion.Completer` abstract
base class. :class:`~prompt_toolkit.completion.WordCompleter` is an example of
a completer that implements that interface.
.. code:: python
from prompt_toolkit import prompt
from prompt_toolkit.completion import WordCompleter
html_completer = WordCompleter(['<html>', '<body>', '<head>', '<title>'])
text = prompt('Enter HTML: ', completer=html_completer)
print('You said: %s' % text)
:class:`~prompt_toolkit.completion.WordCompleter` is a simple completer that
completes the last word before the cursor with any of the given words.
.. image:: ../images/html-completion.png
.. note::
Note that in prompt_toolkit 2.0, the auto completion became synchronous. This
means that if it takes a long time to compute the completions, that this
will block the event loop and the input processing.
For heavy completion algorithms, it is recommended to wrap the completer in
a :class:`~prompt_toolkit.completion.ThreadedCompleter` in order to run it
in a background thread.
Nested completion
^^^^^^^^^^^^^^^^^
Sometimes you have a command line interface where the completion depends on the
previous words from the input. Examples are the CLIs from routers and switches.
A simple :class:`~prompt_toolkit.completion.WordCompleter` is not enough in
that case. We want to to be able to define completions at multiple hierarchical
levels. :class:`~prompt_toolkit.completion.NestedCompleter` solves this issue:
.. code:: python
from prompt_toolkit import prompt
from prompt_toolkit.completion import NestedCompleter
completer = NestedCompleter.from_nested_dict({
'show': {
'version': None,
'clock': None,
'ip': {
'interface': {'brief'}
}
},
'exit': None,
})
text = prompt('# ', completer=completer)
print('You said: %s' % text)
Whenever there is a ``None`` value in the dictionary, it means that there is no
further nested completion at that point. When all values of a dictionary would
be ``None``, it can also be replaced with a set.
A custom completer
^^^^^^^^^^^^^^^^^^
For more complex examples, it makes sense to create a custom completer. For
instance:
.. code:: python
from prompt_toolkit import prompt
from prompt_toolkit.completion import Completer, Completion
class MyCustomCompleter(Completer):
def get_completions(self, document, complete_event):
yield Completion('completion', start_position=0)
text = prompt('> ', completer=MyCustomCompleter())
A :class:`~prompt_toolkit.completion.Completer` class has to implement a
generator named :meth:`~prompt_toolkit.completion.Completer.get_completions`
that takes a :class:`~prompt_toolkit.document.Document` and yields the current
:class:`~prompt_toolkit.completion.Completion` instances. Each completion
contains a portion of text, and a position.
The position is used for fixing text before the cursor. Pressing the tab key
could for instance turn parts of the input from lowercase to uppercase. This
makes sense for a case insensitive completer. Or in case of a fuzzy completion,
it could fix typos. When ``start_position`` is something negative, this amount
of characters will be deleted and replaced.
Styling individual completions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Each completion can provide a custom style, which is used when it is rendered
in the completion menu or toolbar. This is possible by passing a style to each
:class:`~prompt_toolkit.completion.Completion` instance.
.. code:: python
from prompt_toolkit.completion import Completer, Completion
class MyCustomCompleter(Completer):
def get_completions(self, document, complete_event):
# Display this completion, black on yellow.
yield Completion('completion1', start_position=0,
style='bg:ansiyellow fg:ansiblack')
# Underline completion.
yield Completion('completion2', start_position=0,
style='underline')
# Specify class name, which will be looked up in the style sheet.
yield Completion('completion3', start_position=0,
style='class:special-completion')
The "colorful-prompts.py" example uses completion styling:
.. image:: ../images/colorful-completions.png
Finally, it is possible to pass :ref:`formatted text <formatted_text>` for the
``display`` attribute of a :class:`~prompt_toolkit.completion.Completion`. This
provides all the freedom you need to display the text in any possible way. It
can also be combined with the ``style`` attribute. For instance:
.. code:: python
from prompt_toolkit.completion import Completer, Completion
from prompt_toolkit.formatted_text import HTML
class MyCustomCompleter(Completer):
def get_completions(self, document, complete_event):
yield Completion(
'completion1', start_position=0,
display=HTML('<b>completion</b><ansired>1</ansired>'),
style='bg:ansiyellow')
Fuzzy completion
^^^^^^^^^^^^^^^^
If one possible completions is "django_migrations", a fuzzy completer would
allow you to get this by typing "djm" only, a subset of characters for this
string.
Prompt_toolkit ships with a :class:`~prompt_toolkit.completion.FuzzyCompleter`
and :class:`~prompt_toolkit.completion.FuzzyWordCompleter` class. These provide
the means for doing this kind of "fuzzy completion". The first one can take any
completer instance and wrap it so that it becomes a fuzzy completer. The second
one behaves like a :class:`~prompt_toolkit.completion.WordCompleter` wrapped
into a :class:`~prompt_toolkit.completion.FuzzyCompleter`.
Complete while typing
^^^^^^^^^^^^^^^^^^^^^
Autcompletions can be generated automatically while typing or when the user
presses the tab key. This can be configured with the ``complete_while_typing``
option:
.. code:: python
text = prompt('Enter HTML: ', completer=my_completer,
complete_while_typing=True)
Notice that this setting is incompatible with the ``enable_history_search``
option. The reason for this is that the up and down key bindings would conflict
otherwise. So, make sure to disable history search for this.
Asynchronous completion
^^^^^^^^^^^^^^^^^^^^^^^
When generating the completions takes a lot of time, it's better to do this in
a background thread. This is possible by wrapping the completer in a
:class:`~prompt_toolkit.completion.ThreadedCompleter`, but also by passing the
`complete_in_thread=True` argument.
.. code:: python
text = prompt('> ', completer=MyCustomCompleter(), complete_in_thread=True)
Input validation
----------------
A prompt can have a validator attached. This is some code that will check
whether the given input is acceptable and it will only return it if that's the
case. Otherwise it will show an error message and move the cursor to a given
position.
A validator should implements the :class:`~prompt_toolkit.validation.Validator`
abstract base class. This requires only one method, named ``validate`` that
takes a :class:`~prompt_toolkit.document.Document` as input and raises
:class:`~prompt_toolkit.validation.ValidationError` when the validation fails.
.. code:: python
from prompt_toolkit.validation import Validator, ValidationError
from prompt_toolkit import prompt
class NumberValidator(Validator):
def validate(self, document):
text = document.text
if text and not text.isdigit():
i = 0
# Get index of fist non numeric character.
# We want to move the cursor here.
for i, c in enumerate(text):
if not c.isdigit():
break
raise ValidationError(message='This input contains non-numeric characters',
cursor_position=i)
number = int(prompt('Give a number: ', validator=NumberValidator()))
print('You said: %i' % number)
.. image:: ../images/number-validator.png
By default, the input is only validated when the user presses the enter key,
but prompt_toolkit can also validate in real-time while typing:
.. code:: python
prompt('Give a number: ', validator=NumberValidator(),
validate_while_typing=True)
If the input validation contains some heavy CPU intensive code, but you don't
want to block the event loop, then it's recommended to wrap the validator class
in a :class:`~prompt_toolkit.validation.ThreadedValidator`.
Validator from a callable
^^^^^^^^^^^^^^^^^^^^^^^^^
Instead of implementing the :class:`~prompt_toolkit.validation.Validator`
abstract base class, it is also possible to start from a simple function and
use the :meth:`~prompt_toolkit.validation.Validator.from_callable` classmethod.
This is easier and sufficient for probably 90% of the validators. It looks as
follows:
.. code:: python
from prompt_toolkit.validation import Validator
from prompt_toolkit import prompt
def is_number(text):
return text.isdigit()
validator = Validator.from_callable(
is_number,
error_message='This input contains non-numeric characters',
move_cursor_to_end=True)
number = int(prompt('Give a number: ', validator=validator))
print('You said: %i' % number)
We define a function that takes a string, and tells whether it's valid input or
not by returning a boolean.
:meth:`~prompt_toolkit.validation.Validator.from_callable` turns that into a
:class:`~prompt_toolkit.validation.Validator` instance. Notice that setting the
cursor position is not possible this way.
History
-------
A :class:`~prompt_toolkit.history.History` object keeps track of all the
previously entered strings, so that the up-arrow can reveal previously entered
items.
The recommended way is to use a
:class:`~prompt_toolkit.shortcuts.PromptSession`, which uses an
:class:`~prompt_toolkit.history.InMemoryHistory` for the entire session by
default. The following example has a history out of the box:
.. code:: python
from prompt_toolkit import PromptSession
session = PromptSession()
while True:
session.prompt()
To persist a history to disk, use a :class:`~prompt_toolkit.history.FileHistory`
instead of the default
:class:`~prompt_toolkit.history.InMemoryHistory`. This history object can be
passed either to a :class:`~prompt_toolkit.shortcuts.PromptSession` or to the
:meth:`~prompt_toolkit.shortcuts.prompt` function. For instance:
.. code:: python
from prompt_toolkit import PromptSession
from prompt_toolkit.history import FileHistory
session = PromptSession(history=FileHistory('~/.myhistory'))
while True:
session.prompt()
Auto suggestion
---------------
Auto suggestion is a way to propose some input completions to the user like the
`fish shell <http://fishshell.com/>`_.
Usually, the input is compared to the history and when there is another entry
starting with the given text, the completion will be shown as gray text behind
the current input. Pressing the right arrow :kbd:`→` or :kbd:`c-e` will insert
this suggestion, :kbd:`alt-f` will insert the first word of the suggestion.
.. note::
When suggestions are based on the history, don't forget to share one
:class:`~prompt_toolkit.history.History` object between consecutive
:func:`~prompt_toolkit.shortcuts.prompt` calls. Using a
:class:`~prompt_toolkit.shortcuts.PromptSession` does this for you.
Example:
.. code:: python
from prompt_toolkit import PromptSession
from prompt_toolkit.history import InMemoryHistory
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
session = PromptSession()
while True:
text = session.prompt('> ', auto_suggest=AutoSuggestFromHistory())
print('You said: %s' % text)
.. image:: ../images/auto-suggestion.png
A suggestion does not have to come from the history. Any implementation of the
:class:`~prompt_toolkit.auto_suggest.AutoSuggest` abstract base class can be
passed as an argument.
Adding a bottom toolbar
-----------------------
Adding a bottom toolbar is as easy as passing a ``bottom_toolbar`` argument to
:func:`~prompt_toolkit.shortcuts.prompt`. This argument be either plain text,
:ref:`formatted text <formatted_text>` or a callable that returns plain or
formatted text.
When a function is given, it will be called every time the prompt is rendered,
so the bottom toolbar can be used to display dynamic information.
The toolbar is always erased when the prompt returns.
Here we have an example of a callable that returns an
:class:`~prompt_toolkit.formatted_text.HTML` object. By default, the toolbar
has the **reversed style**, which is why we are setting the background instead
of the foreground.
.. code:: python
from prompt_toolkit import prompt
from prompt_toolkit.formatted_text import HTML
def bottom_toolbar():
return HTML('This is a <b><style bg="ansired">Toolbar</style></b>!')
text = prompt('> ', bottom_toolbar=bottom_toolbar)
print('You said: %s' % text)
.. image:: ../images/bottom-toolbar.png
Similar, we could use a list of style/text tuples.
.. code:: python
from prompt_toolkit import prompt
from prompt_toolkit.styles import Style
def bottom_toolbar():
return [('class:bottom-toolbar', ' This is a toolbar. ')]
style = Style.from_dict({
'bottom-toolbar': '#ffffff bg:#333333',
})
text = prompt('> ', bottom_toolbar=bottom_toolbar, style=style)
print('You said: %s' % text)
The default class name is ``bottom-toolbar`` and that will also be used to fill
the background of the toolbar.
Adding a right prompt
---------------------
The :func:`~prompt_toolkit.shortcuts.prompt` function has out of the box
support for right prompts as well. People familiar to ZSH could recognise this
as the `RPROMPT` option.
So, similar to adding a bottom toolbar, we can pass an ``rprompt`` argument.
This can be either plain text, :ref:`formatted text <formatted_text>` or a
callable which returns either.
.. code:: python
from prompt_toolkit import prompt
from prompt_toolkit.styles import Style
example_style = Style.from_dict({
'rprompt': 'bg:#ff0066 #ffffff',
})
def get_rprompt():
return '<rprompt>'
answer = prompt('> ', rprompt=get_rprompt, style=example_style)
.. image:: ../images/rprompt.png
The ``get_rprompt`` function can return any kind of formatted text such as
:class:`~prompt_toolkit.formatted_text.HTML`. it is also possible to pass text
directly to the ``rprompt`` argument of the
:func:`~prompt_toolkit.shortcuts.prompt` function. It does not have to be a
callable.
Vi input mode
-------------
Prompt-toolkit supports both Emacs and Vi key bindings, similar to Readline.
The :func:`~prompt_toolkit.shortcuts.prompt` function will use Emacs bindings by
default. This is done because on most operating systems, also the Bash shell
uses Emacs bindings by default, and that is more intuitive. If however, Vi
binding are required, just pass ``vi_mode=True``.
.. code:: python
from prompt_toolkit import prompt
prompt('> ', vi_mode=True)
Adding custom key bindings
--------------------------
By default, every prompt already has a set of key bindings which implements the
usual Vi or Emacs behaviour. We can extend this by passing another
:class:`~prompt_toolkit.key_binding.KeyBindings` instance to the
``key_bindings`` argument of the :func:`~prompt_toolkit.shortcuts.prompt`
function or the :class:`~prompt_toolkit.shortcuts.PromptSession` class.
An example of a prompt that prints ``'hello world'`` when :kbd:`Control-T` is pressed.
.. code:: python
from prompt_toolkit import prompt
from prompt_toolkit.application import run_in_terminal
from prompt_toolkit.key_binding import KeyBindings
bindings = KeyBindings()
@bindings.add('c-t')
def _(event):
" Say 'hello' when `c-t` is pressed. "
def print_hello():
print('hello world')
run_in_terminal(print_hello)
@bindings.add('c-x')
def _(event):
" Exit when `c-x` is pressed. "
event.app.exit()
text = prompt('> ', key_bindings=bindings)
print('You said: %s' % text)
Note that we use
:meth:`~prompt_toolkit.application.run_in_terminal` for the first key binding.
This ensures that the output of the print-statement and the prompt don't mix
up. If the key bindings doesn't print anything, then it can be handled directly
without nesting functions.
Enable key bindings according to a condition
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Often, some key bindings can be enabled or disabled according to a certain
condition. For instance, the Emacs and Vi bindings will never be active at the
same time, but it is possible to switch between Emacs and Vi bindings at run
time.
In order to enable a key binding according to a certain condition, we have to
pass it a :class:`~prompt_toolkit.filters.Filter`, usually a
:class:`~prompt_toolkit.filters.Condition` instance. (:ref:`Read more about
filters <filters>`.)
.. code:: python
from prompt_toolkit import prompt
from prompt_toolkit.filters import Condition
from prompt_toolkit.key_binding import KeyBindings
bindings = KeyBindings()
@Condition
def is_active():
" Only activate key binding on the second half of each minute. "
return datetime.datetime.now().second > 30
@bindings.add('c-t', filter=is_active)
def _(event):
# ...
pass
prompt('> ', key_bindings=bindings)
Dynamically switch between Emacs and Vi mode
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The :class:`~prompt_toolkit.application.Application` has an ``editing_mode``
attribute. We can change the key bindings by changing this attribute from
``EditingMode.VI`` to ``EditingMode.EMACS``.
.. code:: python
from prompt_toolkit import prompt
from prompt_toolkit.application.current import get_app
from prompt_toolkit.enums import EditingMode
from prompt_toolkit.key_binding import KeyBindings
def run():
# Create a set of key bindings.
bindings = KeyBindings()
# Add an additional key binding for toggling this flag.
@bindings.add('f4')
def _(event):
" Toggle between Emacs and Vi mode. "
app = event.app
if app.editing_mode == EditingMode.VI:
app.editing_mode = EditingMode.EMACS
else:
app.editing_mode = EditingMode.VI
# Add a toolbar at the bottom to display the current input mode.
def bottom_toolbar():
" Display the current input mode. "
text = 'Vi' if get_app().editing_mode == EditingMode.VI else 'Emacs'
return [
('class:toolbar', ' [F4] %s ' % text)
]
prompt('> ', key_bindings=bindings, bottom_toolbar=bottom_toolbar)
run()
:ref:`Read more about key bindings ...<key_bindings>`
Using control-space for completion
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
An popular short cut that people sometimes use it to use control-space for
opening the autocompletion menu instead of the tab key. This can be done with
the following key binding.
.. code:: python
kb = KeyBindings()
@kb.add('c-space')
def _(event):
" Initialize autocompletion, or select the next completion. "
buff = event.app.current_buffer
if buff.complete_state:
buff.complete_next()
else:
buff.start_completion(select_first=False)
Other prompt options
--------------------
Multiline input
^^^^^^^^^^^^^^^
Reading multiline input is as easy as passing the ``multiline=True`` parameter.
.. code:: python
from prompt_toolkit import prompt
prompt('> ', multiline=True)
A side effect of this is that the enter key will now insert a newline instead
of accepting and returning the input. The user will now have to press
:kbd:`Meta+Enter` in order to accept the input. (Or :kbd:`Escape` followed by
:kbd:`Enter`.)
It is possible to specify a continuation prompt. This works by passing a
``prompt_continuation`` callable to :func:`~prompt_toolkit.shortcuts.prompt`.
This function is supposed to return :ref:`formatted text <formatted_text>`, or
a list of ``(style, text)`` tuples. The width of the returned text should not
exceed the given width. (The width of the prompt margin is defined by the
prompt.)
.. code:: python
from prompt_toolkit import prompt
def prompt_continuation(width, line_number, is_soft_wrap):
return '.' * width
# Or: return [('', '.' * width)]
prompt('multiline input> ', multiline=True,
prompt_continuation=prompt_continuation)
.. image:: ../images/multiline-input.png
Passing a default
^^^^^^^^^^^^^^^^^
A default value can be given:
.. code:: python
from prompt_toolkit import prompt
import getpass
prompt('What is your name: ', default='%s' % getpass.getuser())
Mouse support
^^^^^^^^^^^^^
There is limited mouse support for positioning the cursor, for scrolling (in
case of large multiline inputs) and for clicking in the autocompletion menu.
Enabling can be done by passing the ``mouse_support=True`` option.
.. code:: python
from prompt_toolkit import prompt
import getpass
prompt('What is your name: ', mouse_support=True)
Line wrapping
^^^^^^^^^^^^^
Line wrapping is enabled by default. This is what most people are used to and
this is what GNU Readline does. When it is disabled, the input string will
scroll horizontally.
.. code:: python
from prompt_toolkit import prompt
import getpass
prompt('What is your name: ', wrap_lines=False)
Password input
^^^^^^^^^^^^^^
When the ``is_password=True`` flag has been given, the input is replaced by
asterisks (``*`` characters).
.. code:: python
from prompt_toolkit import prompt
import getpass
prompt('Enter password: ', is_password=True)
Prompt in an `asyncio` application
----------------------------------
.. note::
New in prompt_toolkit 3.0. (In prompt_toolkit 2.0 this was possible using a
work-around).
For `asyncio <https://docs.python.org/3/library/asyncio.html>`_ applications,
it's very important to never block the eventloop. However,
:func:`~prompt_toolkit.shortcuts.prompt` is blocking, and calling this would
freeze the whole application. Asyncio actually won't even allow us to run that
function within a coroutine.
The answer is to call
:meth:`~prompt_toolkit.shortcuts.PromptSession.prompt_async` instead of
:meth:`~prompt_toolkit.shortcuts.PromptSession.prompt`. The async variation
returns a coroutines and is awaitable.
.. code:: python
from prompt_toolkit import PromptSession
from prompt_toolkit.patch_stdout import patch_stdout
async def my_coroutine():
session = PromptSession()
while True:
with patch_stdout():
result = await session.prompt_async('Say something: ')
print('You said: %s' % result)
The :func:`~prompt_toolkit.patch_stdout.patch_stdout` context manager is
optional, but it's recommended, because other coroutines could print to stdout.
This ensures that other output won't destroy the prompt.

View File

@ -1,270 +0,0 @@
.. _dialogs:
Dialogs
=======
Prompt_toolkit ships with a high level API for displaying dialogs, similar to
the Whiptail program, but in pure Python.
Message box
-----------
Use the :func:`~prompt_toolkit.shortcuts.message_dialog` function to display a
simple message box. For instance:
.. code:: python
from prompt_toolkit.shortcuts import message_dialog
message_dialog(
title='Example dialog window',
text='Do you want to continue?\nPress ENTER to quit.').run()
.. image:: ../images/dialogs/messagebox.png
Input box
---------
The :func:`~prompt_toolkit.shortcuts.input_dialog` function can display an
input box. It will return the user input as a string.
.. code:: python
from prompt_toolkit.shortcuts import input_dialog
text = input_dialog(
title='Input dialog example',
text='Please type your name:').run()
.. image:: ../images/dialogs/inputbox.png
The ``password=True`` option can be passed to the
:func:`~prompt_toolkit.shortcuts.input_dialog` function to turn this into a
password input box.
Yes/No confirmation dialog
--------------------------
The :func:`~prompt_toolkit.shortcuts.yes_no_dialog` function displays a yes/no
confirmation dialog. It will return a boolean according to the selection.
.. code:: python
from prompt_toolkit.shortcuts import yes_no_dialog
result = yes_no_dialog(
title='Yes/No dialog example',
text='Do you want to confirm?').run()
.. image:: ../images/dialogs/confirm.png
Button dialog
-------------
The :func:`~prompt_toolkit.shortcuts.button_dialog` function displays a dialog
with choices offered as buttons. Buttons are indicated as a list of tuples,
each providing the label (first) and return value if clicked (second).
.. code:: python
from prompt_toolkit.shortcuts import button_dialog
result = button_dialog(
title='Button dialog example',
text='Do you want to confirm?',
buttons=[
('Yes', True),
('No', False),
('Maybe...', None)
],
).run()
.. image:: ../images/dialogs/button.png
Radio list dialog
-----------------
The :func:`~prompt_toolkit.shortcuts.radiolist_dialog` functiom displays a dialog
with choices offered as a radio list. The values are provided as a list of tuples,
each providing the return value (first element) and the displayed value (second element).
.. code:: python
from prompt_toolkit.shortcuts import radiolist_dialog
result = radiolist_dialog(
title="RadioList dialog",
text="Which breakfast would you like ?",
values=[
("breakfast1", "Eggs and beacon"),
("breakfast2", "French breakfast"),
("breakfast3", "Equestrian breakfast")
]
).run()
Checkbox list dialog
--------------------
The :func:`~prompt_toolkit.shortcuts.checkboxlist_dialog` has the same usage and purpose than the Radiolist dialog, but allows several values to be selected and therefore returned.
.. code:: python
from prompt_toolkit.shortcuts import checkboxlist_dialog
results_array = checkboxlist_dialog(
title="CheckboxList dialog",
text="What would you like in your breakfast ?",
values=[
("eggs", "Eggs"),
("bacon", "Bacon"),
("croissants", "20 Croissants"),
("daily", "The breakfast of the day")
]
).run()
Styling of dialogs
------------------
A custom :class:`~prompt_toolkit.styles.Style` instance can be passed to all
dialogs to override the default style. Also, text can be styled by passing an
:class:`~prompt_toolkit.formatted_text.HTML` object.
.. code:: python
from prompt_toolkit.formatted_text import HTML
from prompt_toolkit.shortcuts import message_dialog
from prompt_toolkit.styles import Style
example_style = Style.from_dict({
'dialog': 'bg:#88ff88',
'dialog frame.label': 'bg:#ffffff #000000',
'dialog.body': 'bg:#000000 #00ff00',
'dialog shadow': 'bg:#00aa00',
})
message_dialog(
title=HTML('<style bg="blue" fg="white">Styled</style> '
'<style fg="ansired">dialog</style> window'),
text='Do you want to continue?\nPress ENTER to quit.',
style=example_style).run()
.. image:: ../images/dialogs/styled.png
Styling reference sheet
-----------------------
In reality, the shortcut commands presented above build a full-screen frame by using a list of components. The two tables below allow you to get the classnames available for each shortcut, therefore you will be able to provide a custom style for every element that is displayed, using the method provided above.
.. note:: All the shortcuts use the ``Dialog`` component, therefore it isn't specified explicitely below.
+--------------------------+-------------------------+
| Shortcut | Components used |
+==========================+=========================+
| ``yes_no_dialog`` | - ``Label`` |
| | - ``Button`` (x2) |
+--------------------------+-------------------------+
| ``button_dialog`` | - ``Label`` |
| | - ``Button`` |
+--------------------------+-------------------------+
| ``input_dialog`` | - ``TextArea`` |
| | - ``Button`` (x2) |
+--------------------------+-------------------------+
| ``message_dialog`` | - ``Label`` |
| | - ``Button`` |
+--------------------------+-------------------------+
| ``radiolist_dialog`` | - ``Label`` |
| | - ``RadioList`` |
| | - ``Button`` (x2) |
+--------------------------+-------------------------+
| ``checkboxlist_dialog`` | - ``Label`` |
| | - ``CheckboxList`` |
| | - ``Button`` (x2) |
+--------------------------+-------------------------+
| ``progress_dialog`` | - ``Label`` |
| | - ``TextArea`` (locked) |
| | - ``ProgressBar`` |
+--------------------------+-------------------------+
+----------------+-----------------------------+
| Components | Available classnames |
+================+=============================+
| Dialog | - ``dialog`` |
| | - ``dialog.body`` |
+----------------+-----------------------------+
| TextArea | - ``text-area`` |
| | - ``text-area.prompt`` |
+----------------+-----------------------------+
| Label | - ``label`` |
+----------------+-----------------------------+
| Button | - ``button`` |
| | - ``button.focused`` |
| | - ``button.arrow`` |
| | - ``button.text`` |
+----------------+-----------------------------+
| Frame | - ``frame`` |
| | - ``frame.border`` |
| | - ``frame.label`` |
+----------------+-----------------------------+
| Shadow | - ``shadow`` |
+----------------+-----------------------------+
| RadioList | - ``radio-list`` |
| | - ``radio`` |
| | - ``radio-checked`` |
| | - ``radio-selected`` |
+----------------+-----------------------------+
| CheckboxList | - ``checkbox-list`` |
| | - ``checkbox`` |
| | - ``checkbox-checked`` |
| | - ``checkbox-selected`` |
+----------------+-----------------------------+
| VerticalLine | - ``line`` |
| | - ``vertical-line`` |
+----------------+-----------------------------+
| HorizontalLine | - ``line`` |
| | - ``horizontal-line`` |
+----------------+-----------------------------+
| ProgressBar | - ``progress-bar`` |
| | - ``progress-bar.used`` |
+----------------+-----------------------------+
Example
_______
Let's customize the example of the ``checkboxlist_dialog``.
It uses 2 ``Button``, a ``CheckboxList`` and a ``Label``, packed inside a ``Dialog``.
Threfore we can customize each of these elements separately, using for instance:
.. code:: python
from prompt_toolkit.shortcuts import checkboxlist_dialog
from prompt_toolkit.styles import Style
results = checkboxlist_dialog(
title="CheckboxList dialog",
text="What would you like in your breakfast ?",
values=[
("eggs", "Eggs"),
("bacon", "Bacon"),
("croissants", "20 Croissants"),
("daily", "The breakfast of the day")
],
style=Style.from_dict({
'dialog': 'bg:#cdbbb3',
'button': 'bg:#bf99a4',
'checkbox': '#e8612c',
'dialog.body': 'bg:#a9cfd0',
'dialog shadow': 'bg:#c98982',
'frame.label': '#fcaca3',
'dialog.body label': '#fd8bb6',
})
).run()

View File

@ -1,411 +0,0 @@
.. _full_screen_applications:
Building full screen applications
=================================
`prompt_toolkit` can be used to create complex full screen terminal
applications. Typically, an application consists of a layout (to describe the
graphical part) and a set of key bindings.
The sections below describe the components required for full screen
applications (or custom, non full screen applications), and how to assemble
them together.
Before going through this page, it could be helpful to go through :ref:`asking
for input <asking_for_input>` (prompts) first. Many things that apply to an
input prompt, like styling, key bindings and so on, also apply to full screen
applications.
.. note::
Also remember that the ``examples`` directory of the prompt_toolkit
repository contains plenty of examples. Each example is supposed to explain
one idea. So, this as well should help you get started.
Don't hesitate to open a GitHub issue if you feel that a certain example is
missing.
A simple application
--------------------
Every prompt_toolkit application is an instance of an
:class:`~prompt_toolkit.application.Application` object. The simplest full
screen example would look like this:
.. code:: python
from prompt_toolkit import Application
app = Application(full_screen=True)
app.run()
This will display a dummy application that says "No layout specified. Press
ENTER to quit.".
.. note::
If we wouldn't set the ``full_screen`` option, the application would
not run in the alternate screen buffer, and only consume the least
amount of space required for the layout.
An application consists of several components. The most important are:
- I/O objects: 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.
You can also think of the layout as a collection of 'widgets'.
- A style: this defines what colors and underline/bold/italic styles are used
everywhere.
- A set of key bindings.
We will discuss all of these in more detail below.
I/O objects
-----------
Every :class:`~prompt_toolkit.application.Application` instance requires an I/O
objects for input and output:
- An :class:`~prompt_toolkit.input.Input` instance, which is an abstraction
of the input stream (stdin).
- An :class:`~prompt_toolkit.output.Output` instance, which is an
abstraction of the output stream, and is called by the renderer.
Both are optional and normally not needed to pass explicitly. Usually, the
default works fine.
There is a third I/O object which is also required by the application, but not
passed inside. This is the event loop, an
:class:`~prompt_toolkit.eventloop.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.
When :func:`~prompt_toolkit.application.Application.run()` is called, the event
loop will run until the application is done. An application will quit when
:func:`~prompt_toolkit.application.Application.exit()` is called.
The layout
----------
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
:class:`~prompt_toolkit.layout.Container` and
:class:`~prompt_toolkit.layout.UIControl` objects.
Examples of :class:`~prompt_toolkit.layout.Container` objects are
:class:`~prompt_toolkit.layout.VSplit` (vertical split),
:class:`~prompt_toolkit.layout.HSplit` (horizontal split) and
:class:`~prompt_toolkit.layout.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.Window` object is a special kind of
container that can contain a :class:`~prompt_toolkit.layout.UIControl`
object. The :class:`~prompt_toolkit.layout.UIControl` object is responsible
for the generation of the actual content. The
:class:`~prompt_toolkit.layout.Window` object acts as an adaptor between the
:class:`~prompt_toolkit.layout.UIControl` and other containers, but it's also
responsible for the scrolling and line wrapping of the content.
Examples of :class:`~prompt_toolkit.layout.UIControl` objects are
:class:`~prompt_toolkit.layout.BufferControl` for showing the content of an
editable/scrollable buffer, and
:class:`~prompt_toolkit.layout.FormattedTextControl` for displaying
(:ref:`formatted <formatted_text>`) text.
Normally, it is never needed to create new
:class:`~prompt_toolkit.layout.UIControl` or
:class:`~prompt_toolkit.layout.Container` classes, but instead you would
create the layout by composing instances of the existing built-ins.
- 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. Prompt_toolkit
contains a couple of widgets like
:class:`~prompt_toolkit.widgets.TextArea`,
:class:`~prompt_toolkit.widgets.Button`,
:class:`~prompt_toolkit.widgets.Frame`,
:class:`~prompt_toolkit.widgets.VerticalLine` and so on.
- The highest level abstractions can be found 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
specific use cases, like a prompt or a simple dialog window.
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::
Under the hood, the difference is:
- containers use *absolute coordinates*, and paint on a
:class:`~prompt_toolkit.layout.screen.Screen` instance.
- user controls create a :class:`~prompt_toolkit.layout.controls.UIContent`
instance. This is a collection of lines that represent the actual
content. A :class:`~prompt_toolkit.layout.controls.UIControl` is not aware
of the screen.
+---------------------------------------------+------------------------------------------------------+
| Abstract base class | Examples |
+=============================================+======================================================+
| :class:`~prompt_toolkit.layout.Container` | :class:`~prompt_toolkit.layout.HSplit` |
| | :class:`~prompt_toolkit.layout.VSplit` |
| | :class:`~prompt_toolkit.layout.FloatContainer` |
| | :class:`~prompt_toolkit.layout.Window` |
+---------------------------------------------+------------------------------------------------------+
| :class:`~prompt_toolkit.layout.UIControl` | :class:`~prompt_toolkit.layout.BufferControl` |
| | :class:`~prompt_toolkit.layout.FormattedTextControl` |
+---------------------------------------------+------------------------------------------------------+
The :class:`~prompt_toolkit.layout.Window` class itself is
particular: it is a :class:`~prompt_toolkit.layout.Container` that
can contain a :class:`~prompt_toolkit.layout.UIControl`. Thus, it's the adaptor
between the two. The :class:`~prompt_toolkit.layout.Window` class also takes
care of scrolling the content and wrapping the lines if needed.
Finally, there is the :class:`~prompt_toolkit.layout.Layout` class which wraps
the whole layout. This is responsible for keeping track of which window has the
focus.
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
vertical line:
.. code:: python
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, FormattedTextControl
from prompt_toolkit.layout.layout import Layout
buffer1 = Buffer() # Editable buffer.
root_container = VSplit([
# One window that holds the BufferControl with the default buffer on
# the left.
Window(content=BufferControl(buffer=buffer1)),
# A vertical line in the middle. We explicitly 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 window will simply fill its
# content by repeating this character.
Window(width=1, char='|'),
# Display the text 'Hello world' on the right.
Window(content=FormattedTextControl(text='Hello world')),
])
layout = Layout(root_container)
app = Application(layout=layout, full_screen=True)
app.run() # You won't be able to Exit this app
Notice that if you execute this right now, there is no way to quit this
application yet. This is something we explain in the next section below.
More complex layouts can be achieved by nesting multiple
:class:`~prompt_toolkit.layout.VSplit`,
:class:`~prompt_toolkit.layout.HSplit` and
:class:`~prompt_toolkit.layout.FloatContainer` objects.
If you want to make some part of the layout only visible when a certain
condition is satisfied, use a
:class:`~prompt_toolkit.layout.ConditionalContainer`.
Focusing windows
^^^^^^^^^^^^^^^^^
Focussing something can be done by calling the
:meth:`~prompt_toolkit.layout.Layout.focus` method. This method is very
flexible and accepts a :class:`~prompt_toolkit.layout.Window`, a
:class:`~prompt_toolkit.buffer.Buffer`, a
:class:`~prompt_toolkit.layout.controls.UIControl` and more.
In the following example, we use :func:`~prompt_toolkit.application.get_app`
for getting the active application.
.. code:: python
from prompt_toolkit.application import get_app
# This window was created earlier.
w = Window()
# ...
# Now focus it.
get_app().layout.focus(w)
Changing the focus is something which is typically done in a key binding, so
read on to see how to define key bindings.
Key bindings
------------
In order to react to user actions, we need to create a
:class:`~prompt_toolkit.key_binding.KeyBindings` object and pass
that to our :class:`~prompt_toolkit.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 focused. Both
:class:`~prompt_toolkit.layout.BufferControl`
:class:`~prompt_toolkit.layout.FormattedTextControl` take a ``key_bindings``
argument.
Global key bindings
^^^^^^^^^^^^^^^^^^^
Key bindings can be passed to the application as follows:
.. code:: python
from prompt_toolkit import Application
from prompt_toolkit.key_binding 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.KeyBindings.add` method as a decorator of
the key handler:
.. code:: python
from prompt_toolkit import Application
from prompt_toolkit.key_binding 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 `Application.run()` call.
"""
event.app.exit()
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.
:ref:`Read more about key bindings ...<key_bindings>`
Modal containers
^^^^^^^^^^^^^^^^
All container objects, like :class:`~prompt_toolkit.layout.VSplit` and
:class:`~prompt_toolkit.layout.HSplit` take a ``modal`` argument.
If this flag has been set, then key bindings from the parent account are not
taken into account if one of the children windows has the focus.
This is useful in a complex layout, where many controls have their own key
bindings, but you only want to enable the key bindings for a certain region of
the layout.
The global key bindings are always active.
More about the Window class
---------------------------
As said earlier, a :class:`~prompt_toolkit.layout.Window` is a
:class:`~prompt_toolkit.layout.Container` that wraps a
:class:`~prompt_toolkit.layout.UIControl`, like a
:class:`~prompt_toolkit.layout.BufferControl` or
:class:`~prompt_toolkit.layout.FormattedTextControl`.
.. note::
Basically, windows are the leafs in the tree structure that represent the UI.
A :class:`~prompt_toolkit.layout.Window` provides a "view" on the
:class:`~prompt_toolkit.layout.UIControl`, which provides lines of content. The
window is in the first place responsible for the line wrapping and scrolling of
the content, but there are much more options.
- Adding left or right margins. These are used for displaying scroll bars or
line numbers.
- There are the `cursorline` and `cursorcolumn` options. These allow
highlighting the line or column of the cursor position.
- Alignment of the content. The content can be left aligned, right aligned or
centered.
- Finally, the background can be filled with a default character.
More about buffers and `BufferControl`
--------------------------------------
Input processors
^^^^^^^^^^^^^^^^
A :class:`~prompt_toolkit.layout.processors.Processor` is used to postprocess
the content of a :class:`~prompt_toolkit.layout.BufferControl` before it's
displayed. It can for instance highlight matching brackets or change the
visualisation of tabs and so on.
A :class:`~prompt_toolkit.layout.processors.Processor` operates on individual
lines. Basically, it takes a (formatted) line and produces a new (formatted)
line.
Some build-in processors:
+----------------------------------------------------------------------------+-----------------------------------------------------------+
| Processor | Usage: |
+============================================================================+===========================================================+
| :class:`~prompt_toolkit.layout.processors.HighlightSearchProcessor` | Highlight the current search results. |
+----------------------------------------------------------------------------+-----------------------------------------------------------+
| :class:`~prompt_toolkit.layout.processors.HighlightSelectionProcessor` | Highlight the selection. |
+----------------------------------------------------------------------------+-----------------------------------------------------------+
| :class:`~prompt_toolkit.layout.processors.PasswordProcessor` | Display input as asterisks. (``*`` characters). |
+----------------------------------------------------------------------------+-----------------------------------------------------------+
| :class:`~prompt_toolkit.layout.processors.BracketsMismatchProcessor` | Highlight open/close mismatches for brackets. |
+----------------------------------------------------------------------------+-----------------------------------------------------------+
| :class:`~prompt_toolkit.layout.processors.BeforeInput` | Insert some text before. |
+----------------------------------------------------------------------------+-----------------------------------------------------------+
| :class:`~prompt_toolkit.layout.processors.AfterInput` | Insert some text after. |
+----------------------------------------------------------------------------+-----------------------------------------------------------+
| :class:`~prompt_toolkit.layout.processors.AppendAutoSuggestion` | Append auto suggestion text. |
+----------------------------------------------------------------------------+-----------------------------------------------------------+
| :class:`~prompt_toolkit.layout.processors.ShowLeadingWhiteSpaceProcessor` | Visualise leading whitespace. |
+----------------------------------------------------------------------------+-----------------------------------------------------------+
| :class:`~prompt_toolkit.layout.processors.ShowTrailingWhiteSpaceProcessor` | Visualise trailing whitespace. |
+----------------------------------------------------------------------------+-----------------------------------------------------------+
| :class:`~prompt_toolkit.layout.processors.TabsProcessor` | Visualise tabs as `n` spaces, or some symbols. |
+----------------------------------------------------------------------------+-----------------------------------------------------------+
A :class:`~prompt_toolkit.layout.BufferControl` takes only one processor as
input, but it is possible to "merge" multiple processors into one with the
:func:`~prompt_toolkit.layout.processors.merge_processors` function.

View File

@ -1,32 +0,0 @@
.. _gallery:
Gallery
=======
Showcase, demonstrating the possibilities of prompt_toolkit.
Ptpython, a Python REPL
^^^^^^^^^^^^^^^^^^^^^^^
The prompt:
.. image:: ../images/ptpython.png
The configuration menu of ptpython.
.. image:: ../images/ptpython-menu.png
The history page with its help. (This is a full-screen layout.)
.. image:: ../images/ptpython-history-help.png
Pyvim, a Vim clone
^^^^^^^^^^^^^^^^^^
.. image:: ../images/pyvim.png
Pymux, a terminal multiplexer (like tmux) in Python
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. image:: ../images/pymux.png

View File

@ -1,85 +0,0 @@
.. _getting_started:
Getting started
===============
Installation
------------
::
pip install prompt_toolkit
For Conda, do:
::
conda install -c https://conda.anaconda.org/conda-forge prompt_toolkit
Several use cases: prompts versus full screen terminal applications
--------------------------------------------------------------------
`prompt_toolkit` was in the first place meant to be a replacement for readline.
However, when it became more mature, we realised that all the components for
full screen applications are there and `prompt_toolkit` is very capable of
handling many use situations. `Pyvim
<http://github.com/jonathanslenders/pyvim>`_ and `pymux
<http://github.com/jonathanslenders/pymux>`_ are examples of full screen
applications.
.. image:: ../images/pyvim.png
Basically, at the core, `prompt_toolkit` has a layout engine, that supports
horizontal and vertical splits as well as floats, where each "window" can
display a user control. The API for user controls is simple yet powerful.
When `prompt_toolkit` is used as a readline replacement, (to simply read some
input from the user), it uses a rather simple built-in layout. One that
displays the default input buffer and the prompt, a float for the
autocompletions and a toolbar for input validation which is hidden by default.
For full screen applications, usually we build a custom layout ourselves.
Further, there is a very flexible key binding system that can be programmed for
all the needs of full screen applications.
A simple prompt
---------------
The following snippet is the most simple example, it uses the
:func:`~prompt_toolkit.shortcuts.prompt` function to asks the user for input
and returns the text. Just like ``(raw_)input``.
.. code:: python
from __future__ import unicode_literals
from prompt_toolkit import prompt
text = prompt('Give me some input: ')
print('You said: %s' % text)
Learning `prompt_toolkit`
-------------------------
In order to learn and understand `prompt_toolkit`, it is best to go through the
all sections in the order below. Also don't forget to have a look at all the
examples `examples
<https://github.com/jonathanslenders/python-prompt-toolkit/tree/master/examples>`_
in the repository.
- First, :ref:`learn how to print text <printing_text>`. This is important,
because it covers how to use "formatted text", which is something you'll use
whenever you want to use colors anywhere.
- Secondly, go through the :ref:`asking for input <asking_for_input>` section.
This is useful for almost any use case, even for full screen applications.
It covers autocompletions, syntax highlighting, key bindings, and so on.
- Then, learn about :ref:`dialogs`, which is easy and fun.
- Finally, learn about :ref:`full screen applications
<full_screen_applications>` and read through :ref:`the advanced topics
<advanced_topics>`.

View File

@ -1,289 +0,0 @@
.. _printing_text:
Printing (and using) formatted text
===================================
Prompt_toolkit ships with a
:func:`~prompt_toolkit.shortcuts.print_formatted_text` function that's meant to
be (as much as possible) compatible with the built-in print function, but on
top of that, also supports colors and formatting.
On Linux systems, this will output VT100 escape sequences, while on Windows it
will use Win32 API calls or VT100 sequences, depending on what is available.
.. note::
This page is also useful if you'd like to learn how to use formatting
in other places, like in a prompt or a toolbar. Just like
:func:`~prompt_toolkit.shortcuts.print_formatted_text` takes any kind
of "formatted text" as input, prompts and toolbars also accept
"formatted text".
Printing plain text
-------------------
The print function can be imported as follows:
.. code:: python
from __future__ import unicode_literals
from prompt_toolkit import print_formatted_text
print_formatted_text('Hello world')
.. note::
`prompt_toolkit` expects unicode strings everywhere. If you are using
Python 2, make sure that all strings which are passed to `prompt_toolkit`
are unicode strings (and not bytes). Either use
``from __future__ import unicode_literals`` or explicitly put a small
``'u'`` in front of every string.
You can replace the built in ``print`` function as follows, if you want to.
.. code:: python
from __future__ import unicode_literals, print_function
from prompt_toolkit import print_formatted_text as print
print('Hello world')
.. note::
If you're using Python 2, make sure to add ``from __future__ import
print_function``. Otherwise, it will not be possible to import a function
named ``print``.
.. _formatted_text:
Formatted text
--------------
There are several ways to display colors:
- By creating an :class:`~prompt_toolkit.formatted_text.HTML` object.
- By creating an :class:`~prompt_toolkit.formatted_text.ANSI` object that
contains ANSI escape sequences.
- By creating a list of ``(style, text)`` tuples.
- By creating a list of ``(pygments.Token, text)`` tuples, and wrapping it in
:class:`~prompt_toolkit.formatted_text.PygmentsTokens`.
An instance of any of these four kinds of objects is called "formatted text".
There are various places in prompt toolkit, where we accept not just plain text
(as a strings), but also formatted text.
HTML
^^^^
:class:`~prompt_toolkit.formatted_text.HTML` can be used to indicate that a
string contains HTML-like formatting. It recognizes the basic tags for bold,
italic and underline: ``<b>``, ``<i>`` and ``<u>``.
.. code:: python
from __future__ import unicode_literals, print_function
from prompt_toolkit import print_formatted_text, HTML
print_formatted_text(HTML('<b>This is bold</b>'))
print_formatted_text(HTML('<i>This is italic</i>'))
print_formatted_text(HTML('<u>This is underlined</u>'))
Further, it's possible to use tags for foreground colors:
.. code:: python
# Colors from the ANSI palette.
print_formatted_text(HTML('<ansired>This is red</ansired>'))
print_formatted_text(HTML('<ansigreen>This is green</ansigreen>'))
# Named colors (256 color palette, or true color, depending on the output).
print_formatted_text(HTML('<skyblue>This is sky blue</skyblue>'))
print_formatted_text(HTML('<seagreen>This is sea green</seagreen>'))
print_formatted_text(HTML('<violet>This is violet</violet>'))
Both foreground and background colors can also be specified setting the `fg`
and `bg` attributes of any HTML tag:
.. code:: python
# Colors from the ANSI palette.
print_formatted_text(HTML('<aaa fg="ansiwhite" bg="ansigreen">White on green</aaa>'))
Underneath, all HTML tags are mapped to classes from a stylesheet, so you can
assign a style for a custom tag.
.. code:: python
from __future__ import unicode_literals, print_function
from prompt_toolkit import print_formatted_text, HTML
from prompt_toolkit.styles import Style
style = Style.from_dict({
'aaa': '#ff0066',
'bbb': '#44ff00 italic',
})
print_formatted_text(HTML('<aaa>Hello</aaa> <bbb>world</bbb>!'), style=style)
ANSI
^^^^
Some people like to use the VT100 ANSI escape sequences to generate output.
Natively, this is however only supported on VT100 terminals, but prompt_toolkit
can parse these, and map them to formatted text instances. This means that they
will work on Windows as well. The :class:`~prompt_toolkit.formatted_text.ANSI`
class takes care of that.
.. code:: python
from __future__ import unicode_literals, print_function
from prompt_toolkit import print_formatted_text, ANSI
print_formatted_text(ANSI('\x1b[31mhello \x1b[32mworld'))
Keep in mind that even on a Linux VT100 terminal, the final output produced by
prompt_toolkit, is not necessarily exactly the same. Depending on the color
depth, it is possible that colors are mapped to different colors, and unknown
tags will be removed.
(style, text) tuples
^^^^^^^^^^^^^^^^^^^^
Internally, both :class:`~prompt_toolkit.formatted_text.HTML` and
:class:`~prompt_toolkit.formatted_text.ANSI` objects are mapped to a list of
``(style, text)`` tuples. It is however also possible to create such a list
manually with :class:`~prompt_toolkit.formatted_text.FormattedText` class.
This is a little more verbose, but it's probably the most powerful
way of expressing formatted text.
.. code:: python
from __future__ import unicode_literals, print_function
from prompt_toolkit import print_formatted_text
from prompt_toolkit.formatted_text import FormattedText
text = FormattedText([
('#ff0066', 'Hello'),
('', ' '),
('#44ff00 italic', 'World'),
])
print_formatted_text(text)
Similar to the :class:`~prompt_toolkit.formatted_text.HTML` example, it is also
possible to use class names, and separate the styling in a style sheet.
.. code:: python
from __future__ import unicode_literals, print_function
from prompt_toolkit import print_formatted_text
from prompt_toolkit.formatted_text import FormattedText
from prompt_toolkit.styles import Style
# The text.
text = FormattedText([
('class:aaa', 'Hello'),
('', ' '),
('class:bbb', 'World'),
])
# The style sheet.
style = Style.from_dict({
'aaa': '#ff0066',
'bbb': '#44ff00 italic',
})
print_formatted_text(text, style=style)
Pygments ``(Token, text)`` tuples
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
When you have a list of `Pygments <http://pygments.org/>`_ ``(Token, text)``
tuples, then these can be printed by wrapping them in a
:class:`~prompt_toolkit.formatted_text.PygmentsTokens` object.
.. code:: python
from pygments.token import Token
from prompt_toolkit import print_formatted_text
from prompt_toolkit.formatted_text import PygmentsTokens
text = [
(Token.Keyword, 'print'),
(Token.Punctuation, '('),
(Token.Literal.String.Double, '"'),
(Token.Literal.String.Double, 'hello'),
(Token.Literal.String.Double, '"'),
(Token.Punctuation, ')'),
(Token.Text, '\n'),
]
print_formatted_text(PygmentsTokens(text))
Similarly, it is also possible to print the output of a Pygments lexer:
.. code:: python
import pygments
from pygments.token import Token
from pygments.lexers.python import PythonLexer
from prompt_toolkit.formatted_text import PygmentsTokens
from prompt_toolkit import print_formatted_text
# Printing the output of a pygments lexer.
tokens = list(pygments.lex('print("Hello")', lexer=PythonLexer()))
print_formatted_text(PygmentsTokens(tokens))
Prompt_toolkit ships with a default colorscheme which styles it just like
Pygments would do, but if you'd like to change the colors, keep in mind that
Pygments tokens map to classnames like this:
+-----------------------------------+---------------------------------------------+
| pygments.Token | prompt_toolkit classname |
+===================================+=============================================+
| - ``Token.Keyword`` | - ``"class:pygments.keyword"`` |
| - ``Token.Punctuation`` | - ``"class:pygments.punctuation"`` |
| - ``Token.Literal.String.Double`` | - ``"class:pygments.literal.string.double"``|
| - ``Token.Text`` | - ``"class:pygments.text"`` |
| - ``Token`` | - ``"class:pygments"`` |
+-----------------------------------+---------------------------------------------+
A classname like ``pygments.literal.string.double`` is actually decomposed in
the following four classnames: ``pygments``, ``pygments.literal``,
``pygments.literal.string`` and ``pygments.literal.string.double``. The final
style is computed by combining the style for these four classnames. So,
changing the style from these Pygments tokens can be done as follows:
.. code:: python
from prompt_toolkit.styles import Style
style = Style.from_dict({
'pygments.keyword': 'underline',
'pygments.literal.string': 'bg:#00ff00 #ffffff',
})
print_formatted_text(PygmentsTokens(tokens), style=style)
to_formatted_text
^^^^^^^^^^^^^^^^^
A useful function to know about is
:func:`~prompt_toolkit.formatted_text.to_formatted_text`. This ensures that the
given input is valid formatted text. While doing so, an additional style can be
applied as well.
.. code:: python
from prompt_toolkit.formatted_text import to_formatted_text, HTML
from prompt_toolkit import print_formatted_text
html = HTML('<aaa>Hello</aaa> <bbb>world</bbb>!')
text = to_formatted_text(html, style='class:my_html bg:#00ff00 italic')
print_formatted_text(text)

View File

@ -1,246 +0,0 @@
.. _progress_bars:
Progress bars
=============
Prompt_toolkit ships with a high level API for displaying progress bars,
inspired by `tqdm <https://github.com/tqdm/tqdm>`_
.. warning::
The API for the prompt_toolkit progress bars is still very new and can
possibly change in the future. It is usable and tested, but keep this in
mind when upgrading.
Remember that the examples directory of the prompt_toolkit repository ships
with many progress bar examples as well.
Simple progress bar
-------------------
Creating a new progress bar can be done by calling the
:class:`~prompt_toolkit.shortcuts.ProgressBar` context manager.
The progress can be displayed for any iterable. This works by wrapping the
iterable (like ``range``) with the
:class:`~prompt_toolkit.shortcuts.ProgressBar` context manager itself. This
way, the progress bar knows when the next item is consumed by the forloop and
when progress happens.
.. code:: python
from prompt_toolkit.shortcuts import ProgressBar
import time
with ProgressBar() as pb:
for i in pb(range(800)):
time.sleep(.01)
.. image:: ../images/progress-bars/simple-progress-bar.png
Keep in mind that not all iterables can report their total length. This happens
with a typical generator. In that case, you can still pass the total as follows
in order to make displaying the progress possible:
.. code:: python
def some_iterable():
yield ...
with ProgressBar() as pb:
for i in pb(some_iterable, total=1000):
time.sleep(.01)
Multiple parallel tasks
-----------------------
A prompt_toolkit :class:`~prompt_toolkit.shortcuts.ProgressBar` can display the
progress of multiple tasks running in parallel. Each task can run in a separate
thread and the :class:`~prompt_toolkit.shortcuts.ProgressBar` user interface
runs in its own thread.
Notice that we set the "daemon" flag for both threads that run the tasks. This
is because control-c will stop the progress and quit our application. We don't
want the application to wait for the background threads to finish. Whether you
want this depends on the application.
.. code:: python
from prompt_toolkit.shortcuts import ProgressBar
import time
import threading
with ProgressBar() as pb:
# Two parallel tasks.
def task_1():
for i in pb(range(100)):
time.sleep(.05)
def task_2():
for i in pb(range(150)):
time.sleep(.08)
# Start threads.
t1 = threading.Thread(target=task_1)
t2 = threading.Thread(target=task_2)
t1.daemon = True
t2.daemon = True
t1.start()
t2.start()
# Wait for the threads to finish. We use a timeout for the join() call,
# because on Windows, join cannot be interrupted by Control-C or any other
# signal.
for t in [t1, t2]:
while t.is_alive():
t.join(timeout=.5)
.. image:: ../images/progress-bars/two-tasks.png
Adding a title and label
------------------------
Each progress bar can have one title, and for each task an individual label.
Both the title and the labels can be :ref:`formatted text <formatted_text>`.
.. code:: python
from prompt_toolkit.shortcuts import ProgressBar
from prompt_toolkit.formatted_text import HTML
import time
title = HTML('Downloading <style bg="yellow" fg="black">4 files...</style>')
label = HTML('<ansired>some file</ansired>: ')
with ProgressBar(title=title) as pb:
for i in pb(range(800), label=label):
time.sleep(.01)
.. image:: ../images/progress-bars/colored-title-and-label.png
Formatting the progress bar
---------------------------
The visualisation of a :class:`~prompt_toolkit.shortcuts.ProgressBar` can be
customized by using a different sequence of formatters. The default formatting
looks something like this:
.. code:: python
from prompt_toolkit.shortcuts.progress_bar.formatters import *
default_formatting = [
Label(),
Text(' '),
Percentage(),
Text(' '),
Bar(),
Text(' '),
Progress(),
Text(' '),
Text('eta [', style='class:time-left'),
TimeLeft(),
Text(']', style='class:time-left'),
Text(' '),
]
That sequence of
:class:`~prompt_toolkit.shortcuts.progress_bar.formatters.Formatter` can be
passed to the `formatter` argument of
:class:`~prompt_toolkit.shortcuts.ProgressBar`. So, we could change this and
modify the progress bar to look like an apt-get style progress bar:
.. code:: python
from prompt_toolkit.shortcuts import ProgressBar
from prompt_toolkit.styles import Style
from prompt_toolkit.shortcuts.progress_bar import formatters
import time
style = Style.from_dict({
'label': 'bg:#ffff00 #000000',
'percentage': 'bg:#ffff00 #000000',
'current': '#448844',
'bar': '',
})
custom_formatters = [
formatters.Label(),
formatters.Text(': [', style='class:percentage'),
formatters.Percentage(),
formatters.Text(']', style='class:percentage'),
formatters.Text(' '),
formatters.Bar(sym_a='#', sym_b='#', sym_c='.'),
formatters.Text(' '),
]
with ProgressBar(style=style, formatters=custom_formatters) as pb:
for i in pb(range(1600), label='Installing'):
time.sleep(.01)
.. image:: ../images/progress-bars/apt-get.png
Adding key bindings and toolbar
-------------------------------
Like other prompt_toolkit applications, we can add custom key bindings, by
passing a :class:`~prompt_toolkit.key_binding.KeyBindings` object:
.. code:: python
from prompt_toolkit import HTML
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.patch_stdout import patch_stdout
from prompt_toolkit.shortcuts import ProgressBar
import time
bottom_toolbar = HTML(' <b>[f]</b> Print "f" <b>[x]</b> Abort.')
# Create custom key bindings first.
kb = KeyBindings()
cancel = [False]
@kb.add('f')
def _(event):
print('You pressed `f`.')
@kb.add('x')
def _(event):
" Send Abort (control-c) signal. "
cancel[0] = True
os.kill(os.getpid(), signal.SIGINT)
# Use `patch_stdout`, to make sure that prints go above the
# application.
with patch_stdout():
with ProgressBar(key_bindings=kb, bottom_toolbar=bottom_toolbar) as pb:
for i in pb(range(800)):
time.sleep(.01)
# Stop when the cancel flag has been set.
if cancel[0]:
break
Notice that we use :func:`~prompt_toolkit.patch_stdout.patch_stdout` to make
printing text possible while the progress bar is displayed. This ensures that
printing happens above the progress bar.
Further, when "x" is pressed, we set a cancel flag, which stops the progress.
It would also be possible to send `SIGINT` to the mean thread, but that's not
always considered a clean way of cancelling something.
In the example above, we also display a toolbar at the bottom which shows the
key bindings.
.. image:: ../images/progress-bars/custom-key-bindings.png
:ref:`Read more about key bindings ...<key_bindings>`

View File

@ -1,282 +0,0 @@
Reference
=========
Application
-----------
.. automodule:: prompt_toolkit.application
:members: Application, get_app, set_app, NoRunningApplicationError,
DummyApplication, run_in_terminal, run_coroutine_in_terminal
Formatted text
--------------
.. automodule:: prompt_toolkit.formatted_text
:members:
Buffer
------
.. automodule:: prompt_toolkit.buffer
:members:
Selection
---------
.. automodule:: prompt_toolkit.selection
:members:
Clipboard
---------
.. automodule:: prompt_toolkit.clipboard
:members: Clipboard, ClipboardData, DummyClipboard, DynamicClipboard, InMemoryClipboard
.. automodule:: prompt_toolkit.clipboard.pyperclip
:members:
Auto completion
---------------
.. automodule:: prompt_toolkit.completion
:members:
Document
--------
.. automodule:: prompt_toolkit.document
:members:
Enums
-----
.. automodule:: prompt_toolkit.enums
:members:
History
-------
.. automodule:: prompt_toolkit.history
:members:
Keys
----
.. automodule:: prompt_toolkit.keys
:members:
Style
-----
.. automodule:: prompt_toolkit.styles
:members: Attrs, ANSI_COLOR_NAMES, BaseStyle, DummyStyle, DynamicStyle,
Style, Priority, merge_styles, style_from_pygments_cls,
style_from_pygments_dict, pygments_token_to_classname, NAMED_COLORS
.. automodule:: prompt_toolkit.styles
:members: StyleTransformation, SwapLightAndDarkStyleTransformation,
AdjustBrightnessStyleTransformation, merge_style_transformations,
DummyStyleTransformation, ConditionalStyleTransformation,
DynamicStyleTransformation
Shortcuts
---------
.. automodule:: prompt_toolkit.shortcuts
:members: prompt, PromptSession, confirm, CompleteStyle,
create_confirm_session, clear, clear_title, print_formatted_text,
set_title, ProgressBar, input_dialog, message_dialog, progress_dialog,
radiolist_dialog, yes_no_dialog, button_dialog
.. automodule:: prompt_toolkit.shortcuts.progress_bar.formatters
:members:
Validation
----------
.. automodule:: prompt_toolkit.validation
:members:
Auto suggestion
---------------
.. automodule:: prompt_toolkit.auto_suggest
:members:
Renderer
--------
.. automodule:: prompt_toolkit.renderer
:members:
Lexers
------
.. automodule:: prompt_toolkit.lexers
:members:
Layout
------
The layout class itself
^^^^^^^^^^^^^^^^^^^^^^^
.. automodule:: prompt_toolkit.layout
:members: Layout, InvalidLayoutError, walk
Containers
^^^^^^^^^^
.. automodule:: prompt_toolkit.layout
:members: Container, HSplit, VSplit, FloatContainer, Float, Window,
WindowAlign, ConditionalContainer, ScrollOffsets, ColorColumn,
to_container, to_window, is_container, HorizontalAlign, VerticalAlign
Controls
^^^^^^^^
.. automodule:: prompt_toolkit.layout
:members: BufferControl, SearchBufferControl, DummyControl,
FormattedTextControl, UIControl, UIContent
Other
^^^^^
.. automodule:: prompt_toolkit.layout
:members: Dimension, Margin, NumberedMargin, ScrollbarMargin,
ConditionalMargin, PromptMargin, CompletionsMenu,
MultiColumnCompletionsMenu
.. automodule:: prompt_toolkit.layout.processors
:members:
.. automodule:: prompt_toolkit.layout.utils
:members:
.. automodule:: prompt_toolkit.layout.screen
:members:
Widgets
-------
.. automodule:: prompt_toolkit.widgets
:members: TextArea, Label, Button, Frame, Shadow, Box, VerticalLine,
HorizontalLine, RadioList, Checkbox, ProgressBar, CompletionsToolbar,
FormattedTextToolbar, SearchToolbar, SystemToolbar, ValidationToolbar,
MenuContainer, MenuItem
Filters
-------
.. automodule:: prompt_toolkit.filters
:members:
.. autoclass:: prompt_toolkit.filters.Filter
:members:
.. autoclass:: prompt_toolkit.filters.Condition
:members:
.. automodule:: prompt_toolkit.filters.utils
:members:
.. automodule:: prompt_toolkit.filters.app
:members:
Key binding
-----------
.. automodule:: prompt_toolkit.key_binding
:members: KeyBindingsBase, KeyBindings, ConditionalKeyBindings,
merge_key_bindings, DynamicKeyBindings
.. automodule:: prompt_toolkit.key_binding.defaults
:members:
.. automodule:: prompt_toolkit.key_binding.vi_state
:members:
.. automodule:: prompt_toolkit.key_binding.key_processor
:members:
Eventloop
---------
.. automodule:: prompt_toolkit.eventloop
:members: EventLoop, get_traceback_from_context, From, Return,
ensure_future, create_event_loop, create_asyncio_event_loop,
get_event_loop, set_event_loop, run_in_executor, call_from_executor,
run_until_complete, Future, InvalidStateError
.. automodule:: prompt_toolkit.eventloop.posix
:members:
.. automodule:: prompt_toolkit.eventloop.win32
:members:
.. automodule:: prompt_toolkit.eventloop.asyncio_win32
:members:
.. automodule:: prompt_toolkit.eventloop.asyncio_posix
:members:
Input
-----
.. automodule:: prompt_toolkit.input
:members: Input, DummyInput, create_input, get_default_input, set_default_input
.. automodule:: prompt_toolkit.input.vt100
:members:
.. automodule:: prompt_toolkit.input.vt100_parser
:members:
.. automodule:: prompt_toolkit.input.ansi_escape_sequences
:members:
.. automodule:: prompt_toolkit.input.win32
:members:
Output
------
.. automodule:: prompt_toolkit.output
:members: Output, DummyOutput, ColorDepth, create_output,
get_default_output, set_default_output
.. automodule:: prompt_toolkit.output.vt100
:members:
.. automodule:: prompt_toolkit.output.win32
:members:
Patch stdout
------------
.. automodule:: prompt_toolkit.patch_stdout
:members: patch_stdout, StdoutProxy

View File

@ -1,10 +0,0 @@
.. _tutorials:
Tutorials
=========
.. toctree::
:caption: Contents:
:maxdepth: 1
repl

View File

@ -1,347 +0,0 @@
.. _tutorial_repl:
Tutorial: Build an SQLite REPL
==============================
The aim of this tutorial is to build an interactive command line interface for
an SQLite database using prompt_toolkit_.
First, install the library using pip, if you haven't done this already.
.. code::
pip install prompt_toolkit
Read User Input
---------------
Let's start accepting input using the
:func:`~prompt_toolkit.shortcuts.prompt()` function. This will ask the user for
input, and echo back whatever the user typed. We wrap it in a ``main()``
function as a good practise.
.. code:: python
from __future__ import unicode_literals
from prompt_toolkit import prompt
def main():
text = prompt('> ')
print('You entered:', text)
if __name__ == '__main__':
main()
.. image:: ../../images/repl/sqlite-1.png
Loop The REPL
-------------
Now we want to call the :meth:`~prompt_toolkit.shortcuts.PromptSession.prompt`
method in a loop. In order to keep the history, the easiest way to do it is to
use a :class:`~prompt_toolkit.shortcuts.PromptSession`. This uses an
:class:`~prompt_toolkit.history.InMemoryHistory` underneath that keeps track of
the history, so that if the user presses the up-arrow, he'll see the previous
entries.
The :meth:`~prompt_toolkit.shortcuts.PromptSession.prompt` method raises
``KeyboardInterrupt`` when ControlC has been pressed and ``EOFError`` when
ControlD has been pressed. This is what people use for cancelling commands and
exiting in a REPL. The try/except below handles these error conditions and make
sure that we go to the next iteration of the loop or quit the loop
respectively.
.. code:: python
from __future__ import unicode_literals
from prompt_toolkit import PromptSession
def main():
session = PromptSession()
while True:
try:
text = session.prompt('> ')
except KeyboardInterrupt:
continue
except EOFError:
break
else:
print('You entered:', text)
print('GoodBye!')
if __name__ == '__main__':
main()
.. image:: ../../images/repl/sqlite-2.png
Syntax Highlighting
-------------------
This is where things get really interesting. Let's step it up a notch by adding
syntax highlighting to the user input. We know that users will be entering SQL
statements, so we can leverage the Pygments_ library for coloring the input.
The ``lexer`` parameter allows us to set the syntax lexer. We're going to use
the ``SqlLexer`` from the Pygments_ library for highlighting.
Notice that in order to pass a Pygments lexer to prompt_toolkit, it needs to be
wrapped into a :class:`~prompt_toolkit.lexers.PygmentsLexer`.
.. code:: python
from __future__ import unicode_literals
from prompt_toolkit import PromptSession
from prompt_toolkit.lexers import PygmentsLexer
from pygments.lexers.sql import SqlLexer
def main():
session = PromptSession(lexer=PygmentsLexer(SqlLexer))
while True:
try:
text = session.prompt('> ')
except KeyboardInterrupt:
continue
except EOFError:
break
else:
print('You entered:', text)
print('GoodBye!')
if __name__ == '__main__':
main()
.. image:: ../../images/repl/sqlite-3.png
Auto-completion
---------------
Now we are going to add auto completion. We'd like to display a drop down menu
of `possible keywords <https://www.sqlite.org/lang_keywords.html>`_ when the
user starts typing.
We can do this by creating an `sql_completer` object from the
:class:`~prompt_toolkit.completion.WordCompleter` class, defining a set of
`keywords` for the auto-completion.
Like the lexer, this ``sql_completer`` instance can be passed to either the
:class:`~prompt_toolkit.shortcuts.PromptSession` class or the
:meth:`~prompt_toolkit.shortcuts.PromptSession.prompt` method.
.. code:: python
from __future__ import unicode_literals
from prompt_toolkit import PromptSession
from prompt_toolkit.completion import WordCompleter
from prompt_toolkit.lexers import PygmentsLexer
from pygments.lexers.sql import SqlLexer
sql_completer = WordCompleter([
'abort', 'action', 'add', 'after', 'all', 'alter', 'analyze', 'and',
'as', 'asc', 'attach', 'autoincrement', 'before', 'begin', 'between',
'by', 'cascade', 'case', 'cast', 'check', 'collate', 'column',
'commit', 'conflict', 'constraint', 'create', 'cross', 'current_date',
'current_time', 'current_timestamp', 'database', 'default',
'deferrable', 'deferred', 'delete', 'desc', 'detach', 'distinct',
'drop', 'each', 'else', 'end', 'escape', 'except', 'exclusive',
'exists', 'explain', 'fail', 'for', 'foreign', 'from', 'full', 'glob',
'group', 'having', 'if', 'ignore', 'immediate', 'in', 'index',
'indexed', 'initially', 'inner', 'insert', 'instead', 'intersect',
'into', 'is', 'isnull', 'join', 'key', 'left', 'like', 'limit',
'match', 'natural', 'no', 'not', 'notnull', 'null', 'of', 'offset',
'on', 'or', 'order', 'outer', 'plan', 'pragma', 'primary', 'query',
'raise', 'recursive', 'references', 'regexp', 'reindex', 'release',
'rename', 'replace', 'restrict', 'right', 'rollback', 'row',
'savepoint', 'select', 'set', 'table', 'temp', 'temporary', 'then',
'to', 'transaction', 'trigger', 'union', 'unique', 'update', 'using',
'vacuum', 'values', 'view', 'virtual', 'when', 'where', 'with',
'without'], ignore_case=True)
def main():
session = PromptSession(
lexer=PygmentsLexer(SqlLexer), completer=sql_completer)
while True:
try:
text = session.prompt('> ')
except KeyboardInterrupt:
continue
except EOFError:
break
else:
print('You entered:', text)
print('GoodBye!')
if __name__ == '__main__':
main()
.. image:: ../../images/repl/sqlite-4.png
In about 30 lines of code we got ourselves an auto completing, syntax
highlighting REPL. Let's make it even better.
Styling the menus
-----------------
If we want, we can now change the colors of the completion menu. This is
possible by creating a :class:`~prompt_toolkit.styles.Style` instance and
passing it to the :meth:`~prompt_toolkit.shortcuts.PromptSession.prompt`
function.
.. code:: python
from __future__ import unicode_literals
from prompt_toolkit import PromptSession
from prompt_toolkit.completion import WordCompleter
from prompt_toolkit.lexers import PygmentsLexer
from prompt_toolkit.styles import Style
from pygments.lexers.sql import SqlLexer
sql_completer = WordCompleter([
'abort', 'action', 'add', 'after', 'all', 'alter', 'analyze', 'and',
'as', 'asc', 'attach', 'autoincrement', 'before', 'begin', 'between',
'by', 'cascade', 'case', 'cast', 'check', 'collate', 'column',
'commit', 'conflict', 'constraint', 'create', 'cross', 'current_date',
'current_time', 'current_timestamp', 'database', 'default',
'deferrable', 'deferred', 'delete', 'desc', 'detach', 'distinct',
'drop', 'each', 'else', 'end', 'escape', 'except', 'exclusive',
'exists', 'explain', 'fail', 'for', 'foreign', 'from', 'full', 'glob',
'group', 'having', 'if', 'ignore', 'immediate', 'in', 'index',
'indexed', 'initially', 'inner', 'insert', 'instead', 'intersect',
'into', 'is', 'isnull', 'join', 'key', 'left', 'like', 'limit',
'match', 'natural', 'no', 'not', 'notnull', 'null', 'of', 'offset',
'on', 'or', 'order', 'outer', 'plan', 'pragma', 'primary', 'query',
'raise', 'recursive', 'references', 'regexp', 'reindex', 'release',
'rename', 'replace', 'restrict', 'right', 'rollback', 'row',
'savepoint', 'select', 'set', 'table', 'temp', 'temporary', 'then',
'to', 'transaction', 'trigger', 'union', 'unique', 'update', 'using',
'vacuum', 'values', 'view', 'virtual', 'when', 'where', 'with',
'without'], ignore_case=True)
style = Style.from_dict({
'completion-menu.completion': 'bg:#008888 #ffffff',
'completion-menu.completion.current': 'bg:#00aaaa #000000',
'scrollbar.background': 'bg:#88aaaa',
'scrollbar.button': 'bg:#222222',
})
def main():
session = PromptSession(
lexer=PygmentsLexer(SqlLexer), completer=sql_completer, style=style)
while True:
try:
text = session.prompt('> ')
except KeyboardInterrupt:
continue
except EOFError:
break
else:
print('You entered:', text)
print('GoodBye!')
if __name__ == '__main__':
main()
.. image:: ../../images/repl/sqlite-5.png
All that's left is hooking up the sqlite backend, which is left as an exercise
for the reader. Just kidding... Keep reading.
Hook up Sqlite
--------------
This step is the final step to make the SQLite REPL actually work. It's time
to relay the input to SQLite.
Obviously I haven't done the due diligence to deal with the errors. But it
gives a good idea of how to get started.
.. code:: python
#!/usr/bin/env python
from __future__ import unicode_literals
import sys
import sqlite3
from prompt_toolkit import PromptSession
from prompt_toolkit.completion import WordCompleter
from prompt_toolkit.lexers import PygmentsLexer
from prompt_toolkit.styles import Style
from pygments.lexers.sql import SqlLexer
sql_completer = WordCompleter([
'abort', 'action', 'add', 'after', 'all', 'alter', 'analyze', 'and',
'as', 'asc', 'attach', 'autoincrement', 'before', 'begin', 'between',
'by', 'cascade', 'case', 'cast', 'check', 'collate', 'column',
'commit', 'conflict', 'constraint', 'create', 'cross', 'current_date',
'current_time', 'current_timestamp', 'database', 'default',
'deferrable', 'deferred', 'delete', 'desc', 'detach', 'distinct',
'drop', 'each', 'else', 'end', 'escape', 'except', 'exclusive',
'exists', 'explain', 'fail', 'for', 'foreign', 'from', 'full', 'glob',
'group', 'having', 'if', 'ignore', 'immediate', 'in', 'index',
'indexed', 'initially', 'inner', 'insert', 'instead', 'intersect',
'into', 'is', 'isnull', 'join', 'key', 'left', 'like', 'limit',
'match', 'natural', 'no', 'not', 'notnull', 'null', 'of', 'offset',
'on', 'or', 'order', 'outer', 'plan', 'pragma', 'primary', 'query',
'raise', 'recursive', 'references', 'regexp', 'reindex', 'release',
'rename', 'replace', 'restrict', 'right', 'rollback', 'row',
'savepoint', 'select', 'set', 'table', 'temp', 'temporary', 'then',
'to', 'transaction', 'trigger', 'union', 'unique', 'update', 'using',
'vacuum', 'values', 'view', 'virtual', 'when', 'where', 'with',
'without'], ignore_case=True)
style = Style.from_dict({
'completion-menu.completion': 'bg:#008888 #ffffff',
'completion-menu.completion.current': 'bg:#00aaaa #000000',
'scrollbar.background': 'bg:#88aaaa',
'scrollbar.button': 'bg:#222222',
})
def main(database):
connection = sqlite3.connect(database)
session = PromptSession(
lexer=PygmentsLexer(SqlLexer), completer=sql_completer, style=style)
while True:
try:
text = session.prompt('> ')
except KeyboardInterrupt:
continue # Control-C pressed. Try again.
except EOFError:
break # Control-D pressed.
with connection:
try:
messages = connection.execute(text)
except Exception as e:
print(repr(e))
else:
for message in messages:
print(message)
print('GoodBye!')
if __name__ == '__main__':
if len(sys.argv) < 2:
db = ':memory:'
else:
db = sys.argv[1]
main(db)
.. image:: ../../images/repl/sqlite-6.png
I hope that gives an idea of how to get started on building command line
interfaces.
The End.
.. _prompt_toolkit: https://github.com/jonathanslenders/python-prompt-toolkit
.. _Pygments: http://pygments.org/

View File

@ -1,221 +0,0 @@
.. _upgrading_2_0:
Upgrading to prompt_toolkit 2.0
===============================
Prompt_toolkit 2.0 is not compatible with 1.0, however you probably want to
upgrade your applications. This page explains why we have these differences and
how to upgrade.
If you experience some difficulties or you feel that some information is
missing from this page, don't hesitate to open a GitHub issue for help.
Why all these breaking changes?
-------------------------------
After more and more custom prompt_toolkit applications were developed, it
became clear that prompt_toolkit 1.0 was not flexible enough for certain use
cases. Mostly, the development of full screen applications was not really
natural. All the important components, like the rendering, key bindings, input
and output handling were present, but the API was in the first place designed
for simple command line prompts. This was mostly notably in the following two
places:
- First, there was the focus which was always pointing to a
:class:`~prompt_toolkit.buffer.Buffer` (or text input widget), but in full
screen applications there are other widgets, like menus and buttons which
can be focused.
- And secondly, it was impossible to make reusable UI components. All the key
bindings for the entire applications were stored together in one
``KeyBindings`` object, and similar, all
:class:`~prompt_toolkit.buffer.Buffer` objects were stored together in one
dictionary. This didn't work well. You want reusable components to define
their own key bindings and everything. It's the idea of encapsulation.
For simple prompts, the changes wouldn't be that invasive, but given that there
would be some, I took the opportunity to fix a couple of other things. For
instance:
- In prompt_toolkit 1.0, we translated `\\r` into `\\n` during the input
processing. This was not a good idea, because some people wanted to handle
these keys individually. This makes sense if you keep in mind that they
correspond to `Control-M` and `Control-J`. However, we couldn't fix this
without breaking everyone's enter key, which happens to be the most important
key in prompts.
Given that we were going to break compatibility anyway, we changed a couple of
other important things that effect both simple prompt applications and
full screen applications. These are the most important:
- We no longer depend on Pygments for styling. While we like Pygments, it was
not flexible enough to provide all the styling options that we need, and the
Pygments tokens were not ideal for styling anything besides tokenized text.
Instead we created something similar to CSS. All UI components can attach
classnames to themselves, as well as define an inline style. The final style is
then computed by combining the inline styles, the classnames and the style
sheet.
There are still adaptors available for using Pygments lexers as well as for
Pygments styles.
- The way that key bindings were defined was too complex.
``KeyBindingsManager`` was too complex and no longer exists. Every set of key
bindings is now a
:class:`~prompt_toolkit.key_binding.KeyBindings` object and multiple of these
can be merged together at any time. The runtime performance remains the same,
but it's now easier for users.
- The separation between the ``CommandLineInterface`` and
:class:`~prompt_toolkit.application.Application` class was confusing and in
the end, didn't really had an advantage. These two are now merged together in
one :class:`~prompt_toolkit.application.Application` class.
- We no longer pass around the active ``CommandLineInterface``. This was one of
the most annoying things. Key bindings need it in order to change anything
and filters need it in order to evaluate their state. It was pretty annoying,
especially because there was usually only one application active at a time.
So, :class:`~prompt_toolkit.application.Application` became a ``TaskLocal``.
That is like a global variable, but scoped in the current coroutine or
context. The way this works is still not 100% correct, but good enough for
the projects that need it (like Pymux), and hopefully Python will get support
for this in the future thanks to PEP521, PEP550 or PEP555.
All of these changes have been tested for many months, and I can say with
confidence that prompt_toolkit 2.0 is a better prompt_toolkit.
Some new features
-----------------
Apart from the breaking changes above, there are also some exciting new
features.
- We now support vt100 escape codes for Windows consoles on Windows 10. This
means much faster rendering, and full color support.
- We have a concept of formatted text. This is an object that evaluates to
styled text. Every input that expects some text, like the message in a
prompt, or the text in a toolbar, can take any kind of formatted text as input.
This means you can pass in a plain string, but also a list of `(style,
text)` tuples (similar to a Pygments tokenized string), or an
:class:`~prompt_toolkit.formatted_text.HTML` object. This simplifies many
APIs.
- New utilities were added. We now have function for printing formatted text
and an experimental module for displaying progress bars.
- Autocompletion, input validation, and auto suggestion can now either be
asynchronous or synchronous. By default they are synchronous, but by wrapping
them in :class:`~prompt_toolkit.completion.ThreadedCompleter`,
:class:`~prompt_toolkit.validation.ThreadedValidator` or
:class:`~prompt_toolkit.auto_suggest.ThreadedAutoSuggest`, they will become
asynchronous by running in a background thread.
Further, if the autocompletion code runs in a background thread, we will show
the completions as soon as they arrive. This means that the autocompletion
algorithm could for instance first yield the most trivial completions and then
take time to produce the completions that take more time.
Upgrading
---------
More guidelines on how to upgrade will follow.
`AbortAction` has been removed
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Prompt_toolkit 1.0 had an argument ``abort_action`` for both the
``Application`` class as well as for the ``prompt`` function. This has been
removed. The recommended way to handle this now is by capturing
``KeyboardInterrupt`` and ``EOFError`` manually.
Calling `create_eventloop` usually not required anymore
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Prompt_toolkit 2.0 will automatically create the appropriate event loop when
it's needed for the first time. There is no need to create one and pass it
around. If you want to run an application on top of asyncio (without using an
executor), it still needs to be activated by calling
:func:`~prompt_toolkit.eventloop.use_asyncio_event_loop` at the beginning.
Pygments styles and tokens
^^^^^^^^^^^^^^^^^^^^^^^^^^
prompt_toolkit 2.0 no longer depends on `Pygments <http://pygments.org/>`_, but
that definitely doesn't mean that you can't use any Pygments functionality
anymore. The only difference is that Pygments stuff needs to be wrapped in an
adaptor to make it compatible with the native prompt_toolkit objects.
- For instance, if you have a list of ``(pygments.Token, text)`` tuples for
formatting, then this needs to be wrapped in a
:class:`~prompt_toolkit.formatted_text.PygmentsTokens` object. This is an
adaptor that turns it into prompt_toolkit "formatted text". Feel free to keep
using this.
- Pygments lexers need to be wrapped in a
:class:`~prompt_toolkit.lexers.PygmentsLexer`. This will convert the list of
Pygments tokens into prompt_toolkit formatted text.
- If you have a Pygments style, then this needs to be converted as well. A
Pygments style class can be converted in a prompt_toolkit
:class:`~prompt_toolkit.styles.Style` with the
:func:`~prompt_toolkit.styles.pygments.style_from_pygments_cls` function
(which used to be called ``style_from_pygments``). A Pygments style
dictionary can be converted using
:func:`~prompt_toolkit.styles.pygments.style_from_pygments_dict`.
Multiple styles can be merged together using
:func:`~prompt_toolkit.styles.merge_styles`.
Wordcompleter
^^^^^^^^^^^^^
`WordCompleter` was moved from
:class:`prompt_toolkit.contrib.completers.base.WordCompleter` to
:class:`prompt_toolkit.completion.word_completer.WordCompleter`.
Asynchronous autocompletion
^^^^^^^^^^^^^^^^^^^^^^^^^^^
By default, prompt_toolkit 2.0 completion is now synchronous. If you still want
asynchronous auto completion (which is often good thing), then you have to wrap
the completer in a :class:`~prompt_toolkit.completion.ThreadedCompleter`.
Filters
^^^^^^^
We don't distiguish anymore between `CLIFilter` and `SimpleFilter`, because the
application object is no longer passed around. This means that all filters are
a `Filter` from now on.
All filters have been turned into functions. For instance, `IsDone` became
`is_done` and `HasCompletions` became `has_completions`.
This was done because almost all classes were called without any arguments in
the `__init__` causing additional braces everywhere. This means that
`HasCompletions()` has to be replaced by `has_completions` (without
parenthesis).
The few filters that took arguments as input, became functions, but still have
to be called with the given arguments.
For new filters, it is recommended to use the `@Condition` decorator,
rather then inheriting from `Filter`. For instance:
.. code:: python
from prompt_toolkit.filters import Condition
@Condition
def my_filter();
return True # Or False

View File

@ -1,118 +0,0 @@
.. _upgrading_3_0:
Upgrading to prompt_toolkit 3.0
===============================
There are two major changes in 3.0 to be aware of:
- First, prompt_toolkit uses the asyncio event loop natively, rather then using
its own implementations of event loops. This means that all coroutines are
now asyncio coroutines, and all Futures are asyncio futures. Asynchronous
generators became real asynchronous generators as well.
- Prompt_toolkit uses type annotations (almost) everywhere. This should not
break any code, but its very helpful in many ways.
There are some minor breaking changes:
- The dialogs API had to change (see below).
Detecting the prompt_toolkit version
------------------------------------
Detecting whether version 3 is being used can be done as follows:
.. code:: python
from prompt_toolkit import __version__ as ptk_version
PTK3 = ptk_version.startswith('3.')
Fixing calls to `get_event_loop`
--------------------------------
Every usage of ``get_event_loop`` has to be fixed. An easy way to do this is by
changing the imports like this:
.. code:: python
if PTK3:
from asyncio import get_event_loop
else:
from prompt_toolkit.eventloop import get_event_loop
Notice that for prompt_toolkit 2.0, ``get_event_loop`` returns a prompt_toolkit
``EventLoop`` object. This is not an asyncio eventloop, but the API is
similar.
There are some changes to the eventloop API:
+-----------------------------------+--------------------------------------+
| version 2.0 | version 3.0 (asyncio) |
+===================================+======================================+
| loop.run_in_executor(callback) | loop.run_in_executor(None, callback) |
+-----------------------------------+--------------------------------------+
| loop.call_from_executor(callback) | loop.call_soon_threadsafe(callback) |
+-----------------------------------+--------------------------------------+
Running on top of asyncio
-------------------------
For 2.0, you had tell prompt_toolkit to run on top of the asyncio event loop.
Now it's the default. So, you can simply remove the following two lines:
.. code::
from prompt_toolkit.eventloop.defaults import use_asyncio_event_loop
use_asyncio_event_loop()
There is a few little breaking changes though. The following:
.. code::
# For 2.0
result = await PromptSession().prompt('Say something: ', async_=True)
has to be changed into:
.. code::
# For 3.0
result = await PromptSession().prompt_async('Say something: ')
Further, it's impossible to call the `prompt()` function within an asyncio
application (within a coroutine), because it will try to run the event loop
again. In that case, always use `prompt_async()`.
Changes to the dialog functions
-------------------------------
The original way of using dialog boxes looked like this:
.. code:: python
from prompt_toolkit.shortcuts import input_dialog
result = input_dialog(title='...', text='...')
Now, the dialog functions return a prompt_toolkit Application object. You have
to call either its ``run`` or ``run_async`` method to display the dialog. The
``async_`` parameter has been removed everywhere.
.. code:: python
if PTK3:
result = input_dialog(title='...', text='...').run()
else:
result = input_dialog(title='...', text='...')
# Or
if PTK3:
result = await input_dialog(title='...', text='...').run_async()
else:
result = await input_dialog(title='...', text='...', async_=True)

View File

@ -1,11 +0,0 @@
.. _upgrading:
Upgrading
=========
.. toctree::
:caption: Contents:
:maxdepth: 1
2.0
3.0

View File

@ -1,23 +0,0 @@
#!/usr/bin/env python
"""
Example of button dialog window.
"""
from prompt_toolkit.shortcuts import button_dialog
def main():
result = button_dialog(
title='Button dialog example',
text='Are you sure?',
buttons=[
('Yes', True),
('No', False),
('Maybe...', None),
],
).run()
print('Result = {}'.format(result))
if __name__ == '__main__':
main()

View File

@ -1,35 +0,0 @@
#!/usr/bin/env python
"""
Example of a checkbox-list-based dialog.
"""
from __future__ import unicode_literals
from prompt_toolkit.shortcuts import checkboxlist_dialog, message_dialog
from prompt_toolkit.styles import Style
results = checkboxlist_dialog(
title="CheckboxList dialog",
text="What would you like in your breakfast ?",
values=[
("eggs", "Eggs"),
("bacon", "Bacon"),
("croissants", "20 Croissants"),
("daily", "The breakfast of the day")
],
style=Style.from_dict({
'dialog': 'bg:#cdbbb3',
'button': 'bg:#bf99a4',
'checkbox': '#e8612c',
'dialog.body': 'bg:#a9cfd0',
'dialog shadow': 'bg:#c98982',
'frame.label': '#fcaca3',
'dialog.body label': '#fd8bb6',
})
).run()
if results:
message_dialog(
title="Room service",
text="You selected: %s\nGreat choice sir !" % ",".join(results)
).run()
else:
message_dialog("*starves*").run()

View File

@ -1,17 +0,0 @@
#!/usr/bin/env python
"""
Example of an input box dialog.
"""
from prompt_toolkit.shortcuts import input_dialog
def main():
result = input_dialog(
title='Input dialog example',
text='Please type your name:').run()
print('Result = {}'.format(result))
if __name__ == '__main__':
main()

View File

@ -1,15 +0,0 @@
#!/usr/bin/env python
"""
Example of a message box window.
"""
from prompt_toolkit.shortcuts import message_dialog
def main():
message_dialog(
title='Example dialog window',
text='Do you want to continue?\nPress ENTER to quit.').run()
if __name__ == '__main__':
main()

View File

@ -1,18 +0,0 @@
#!/usr/bin/env python
"""
Example of an password input dialog.
"""
from prompt_toolkit.shortcuts import input_dialog
def main():
result = input_dialog(
title='Password dialog example',
text='Please type your password:',
password=True).run()
print('Result = {}'.format(result))
if __name__ == '__main__':
main()

View File

@ -1,46 +0,0 @@
#!/usr/bin/env python
"""
Example of a progress bar dialog.
"""
import os
import time
from prompt_toolkit.shortcuts import progress_dialog
def worker(set_percentage, log_text):
"""
This worker function is called by `progress_dialog`. It will run in a
background thread.
The `set_percentage` function can be used to update the progress bar, while
the `log_text` function can be used to log text in the logging window.
"""
percentage = 0
for dirpath, dirnames, filenames in os.walk('../..'):
for f in filenames:
log_text('{} / {}\n'.format(dirpath, f))
set_percentage(percentage + 1)
percentage += 2
time.sleep(.1)
if percentage == 100:
break
if percentage == 100:
break
# Show 100% for a second, before quitting.
set_percentage(100)
time.sleep(1)
def main():
progress_dialog(
title='Progress dialog example',
text='As an examples, we walk through the filesystem and print '
'all directories',
run_callback=worker).run()
if __name__ == '__main__':
main()

View File

@ -1,37 +0,0 @@
#!/usr/bin/env python
"""
Example of a radio list box dialog.
"""
from prompt_toolkit.formatted_text import HTML
from prompt_toolkit.shortcuts import radiolist_dialog
def main():
result = radiolist_dialog(
values=[
('red', 'Red'),
('green', 'Green'),
('blue', 'Blue'),
('orange', 'Orange'),
],
title='Radiolist dialog example',
text='Please select a color:').run()
print('Result = {}'.format(result))
# With HTML.
result = radiolist_dialog(
values=[
('red', HTML('<style bg="red" fg="white">Red</style>')),
('green', HTML('<style bg="green" fg="white">Green</style>')),
('blue', HTML('<style bg="blue" fg="white">Blue</style>')),
('orange', HTML('<style bg="orange" fg="white">Orange</style>')),
],
title=HTML('Radiolist dialog example <reverse>with colors</reverse>'),
text='Please select a color:').run()
print('Result = {}'.format(result))
if __name__ == '__main__':
main()

View File

@ -1,32 +0,0 @@
#!/usr/bin/env python
"""
Example of a style dialog window.
All dialog shortcuts take a `style` argument in order to apply a custom
styling.
This also demonstrates that the `title` argument can be any kind of formatted
text.
"""
from prompt_toolkit.formatted_text import HTML
from prompt_toolkit.shortcuts import message_dialog
from prompt_toolkit.styles import Style
# Custom color scheme.
example_style = Style.from_dict({
'dialog': 'bg:#88ff88',
'dialog frame-label': 'bg:#ffffff #000000',
'dialog.body': 'bg:#000000 #00ff00',
'dialog shadow': 'bg:#00aa00',
})
def main():
message_dialog(
title=HTML('<style bg="blue" fg="white">Styled</style> '
'<style fg="ansired">dialog</style> window'),
text='Do you want to continue?\nPress ENTER to quit.',
style=example_style).run()
if __name__ == '__main__':
main()

View File

@ -1,17 +0,0 @@
#!/usr/bin/env python
"""
Example of confirmation (yes/no) dialog window.
"""
from prompt_toolkit.shortcuts import yes_no_dialog
def main():
result = yes_no_dialog(
title='Yes/No dialog example',
text='Do you want to confirm?').run()
print('Result = {}'.format(result))
if __name__ == '__main__':
main()

View File

@ -1,98 +0,0 @@
#!/usr/bin/env python
"""
A simple example of a few buttons and click handlers.
"""
from prompt_toolkit.application import Application
from prompt_toolkit.application.current import get_app
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.key_binding.bindings.focus import (
focus_next,
focus_previous,
)
from prompt_toolkit.layout import HSplit, Layout, VSplit
from prompt_toolkit.styles import Style
from prompt_toolkit.widgets import Box, Button, Frame, Label, TextArea
# Event handlers for all the buttons.
def button1_clicked():
text_area.text = 'Button 1 clicked'
def button2_clicked():
text_area.text = 'Button 2 clicked'
def button3_clicked():
text_area.text = 'Button 3 clicked'
def exit_clicked():
get_app().exit()
# All the widgets for the UI.
button1 = Button('Button 1', handler=button1_clicked)
button2 = Button('Button 2', handler=button2_clicked)
button3 = Button('Button 3', handler=button3_clicked)
button4 = Button('Exit', handler=exit_clicked)
text_area = TextArea(focusable=True)
# Combine all the widgets in a UI.
# The `Box` object ensures that padding will be inserted around the containing
# widget. It adapts automatically, unless an explicit `padding` amount is given.
root_container = Box(
HSplit([
Label(text='Press `Tab` to move the focus.'),
VSplit([
Box(
body=HSplit(
[button1, button2, button3, button4],
padding=1),
padding=1,
style='class:left-pane'),
Box(
body=Frame(text_area),
padding=1,
style='class:right-pane'),
]),
]),
)
layout = Layout(
container=root_container,
focused_element=button1)
# Key bindings.
kb = KeyBindings()
kb.add('tab')(focus_next)
kb.add('s-tab')(focus_previous)
# Styling.
style = Style([
('left-pane', 'bg:#888800 #000000'),
('right-pane', 'bg:#00aa00 #000000'),
('button', '#000000'),
('button-arrow', '#000000'),
('button focused', 'bg:#ff0000'),
('text-area focused', 'bg:#ff0000'),
])
# Build a main application object.
application = Application(
layout=layout,
key_bindings=kb,
style=style,
full_screen=True)
def main():
application.run()
if __name__ == '__main__':
main()

View File

@ -1,87 +0,0 @@
#!/usr/bin/env python
"""
A simple example of a calculator program.
This could be used as inspiration for a REPL.
"""
from prompt_toolkit.application import Application
from prompt_toolkit.document import Document
from prompt_toolkit.filters import has_focus
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.layout.containers import HSplit, Window
from prompt_toolkit.layout.layout import Layout
from prompt_toolkit.styles import Style
from prompt_toolkit.widgets import SearchToolbar, TextArea
help_text = """
Type any expression (e.g. "4 + 4") followed by enter to execute.
Press Control-C to exit.
"""
def main():
# The layout.
search_field = SearchToolbar() # For reverse search.
output_field = TextArea(style='class:output-field', text=help_text)
input_field = TextArea(
height=1, prompt='>>> ', style='class:input-field', multiline=False,
wrap_lines=False, search_field=search_field)
container = HSplit([
output_field,
Window(height=1, char='-', style='class:line'),
input_field,
search_field,
])
# Attach accept handler to the input field. We do this by assigning the
# handler to the `TextArea` that we created earlier. it is also possible to
# pass it to the constructor of `TextArea`.
# NOTE: It's better to assign an `accept_handler`, rather then adding a
# custom ENTER key binding. This will automatically reset the input
# field and add the strings to the history.
def accept(buff):
# Evaluate "calculator" expression.
try:
output = '\n\nIn: {}\nOut: {}'.format(
input_field.text,
eval(input_field.text)) # Don't do 'eval' in real code!
except BaseException as e:
output = '\n\n{}'.format(e)
new_text = output_field.text + output
# Add text to output buffer.
output_field.buffer.document = Document(
text=new_text, cursor_position=len(new_text))
input_field.accept_handler = accept
# The key bindings.
kb = KeyBindings()
@kb.add('c-c')
@kb.add('c-q')
def _(event):
" Pressing Ctrl-Q or Ctrl-C will exit the user interface. "
event.app.exit()
# Style.
style = Style([
('output-field', 'bg:#000044 #ffffff'),
('input-field', 'bg:#000000 #ffffff'),
('line', '#004400'),
])
# Run application.
application = Application(
layout=Layout(container, focused_element=input_field),
key_bindings=kb,
style=style,
mouse_support=True,
full_screen=True)
application.run()
if __name__ == '__main__':
main()

View File

@ -1,8 +0,0 @@
#!/usr/bin/env python
"""
This is the most simple example possible.
"""
from prompt_toolkit import Application
app = Application(full_screen=False)
app.run()

View File

@ -1,188 +0,0 @@
#!/usr/bin/env python
"""
"""
from pygments.lexers.html import HtmlLexer
from prompt_toolkit.application import Application
from prompt_toolkit.application.current import get_app
from prompt_toolkit.completion import WordCompleter
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.key_binding.bindings.focus import (
focus_next,
focus_previous,
)
from prompt_toolkit.layout.containers import Float, HSplit, VSplit
from prompt_toolkit.layout.dimension import D
from prompt_toolkit.layout.layout import Layout
from prompt_toolkit.layout.menus import CompletionsMenu
from prompt_toolkit.lexers import PygmentsLexer
from prompt_toolkit.styles import Style
from prompt_toolkit.widgets import (
Box,
Button,
Checkbox,
Dialog,
Frame,
Label,
MenuContainer,
MenuItem,
ProgressBar,
RadioList,
TextArea,
)
def accept_yes():
get_app().exit(result=True)
def accept_no():
get_app().exit(result=False)
def do_exit():
get_app().exit(result=False)
yes_button = Button(text='Yes', handler=accept_yes)
no_button = Button(text='No', handler=accept_no)
textfield = TextArea(lexer=PygmentsLexer(HtmlLexer))
checkbox1 = Checkbox(text='Checkbox')
checkbox2 = Checkbox(text='Checkbox')
radios = RadioList(values=[
('Red', 'red'),
('Green', 'green'),
('Blue', 'blue'),
('Orange', 'orange'),
('Yellow', 'yellow'),
('Purple', 'Purple'),
('Brown', 'Brown'),
])
animal_completer = WordCompleter([
'alligator', 'ant', 'ape', 'bat', 'bear', 'beaver', 'bee', 'bison',
'butterfly', 'cat', 'chicken', 'crocodile', 'dinosaur', 'dog', 'dolphin',
'dove', 'duck', 'eagle', 'elephant', 'fish', 'goat', 'gorilla', 'kangaroo',
'leopard', 'lion', 'mouse', 'rabbit', 'rat', 'snake', 'spider', 'turkey',
'turtle', ], ignore_case=True)
root_container = HSplit([
VSplit([
Frame(body=Label(text='Left frame\ncontent')),
Dialog(title='The custom window',
body=Label('hello\ntest')),
textfield,
], height=D()),
VSplit([
Frame(body=ProgressBar(),
title='Progress bar'),
Frame(title='Checkbox list',
body=HSplit([
checkbox1,
checkbox2,
])),
Frame(title='Radio list', body=radios),
], padding=1),
Box(
body=VSplit([
yes_button,
no_button,
], align='CENTER', padding=3),
style='class:button-bar',
height=3,
),
])
root_container = MenuContainer(body=root_container, menu_items=[
MenuItem('File', children=[
MenuItem('New'),
MenuItem('Open', children=[
MenuItem('From file...'),
MenuItem('From URL...'),
MenuItem('Something else..', children=[
MenuItem('A'),
MenuItem('B'),
MenuItem('C'),
MenuItem('D'),
MenuItem('E'),
]),
]),
MenuItem('Save'),
MenuItem('Save as...'),
MenuItem('-', disabled=True),
MenuItem('Exit', handler=do_exit),
]),
MenuItem('Edit', children=[
MenuItem('Undo'),
MenuItem('Cut'),
MenuItem('Copy'),
MenuItem('Paste'),
MenuItem('Delete'),
MenuItem('-', disabled=True),
MenuItem('Find'),
MenuItem('Find next'),
MenuItem('Replace'),
MenuItem('Go To'),
MenuItem('Select All'),
MenuItem('Time/Date'),
]),
MenuItem('View', children=[
MenuItem('Status Bar'),
]),
MenuItem('Info', children=[
MenuItem('About'),
]),
], floats=[
Float(xcursor=True,
ycursor=True,
content=CompletionsMenu(
max_height=16,
scroll_offset=1)),
])
# Global key bindings.
bindings = KeyBindings()
bindings.add('tab')(focus_next)
bindings.add('s-tab')(focus_previous)
style = Style.from_dict({
'window.border': '#888888',
'shadow': 'bg:#222222',
'menu-bar': 'bg:#aaaaaa #888888',
'menu-bar.selected-item': 'bg:#ffffff #000000',
'menu': 'bg:#888888 #ffffff',
'menu.border': '#aaaaaa',
'window.border shadow': '#444444',
'focused button': 'bg:#880000 #ffffff noinherit',
# Styling for Dialog widgets.
'radiolist focused': 'noreverse',
'radiolist focused radio.selected': 'reverse',
'button-bar': 'bg:#aaaaff'
})
application = Application(
layout=Layout(
root_container,
focused_element=yes_button,
),
key_bindings=bindings,
style=style,
mouse_support=True,
full_screen=True)
def run():
result = application.run()
print('You said: %r' % result)
if __name__ == '__main__':
run()

View File

@ -1,43 +0,0 @@
#!/usr/bin/env python
"""
A simple example of a a text area displaying "Hello World!".
"""
from prompt_toolkit.application import Application
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.layout import Layout
from prompt_toolkit.widgets import Box, Frame, TextArea
# Layout for displaying hello world.
# (The frame creates the border, the box takes care of the margin/padding.)
root_container = Box(
Frame(TextArea(
text='Hello world!\nPress control-c to quit.',
width=40,
height=10,
)),
)
layout = Layout(container=root_container)
# Key bindings.
kb = KeyBindings()
@kb.add('c-c')
def _(event):
" Quit when control-c is pressed. "
event.app.exit()
# Build a main application object.
application = Application(
layout=layout,
key_bindings=kb,
full_screen=True)
def main():
application.run()
if __name__ == '__main__':
main()

View File

@ -1,7 +0,0 @@
#!/usr/bin/env python
"""
An empty full screen application without layout.
"""
from prompt_toolkit import Application
Application(full_screen=True).run()

View File

@ -1,103 +0,0 @@
#!/usr/bin/env python
"""
A simple application that shows a Pager application.
"""
from pygments.lexers.python import PythonLexer
from prompt_toolkit.application import Application
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.layout.containers import HSplit, Window
from prompt_toolkit.layout.controls import FormattedTextControl
from prompt_toolkit.layout.dimension import LayoutDimension as D
from prompt_toolkit.layout.layout import Layout
from prompt_toolkit.lexers import PygmentsLexer
from prompt_toolkit.styles import Style
from prompt_toolkit.widgets import SearchToolbar, TextArea
# Create one text buffer for the main content.
_pager_py_path = __file__
with open(_pager_py_path, 'rb') as f:
text = f.read().decode('utf-8')
def get_statusbar_text():
return [
('class:status', _pager_py_path + ' - '),
('class:status.position', '{}:{}'.format(
text_area.document.cursor_position_row + 1,
text_area.document.cursor_position_col + 1)),
('class:status', ' - Press '),
('class:status.key', 'Ctrl-C'),
('class:status', ' to exit, '),
('class:status.key', '/'),
('class:status', ' for searching.'),
]
search_field = SearchToolbar(text_if_not_searching=[
('class:not-searching', "Press '/' to start searching.")])
text_area = TextArea(
text=text,
read_only=True,
scrollbar=True,
line_numbers=True,
search_field=search_field,
lexer=PygmentsLexer(PythonLexer))
root_container = HSplit([
# The top toolbar.
Window(content=FormattedTextControl(
get_statusbar_text),
height=D.exact(1),
style='class:status'),
# The main content.
text_area,
search_field,
])
# Key bindings.
bindings = KeyBindings()
@bindings.add('c-c')
@bindings.add('q')
def _(event):
" Quit. "
event.app.exit()
style = Style.from_dict({
'status': 'reverse',
'status.position': '#aaaa00',
'status.key': '#ffaa00',
'not-searching': '#888888',
})
# create application.
application = Application(
layout=Layout(
root_container,
focused_element=text_area,
),
key_bindings=bindings,
enable_page_navigation_bindings=True,
mouse_support=True,
style=style,
full_screen=True)
def run():
application.run()
if __name__ == '__main__':
run()

View File

@ -1,61 +0,0 @@
#!/usr/bin/env python
"""
Demo of the different Window alignment options.
"""
from prompt_toolkit.application import Application
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.layout.containers import HSplit, Window, WindowAlign
from prompt_toolkit.layout.controls import FormattedTextControl
from prompt_toolkit.layout.layout import Layout
LIPSUM = """Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas
quis interdum enim. Nam viverra, mauris et blandit malesuada, ante est bibendum
mauris, ac dignissim dui tellus quis ligula. Aenean condimentum leo at
dignissim placerat. In vel dictum ex, vulputate accumsan mi. Donec ut quam
placerat massa tempor elementum. Sed tristique mauris ac suscipit euismod. Ut
tempus vehicula augue non venenatis. Mauris aliquam velit turpis, nec congue
risus aliquam sit amet. Pellentesque blandit scelerisque felis, faucibus
consequat ante. Curabitur tempor tortor a imperdiet tincidunt. Nam sed justo
sit amet odio bibendum congue. Quisque varius ligula nec ligula gravida, sed
convallis augue faucibus. Nunc ornare pharetra bibendum. Praesent blandit ex
quis sodales maximus."""
# 1. The layout
left_text = '\nLeft aligned text. - (Press "q" to quit)\n\n' + LIPSUM
center_text = 'Centered text.\n\n' + LIPSUM
right_text = 'Right aligned text.\n\n' + LIPSUM
body = HSplit([
Window(FormattedTextControl(left_text), align=WindowAlign.LEFT),
Window(height=1, char='-'),
Window(FormattedTextControl(center_text), align=WindowAlign.CENTER),
Window(height=1, char='-'),
Window(FormattedTextControl(right_text), align=WindowAlign.RIGHT),
])
# 2. Key bindings
kb = KeyBindings()
@kb.add('q')
def _(event):
" Quit application. "
event.app.exit()
# 3. The `Application`
application = Application(
layout=Layout(body),
key_bindings=kb,
full_screen=True)
def run():
application.run()
if __name__ == '__main__':
run()

View File

@ -1,72 +0,0 @@
#!/usr/bin/env python
"""
An example of a BufferControl in a full screen layout that offers auto
completion.
Important is to make sure that there is a `CompletionsMenu` in the layout,
otherwise the completions won't be visible.
"""
from prompt_toolkit.application import Application
from prompt_toolkit.buffer import Buffer
from prompt_toolkit.completion import WordCompleter
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.layout.containers import (
Float,
FloatContainer,
HSplit,
Window,
)
from prompt_toolkit.layout.controls import BufferControl, FormattedTextControl
from prompt_toolkit.layout.layout import Layout
from prompt_toolkit.layout.menus import CompletionsMenu
# The completer.
animal_completer = WordCompleter([
'alligator', 'ant', 'ape', 'bat', 'bear', 'beaver', 'bee', 'bison',
'butterfly', 'cat', 'chicken', 'crocodile', 'dinosaur', 'dog', 'dolphin',
'dove', 'duck', 'eagle', 'elephant', 'fish', 'goat', 'gorilla', 'kangaroo',
'leopard', 'lion', 'mouse', 'rabbit', 'rat', 'snake', 'spider', 'turkey',
'turtle',
], ignore_case=True)
# The layout
buff = Buffer(completer=animal_completer, complete_while_typing=True)
body = FloatContainer(
content=HSplit([
Window(FormattedTextControl('Press "q" to quit.'), height=1, style='reverse'),
Window(BufferControl(buffer=buff)),
]),
floats=[
Float(xcursor=True,
ycursor=True,
content=CompletionsMenu(max_height=16, scroll_offset=1))
]
)
# Key bindings
kb = KeyBindings()
@kb.add('q')
@kb.add('c-c')
def _(event):
" Quit application. "
event.app.exit()
# The `Application`
application = Application(
layout=Layout(body),
key_bindings=kb,
full_screen=True)
def run():
application.run()
if __name__ == '__main__':
run()

View File

@ -1,64 +0,0 @@
#!/usr/bin/env python
"""
Colorcolumn example.
"""
from prompt_toolkit.application import Application
from prompt_toolkit.buffer import Buffer
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.layout.containers import ColorColumn, HSplit, Window
from prompt_toolkit.layout.controls import BufferControl, FormattedTextControl
from prompt_toolkit.layout.layout import Layout
LIPSUM = """
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas
quis interdum enim. Nam viverra, mauris et blandit malesuada, ante est bibendum
mauris, ac dignissim dui tellus quis ligula. Aenean condimentum leo at
dignissim placerat. In vel dictum ex, vulputate accumsan mi. Donec ut quam
placerat massa tempor elementum. Sed tristique mauris ac suscipit euismod. Ut
tempus vehicula augue non venenatis. Mauris aliquam velit turpis, nec congue
risus aliquam sit amet. Pellentesque blandit scelerisque felis, faucibus
consequat ante. Curabitur tempor tortor a imperdiet tincidunt. Nam sed justo
sit amet odio bibendum congue. Quisque varius ligula nec ligula gravida, sed
convallis augue faucibus. Nunc ornare pharetra bibendum. Praesent blandit ex
quis sodales maximus."""
# Create text buffers.
buff = Buffer()
buff.text = LIPSUM
# 1. The layout
color_columns = [
ColorColumn(50),
ColorColumn(80, style='bg:#ff0000'),
ColorColumn(10, style='bg:#ff0000'),
]
body = HSplit([
Window(FormattedTextControl('Press "q" to quit.'), height=1, style='reverse'),
Window(BufferControl(buffer=buff), colorcolumns=color_columns),
])
# 2. Key bindings
kb = KeyBindings()
@kb.add('q')
def _(event):
" Quit application. "
event.app.exit()
# 3. The `Application`
application = Application(
layout=Layout(body),
key_bindings=kb,
full_screen=True)
def run():
application.run()
if __name__ == '__main__':
run()

View File

@ -1,60 +0,0 @@
#!/usr/bin/env python
"""
Cursorcolumn / cursorline example.
"""
from prompt_toolkit.application import Application
from prompt_toolkit.buffer import Buffer
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.layout.containers import HSplit, Window
from prompt_toolkit.layout.controls import BufferControl, FormattedTextControl
from prompt_toolkit.layout.layout import Layout
LIPSUM = """
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas
quis interdum enim. Nam viverra, mauris et blandit malesuada, ante est bibendum
mauris, ac dignissim dui tellus quis ligula. Aenean condimentum leo at
dignissim placerat. In vel dictum ex, vulputate accumsan mi. Donec ut quam
placerat massa tempor elementum. Sed tristique mauris ac suscipit euismod. Ut
tempus vehicula augue non venenatis. Mauris aliquam velit turpis, nec congue
risus aliquam sit amet. Pellentesque blandit scelerisque felis, faucibus
consequat ante. Curabitur tempor tortor a imperdiet tincidunt. Nam sed justo
sit amet odio bibendum congue. Quisque varius ligula nec ligula gravida, sed
convallis augue faucibus. Nunc ornare pharetra bibendum. Praesent blandit ex
quis sodales maximus."""
# Create text buffers. Cursorcolumn/cursorline are mostly combined with an
# (editable) text buffers, where the user can move the cursor.
buff = Buffer()
buff.text = LIPSUM
# 1. The layout
body = HSplit([
Window(FormattedTextControl('Press "q" to quit.'), height=1, style='reverse'),
Window(BufferControl(buffer=buff), cursorcolumn=True, cursorline=True),
])
# 2. Key bindings
kb = KeyBindings()
@kb.add('q')
def _(event):
" Quit application. "
event.app.exit()
# 3. The `Application`
application = Application(
layout=Layout(body),
key_bindings=kb,
full_screen=True)
def run():
application.run()
if __name__ == '__main__':
run()

View File

@ -1,83 +0,0 @@
#!/usr/bin/env python
"""
Example of the 'transparency' attribute of `Window' when used in a Float.
"""
from prompt_toolkit.application import Application
from prompt_toolkit.formatted_text import HTML
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.layout.containers import Float, FloatContainer, Window
from prompt_toolkit.layout.controls import FormattedTextControl
from prompt_toolkit.layout.layout import Layout
from prompt_toolkit.widgets import Frame
LIPSUM = ' '.join(("""Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Maecenas quis interdum enim. Nam viverra, mauris et blandit malesuada, ante est
bibendum mauris, ac dignissim dui tellus quis ligula. Aenean condimentum leo at
dignissim placerat. In vel dictum ex, vulputate accumsan mi. Donec ut quam
placerat massa tempor elementum. Sed tristique mauris ac suscipit euismod. Ut
tempus vehicula augue non venenatis. Mauris aliquam velit turpis, nec congue
risus aliquam sit amet. Pellentesque blandit scelerisque felis, faucibus
consequat ante. Curabitur tempor tortor a imperdiet tincidunt. Nam sed justo
sit amet odio bibendum congue. Quisque varius ligula nec ligula gravida, sed
convallis augue faucibus. Nunc ornare pharetra bibendum. Praesent blandit ex
quis sodales maximus. """ * 100).split())
# 1. The layout
left_text = HTML("<reverse>transparent=False</reverse>\n")
right_text = HTML("<reverse>transparent=True</reverse>")
quit_text = "Press 'q' to quit."
body = FloatContainer(
content=Window(FormattedTextControl(LIPSUM), wrap_lines=True),
floats=[
# Important note: Wrapping the floating objects in a 'Frame' is
# only required for drawing the border around the
# floating text. We do it here to make the layout more
# obvious.
# Left float.
Float(
Frame(Window(FormattedTextControl(left_text), width=20, height=4)),
transparent=False,
left=0),
# Right float.
Float(
Frame(Window(FormattedTextControl(right_text), width=20, height=4)),
transparent=True,
right=0),
# Quit text.
Float(
Frame(Window(FormattedTextControl(quit_text), width=18, height=1),
style='bg:#ff44ff #ffffff'),
top=1),
])
# 2. Key bindings
kb = KeyBindings()
@kb.add('q')
def _(event):
" Quit application. "
event.app.exit()
# 3. The `Application`
application = Application(
layout=Layout(body),
key_bindings=kb,
full_screen=True)
def run():
application.run()
if __name__ == '__main__':
run()

View File

@ -1,102 +0,0 @@
#!/usr/bin/env python
"""
Horizontal split example.
"""
from prompt_toolkit.application import Application
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.layout.containers import Float, FloatContainer, Window
from prompt_toolkit.layout.controls import FormattedTextControl
from prompt_toolkit.layout.layout import Layout
from prompt_toolkit.widgets import Frame
LIPSUM = ' '.join(("""Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Maecenas quis interdum enim. Nam viverra, mauris et blandit malesuada, ante est
bibendum mauris, ac dignissim dui tellus quis ligula. Aenean condimentum leo at
dignissim placerat. In vel dictum ex, vulputate accumsan mi. Donec ut quam
placerat massa tempor elementum. Sed tristique mauris ac suscipit euismod. Ut
tempus vehicula augue non venenatis. Mauris aliquam velit turpis, nec congue
risus aliquam sit amet. Pellentesque blandit scelerisque felis, faucibus
consequat ante. Curabitur tempor tortor a imperdiet tincidunt. Nam sed justo
sit amet odio bibendum congue. Quisque varius ligula nec ligula gravida, sed
convallis augue faucibus. Nunc ornare pharetra bibendum. Praesent blandit ex
quis sodales maximus. """ * 100).split())
# 1. The layout
left_text = "Floating\nleft"
right_text = "Floating\nright"
top_text = "Floating\ntop"
bottom_text = "Floating\nbottom"
center_text = "Floating\ncenter"
quit_text = "Press 'q' to quit."
body = FloatContainer(
content=Window(FormattedTextControl(LIPSUM), wrap_lines=True),
floats=[
# Important note: Wrapping the floating objects in a 'Frame' is
# only required for drawing the border around the
# floating text. We do it here to make the layout more
# obvious.
# Left float.
Float(
Frame(Window(FormattedTextControl(left_text), width=10, height=2),
style='bg:#44ffff #ffffff'),
left=0),
# Right float.
Float(
Frame(Window(FormattedTextControl(right_text), width=10, height=2),
style='bg:#44ffff #ffffff'),
right=0),
# Bottom float.
Float(
Frame(Window(FormattedTextControl(bottom_text), width=10, height=2),
style='bg:#44ffff #ffffff'),
bottom=0),
# Top float.
Float(
Frame(Window(FormattedTextControl(top_text), width=10, height=2),
style='bg:#44ffff #ffffff'),
top=0),
# Center float.
Float(
Frame(Window(FormattedTextControl(center_text), width=10, height=2),
style='bg:#44ffff #ffffff')),
# Quit text.
Float(
Frame(Window(FormattedTextControl(quit_text), width=18, height=1),
style='bg:#ff44ff #ffffff'),
top=6),
])
# 2. Key bindings
kb = KeyBindings()
@kb.add('q')
def _(event):
" Quit application. "
event.app.exit()
# 3. The `Application`
application = Application(
layout=Layout(body),
key_bindings=kb,
full_screen=True)
def run():
application.run()
if __name__ == '__main__':
run()

View File

@ -1,107 +0,0 @@
#!/usr/bin/env python
"""
Demonstration of how to programmatically focus a certain widget.
"""
from prompt_toolkit.application import Application
from prompt_toolkit.buffer import Buffer
from prompt_toolkit.document import Document
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.layout.containers import HSplit, VSplit, Window
from prompt_toolkit.layout.controls import BufferControl, FormattedTextControl
from prompt_toolkit.layout.layout import Layout
# 1. The layout
top_text = (
"Focus example.\n"
"[q] Quit [a] Focus left top [b] Right top [c] Left bottom [d] Right bottom."
)
LIPSUM = """Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Maecenas quis interdum enim. Nam viverra, mauris et blandit malesuada, ante est
bibendum mauris, ac dignissim dui tellus quis ligula. Aenean condimentum leo at
dignissim placerat. In vel dictum ex, vulputate accumsan mi. Donec ut quam
placerat massa tempor elementum. Sed tristique mauris ac suscipit euismod. Ut
tempus vehicula augue non venenatis. Mauris aliquam velit turpis, nec congue
risus aliquam sit amet. Pellentesque blandit scelerisque felis, faucibus
consequat ante. Curabitur tempor tortor a imperdiet tincidunt. Nam sed justo
sit amet odio bibendum congue. Quisque varius ligula nec ligula gravida, sed
convallis augue faucibus. Nunc ornare pharetra bibendum. Praesent blandit ex
quis sodales maximus. """
left_top = Window(BufferControl(Buffer(document=Document(LIPSUM))))
left_bottom = Window(BufferControl(Buffer(document=Document(LIPSUM))))
right_top = Window(BufferControl(Buffer(document=Document(LIPSUM))))
right_bottom = Window(BufferControl(Buffer(document=Document(LIPSUM))))
body = HSplit([
Window(FormattedTextControl(top_text), height=2, style='reverse'),
Window(height=1, char='-'), # Horizontal line in the middle.
VSplit([
left_top,
Window(width=1, char='|'),
right_top
]),
Window(height=1, char='-'), # Horizontal line in the middle.
VSplit([
left_bottom,
Window(width=1, char='|'),
right_bottom
]),
])
# 2. Key bindings
kb = KeyBindings()
@kb.add('q')
def _(event):
" Quit application. "
event.app.exit()
@kb.add('a')
def _(event):
event.app.layout.focus(left_top)
@kb.add('b')
def _(event):
event.app.layout.focus(right_top)
@kb.add('c')
def _(event):
event.app.layout.focus(left_bottom)
@kb.add('d')
def _(event):
event.app.layout.focus(right_bottom)
@kb.add('tab')
def _(event):
event.app.layout.focus_next()
@kb.add('s-tab')
def _(event):
event.app.layout.focus_previous()
# 3. The `Application`
application = Application(
layout=Layout(body),
key_bindings=kb,
full_screen=True)
def run():
application.run()
if __name__ == '__main__':
run()

View File

@ -1,103 +0,0 @@
#!/usr/bin/env python
"""
Horizontal align demo with HSplit.
"""
from prompt_toolkit.application import Application
from prompt_toolkit.formatted_text import HTML
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.layout.containers import (
HorizontalAlign,
HSplit,
VerticalAlign,
VSplit,
Window,
WindowAlign,
)
from prompt_toolkit.layout.controls import FormattedTextControl
from prompt_toolkit.layout.dimension import D
from prompt_toolkit.layout.layout import Layout
from prompt_toolkit.widgets import Frame
TITLE = HTML(""" <u>HSplit HorizontalAlign</u> example.
Press <b>'q'</b> to quit.""")
LIPSUM = """\
Lorem ipsum dolor
sit amet, consectetur
adipiscing elit.
Maecenas quis
interdum enim."""
# 1. The layout
body = HSplit([
Frame(
Window(FormattedTextControl(TITLE), height=2), style='bg:#88ff88 #000000'),
HSplit([
# Left alignment.
VSplit([
Window(FormattedTextControl(HTML('<u>LEFT</u>')), width=10,
ignore_content_width=True, style='bg:#ff3333 ansiblack', align=WindowAlign.CENTER),
VSplit([
Window(FormattedTextControl(LIPSUM), height=4, style='bg:#444488'),
Window(FormattedTextControl(LIPSUM), height=4, style='bg:#444488'),
Window(FormattedTextControl(LIPSUM), height=4, style='bg:#444488'),
], padding=1, padding_style='bg:#888888', align=HorizontalAlign.LEFT, height=5, padding_char='|'),
]),
# Center alignment.
VSplit([
Window(FormattedTextControl(HTML('<u>CENTER</u>')), width=10,
ignore_content_width=True, style='bg:#ff3333 ansiblack', align=WindowAlign.CENTER),
VSplit([
Window(FormattedTextControl(LIPSUM), height=4, style='bg:#444488'),
Window(FormattedTextControl(LIPSUM), height=4, style='bg:#444488'),
Window(FormattedTextControl(LIPSUM), height=4, style='bg:#444488'),
], padding=1, padding_style='bg:#888888', align=HorizontalAlign.CENTER, height=5, padding_char='|'),
]),
# Right alignment.
VSplit([
Window(FormattedTextControl(HTML('<u>RIGHT</u>')), width=10,
ignore_content_width=True, style='bg:#ff3333 ansiblack', align=WindowAlign.CENTER),
VSplit([
Window(FormattedTextControl(LIPSUM), height=4, style='bg:#444488'),
Window(FormattedTextControl(LIPSUM), height=4, style='bg:#444488'),
Window(FormattedTextControl(LIPSUM), height=4, style='bg:#444488'),
], padding=1, padding_style='bg:#888888', align=HorizontalAlign.RIGHT, height=5, padding_char='|'),
]),
# Justify
VSplit([
Window(FormattedTextControl(HTML('<u>JUSTIFY</u>')), width=10,
ignore_content_width=True, style='bg:#ff3333 ansiblack', align=WindowAlign.CENTER),
VSplit([
Window(FormattedTextControl(LIPSUM), style='bg:#444488'),
Window(FormattedTextControl(LIPSUM), style='bg:#444488'),
Window(FormattedTextControl(LIPSUM), style='bg:#444488'),
], padding=1, padding_style='bg:#888888', align=HorizontalAlign.JUSTIFY, height=5, padding_char='|'),
]),
], padding=1, padding_style="bg:#ff3333 #ffffff", padding_char='.', align=VerticalAlign.TOP)
])
# 2. Key bindings
kb = KeyBindings()
@kb.add('q')
def _(event):
" Quit application. "
event.app.exit()
# 3. The `Application`
application = Application(
layout=Layout(body),
key_bindings=kb,
full_screen=True)
def run():
application.run()
if __name__ == '__main__':
run()

View File

@ -1,45 +0,0 @@
#!/usr/bin/env python
"""
Horizontal split example.
"""
from prompt_toolkit.application import Application
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.layout.containers import HSplit, Window
from prompt_toolkit.layout.controls import FormattedTextControl
from prompt_toolkit.layout.layout import Layout
# 1. The layout
left_text = "\nVertical-split example. Press 'q' to quit.\n\n(top pane.)"
right_text = "\n(bottom pane.)"
body = HSplit([
Window(FormattedTextControl(left_text)),
Window(height=1, char='-'), # Horizontal line in the middle.
Window(FormattedTextControl(right_text)),
])
# 2. Key bindings
kb = KeyBindings()
@kb.add('q')
def _(event):
" Quit application. "
event.app.exit()
# 3. The `Application`
application = Application(
layout=Layout(body),
key_bindings=kb,
full_screen=True)
def run():
application.run()
if __name__ == '__main__':
run()

View File

@ -1,103 +0,0 @@
#!/usr/bin/env python
"""
An example of a BufferControl in a full screen layout that offers auto
completion.
Important is to make sure that there is a `CompletionsMenu` in the layout,
otherwise the completions won't be visible.
"""
from prompt_toolkit.application import Application
from prompt_toolkit.buffer import Buffer
from prompt_toolkit.completion import WordCompleter
from prompt_toolkit.filters import Condition
from prompt_toolkit.formatted_text import HTML
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.layout.containers import (
Float,
FloatContainer,
HSplit,
Window,
)
from prompt_toolkit.layout.controls import BufferControl, FormattedTextControl
from prompt_toolkit.layout.layout import Layout
from prompt_toolkit.layout.menus import CompletionsMenu
LIPSUM = """
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas
quis interdum enim. Nam viverra, mauris et blandit malesuada, ante est bibendum
mauris, ac dignissim dui tellus quis ligula. Aenean condimentum leo at
dignissim placerat. In vel dictum ex, vulputate accumsan mi. Donec ut quam
placerat massa tempor elementum. Sed tristique mauris ac suscipit euismod. Ut
tempus vehicula augue non venenatis. Mauris aliquam velit turpis, nec congue
risus aliquam sit amet. Pellentesque blandit scelerisque felis, faucibus
consequat ante. Curabitur tempor tortor a imperdiet tincidunt. Nam sed justo
sit amet odio bibendum congue. Quisque varius ligula nec ligula gravida, sed
convallis augue faucibus. Nunc ornare pharetra bibendum. Praesent blandit ex
quis sodales maximus."""
def get_line_prefix(lineno, wrap_count):
if wrap_count == 0:
return HTML('[%s] <style bg="orange" fg="black">--&gt;</style> ') % lineno
text = str(lineno) + '-' + '*' * (lineno // 2) + ': '
return HTML('[%s.%s] <style bg="ansigreen" fg="ansiblack">%s</style>') % (
lineno, wrap_count, text)
# Global wrap lines flag.
wrap_lines = True
# The layout
buff = Buffer(complete_while_typing=True)
buff.text = LIPSUM
body = FloatContainer(
content=HSplit([
Window(FormattedTextControl(
'Press "q" to quit. Press "w" to enable/disable wrapping.'),
height=1, style='reverse'),
Window(BufferControl(buffer=buff), get_line_prefix=get_line_prefix,
wrap_lines=Condition(lambda: wrap_lines)),
]),
floats=[
Float(xcursor=True,
ycursor=True,
content=CompletionsMenu(max_height=16, scroll_offset=1))
]
)
# Key bindings
kb = KeyBindings()
@kb.add('q')
@kb.add('c-c')
def _(event):
" Quit application. "
event.app.exit()
@kb.add('w')
def _(event):
" Disable/enable wrapping. "
global wrap_lines
wrap_lines = not wrap_lines
# The `Application`
application = Application(
layout=Layout(body),
key_bindings=kb,
full_screen=True,
mouse_support=True)
def run():
application.run()
if __name__ == '__main__':
run()

View File

@ -1,70 +0,0 @@
#!/usr/bin/env python
"""
Example of Window margins.
This is mainly used for displaying line numbers and scroll bars, but it could
be used to display any other kind of information as well.
"""
from prompt_toolkit.application import Application
from prompt_toolkit.buffer import Buffer
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.layout.containers import HSplit, Window
from prompt_toolkit.layout.controls import BufferControl, FormattedTextControl
from prompt_toolkit.layout.layout import Layout
from prompt_toolkit.layout.margins import NumberedMargin, ScrollbarMargin
LIPSUM = """
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas
quis interdum enim. Nam viverra, mauris et blandit malesuada, ante est bibendum
mauris, ac dignissim dui tellus quis ligula. Aenean condimentum leo at
dignissim placerat. In vel dictum ex, vulputate accumsan mi. Donec ut quam
placerat massa tempor elementum. Sed tristique mauris ac suscipit euismod. Ut
tempus vehicula augue non venenatis. Mauris aliquam velit turpis, nec congue
risus aliquam sit amet. Pellentesque blandit scelerisque felis, faucibus
consequat ante. Curabitur tempor tortor a imperdiet tincidunt. Nam sed justo
sit amet odio bibendum congue. Quisque varius ligula nec ligula gravida, sed
convallis augue faucibus. Nunc ornare pharetra bibendum. Praesent blandit ex
quis sodales maximus.""" * 40
# Create text buffers. The margins will update if you scroll up or down.
buff = Buffer()
buff.text = LIPSUM
# 1. The layout
body = HSplit([
Window(FormattedTextControl('Press "q" to quit.'), height=1, style='reverse'),
Window(
BufferControl(buffer=buff),
# Add margins.
left_margins=[NumberedMargin(), ScrollbarMargin()],
right_margins=[ScrollbarMargin(), ScrollbarMargin()],
),
])
# 2. Key bindings
kb = KeyBindings()
@kb.add('q')
@kb.add('c-c')
def _(event):
" Quit application. "
event.app.exit()
# 3. The `Application`
application = Application(
layout=Layout(body),
key_bindings=kb,
full_screen=True)
def run():
application.run()
if __name__ == '__main__':
run()

View File

@ -1,94 +0,0 @@
#!/usr/bin/env python
"""
Vertical align demo with VSplit.
"""
from prompt_toolkit.application import Application
from prompt_toolkit.formatted_text import HTML
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.layout.containers import (
HSplit,
VerticalAlign,
VSplit,
Window,
WindowAlign,
)
from prompt_toolkit.layout.controls import FormattedTextControl
from prompt_toolkit.layout.dimension import D
from prompt_toolkit.layout.layout import Layout
from prompt_toolkit.widgets import Frame
TITLE = HTML(""" <u>VSplit VerticalAlign</u> example.
Press <b>'q'</b> to quit.""")
LIPSUM = """
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas
quis interdum enim. Nam viverra, mauris et blandit malesuada, ante est bibendum
mauris, ac dignissim dui tellus quis ligula. Aenean condimentum leo at
dignissim placerat."""
# 1. The layout
body = HSplit([
Frame(
Window(FormattedTextControl(TITLE), height=2), style='bg:#88ff88 #000000'),
VSplit([
Window(FormattedTextControl(HTML(' <u>VerticalAlign.TOP</u>')), height=4,
ignore_content_width=True, style='bg:#ff3333 #000000 bold', align=WindowAlign.CENTER),
Window(FormattedTextControl(HTML(' <u>VerticalAlign.CENTER</u>')), height=4,
ignore_content_width=True, style='bg:#ff3333 #000000 bold', align=WindowAlign.CENTER),
Window(FormattedTextControl(HTML(' <u>VerticalAlign.BOTTOM</u>')), height=4,
ignore_content_width=True, style='bg:#ff3333 #000000 bold', align=WindowAlign.CENTER),
Window(FormattedTextControl(HTML(' <u>VerticalAlign.JUSTIFY</u>')), height=4,
ignore_content_width=True, style='bg:#ff3333 #000000 bold', align=WindowAlign.CENTER),
], height=1, padding=1, padding_style='bg:#ff3333'),
VSplit([
# Top alignment.
HSplit([
Window(FormattedTextControl(LIPSUM), height=4, style='bg:#444488'),
Window(FormattedTextControl(LIPSUM), height=4, style='bg:#444488'),
Window(FormattedTextControl(LIPSUM), height=4, style='bg:#444488'),
], padding=1, padding_style='bg:#888888', align=VerticalAlign.TOP, padding_char='~'),
# Center alignment.
HSplit([
Window(FormattedTextControl(LIPSUM), height=4, style='bg:#444488'),
Window(FormattedTextControl(LIPSUM), height=4, style='bg:#444488'),
Window(FormattedTextControl(LIPSUM), height=4, style='bg:#444488'),
], padding=1, padding_style='bg:#888888', align=VerticalAlign.CENTER, padding_char='~'),
# Bottom alignment.
HSplit([
Window(FormattedTextControl(LIPSUM), height=4, style='bg:#444488'),
Window(FormattedTextControl(LIPSUM), height=4, style='bg:#444488'),
Window(FormattedTextControl(LIPSUM), height=4, style='bg:#444488'),
], padding=1, padding_style='bg:#888888', align=VerticalAlign.BOTTOM, padding_char='~'),
# Justify
HSplit([
Window(FormattedTextControl(LIPSUM), style='bg:#444488'),
Window(FormattedTextControl(LIPSUM), style='bg:#444488'),
Window(FormattedTextControl(LIPSUM), style='bg:#444488'),
], padding=1, padding_style='bg:#888888', align=VerticalAlign.JUSTIFY, padding_char='~'),
], padding=1, padding_style="bg:#ff3333 #ffffff", padding_char='.')
])
# 2. Key bindings
kb = KeyBindings()
@kb.add('q')
def _(event):
" Quit application. "
event.app.exit()
# 3. The `Application`
application = Application(
layout=Layout(body),
key_bindings=kb,
full_screen=True)
def run():
application.run()
if __name__ == '__main__':
run()

View File

@ -1,45 +0,0 @@
#!/usr/bin/env python
"""
Vertical split example.
"""
from prompt_toolkit.application import Application
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.layout.containers import VSplit, Window
from prompt_toolkit.layout.controls import FormattedTextControl
from prompt_toolkit.layout.layout import Layout
# 1. The layout
left_text = "\nVertical-split example. Press 'q' to quit.\n\n(left pane.)"
right_text = "\n(right pane.)"
body = VSplit([
Window(FormattedTextControl(left_text)),
Window(width=1, char='|'), # Vertical line in the middle.
Window(FormattedTextControl(right_text)),
])
# 2. Key bindings
kb = KeyBindings()
@kb.add('q')
def _(event):
" Quit application. "
event.app.exit()
# 3. The `Application`
application = Application(
layout=Layout(body),
key_bindings=kb,
full_screen=True)
def run():
application.run()
if __name__ == '__main__':
run()

View File

@ -1,160 +0,0 @@
#!/usr/bin/env python
"""
Simple example of a full screen application with a vertical split.
This will show a window on the left for user input. When the user types, the
reversed input is shown on the right. Pressing Ctrl-Q will quit the application.
"""
from prompt_toolkit.application import Application
from prompt_toolkit.buffer import Buffer
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.layout.containers import (
HSplit,
VSplit,
Window,
WindowAlign,
)
from prompt_toolkit.layout.controls import BufferControl, FormattedTextControl
from prompt_toolkit.layout.layout import Layout
# 3. Create the buffers
# ------------------
left_buffer = Buffer()
right_buffer = Buffer()
# 1. First we create the layout
# --------------------------
left_window = Window(BufferControl(buffer=left_buffer))
right_window = Window(BufferControl(buffer=right_buffer))
body = VSplit([
left_window,
# A vertical line in the middle. We explicitly specify the width, to make
# sure that the layout engine will not try to divide the whole width by
# three for all these windows.
Window(width=1, char='|', style='class:line'),
# Display the Result buffer on the right.
right_window,
])
# As a demonstration. Let's add a title bar to the top, displaying "Hello world".
# somewhere, because usually the default key bindings include searching. (Press
# Ctrl-R.) It would be really annoying if the search key bindings are handled,
# but the user doesn't see any feedback. We will add the search toolbar to the
# bottom by using an HSplit.
def get_titlebar_text():
return [
('class:title', ' Hello world '),
('class:title', ' (Press [Ctrl-Q] to quit.)'),
]
root_container = HSplit([
# The titlebar.
Window(height=1,
content=FormattedTextControl(get_titlebar_text),
align=WindowAlign.CENTER),
# Horizontal separator.
Window(height=1, char='-', style='class:line'),
# The 'body', like defined above.
body,
])
# 2. Adding key bindings
# --------------------
# As a demonstration, we will add just a ControlQ key binding to exit the
# application. Key bindings are registered in a
# `prompt_toolkit.key_bindings.registry.Registry` instance. We use the
# `load_default_key_bindings` utility function to create a registry that
# already contains the default key bindings.
kb = KeyBindings()
# Now add the Ctrl-Q binding. We have to pass `eager=True` here. The reason is
# that there is another key *sequence* that starts with Ctrl-Q as well. Yes, a
# key binding is linked to a sequence of keys, not necessarily one key. So,
# what happens if there is a key binding for the letter 'a' and a key binding
# for 'ab'. When 'a' has been pressed, nothing will happen yet. Because the
# next key could be a 'b', but it could as well be anything else. If it's a 'c'
# for instance, we'll handle the key binding for 'a' and then look for a key
# binding for 'c'. So, when there's a common prefix in a key binding sequence,
# prompt-toolkit will wait calling a handler, until we have enough information.
# Now, There is an Emacs key binding for the [Ctrl-Q Any] sequence by default.
# Pressing Ctrl-Q followed by any other key will do a quoted insert. So to be
# sure that we won't wait for that key binding to match, but instead execute
# Ctrl-Q immediately, we can pass eager=True. (Don't make a habit of adding
# `eager=True` to all key bindings, but do it when it conflicts with another
# existing key binding, and you definitely want to override that behaviour.
@kb.add('c-c', eager=True)
@kb.add('c-q', eager=True)
def _(event):
"""
Pressing Ctrl-Q or Ctrl-C 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 `Application.run()` call.
Note that Ctrl-Q does not work on all terminals. Sometimes it requires
executing `stty -ixon`.
"""
event.app.exit()
# Now we add an event handler that captures change events to the buffer on the
# left. If the text changes over there, we'll update the buffer on the right.
def default_buffer_changed(_):
"""
When the buffer on the left changes, update the buffer on
the right. We just reverse the text.
"""
right_buffer.text = left_buffer.text[::-1]
left_buffer.on_text_changed += default_buffer_changed
# 3. Creating an `Application` instance
# ----------------------------------
# This glues everything together.
application = Application(
layout=Layout(root_container, focused_element=left_window),
key_bindings=kb,
# Let's add mouse support!
mouse_support=True,
# Using an alternate screen buffer means as much as: "run full screen".
# It switches the terminal to an alternate screen.
full_screen=True)
# 4. Run the application
# -------------------
def run():
# Run the interface. (This runs the event loop until Ctrl-Q is pressed.)
application.run()
if __name__ == '__main__':
run()

View File

@ -1,352 +0,0 @@
#!/usr/bin/env python
"""
A simple example of a Notepad-like text editor.
"""
import datetime
from asyncio import Future, ensure_future
from prompt_toolkit.application import Application
from prompt_toolkit.application.current import get_app
from prompt_toolkit.completion import PathCompleter
from prompt_toolkit.filters import Condition
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.layout.containers import (
ConditionalContainer,
Float,
HSplit,
VSplit,
Window,
WindowAlign,
)
from prompt_toolkit.layout.controls import FormattedTextControl
from prompt_toolkit.layout.dimension import D
from prompt_toolkit.layout.layout import Layout
from prompt_toolkit.layout.menus import CompletionsMenu
from prompt_toolkit.lexers import DynamicLexer, PygmentsLexer
from prompt_toolkit.search import start_search
from prompt_toolkit.styles import Style
from prompt_toolkit.widgets import (
Button,
Dialog,
Label,
MenuContainer,
MenuItem,
SearchToolbar,
TextArea,
)
class ApplicationState:
"""
Application state.
For the simplicity, we store this as a global, but better would be to
instantiate this as an object and pass at around.
"""
show_status_bar = True
current_path = None
def get_statusbar_text():
return ' Press Ctrl-C to open menu. '
def get_statusbar_right_text():
return ' {}:{} '.format(
text_field.document.cursor_position_row + 1,
text_field.document.cursor_position_col + 1)
search_toolbar = SearchToolbar()
text_field = TextArea(
lexer=DynamicLexer(
lambda: PygmentsLexer.from_filename(
ApplicationState.current_path or '.txt',
sync_from_start=False)),
scrollbar=True,
line_numbers=True,
search_field=search_toolbar,
)
class TextInputDialog:
def __init__(self, title='', label_text='', completer=None):
self.future = Future()
def accept_text(buf):
get_app().layout.focus(ok_button)
buf.complete_state = None
return True
def accept():
self.future.set_result(self.text_area.text)
def cancel():
self.future.set_result(None)
self.text_area = TextArea(
completer=completer,
multiline=False,
width=D(preferred=40),
accept_handler=accept_text)
ok_button = Button(text='OK', handler=accept)
cancel_button = Button(text='Cancel', handler=cancel)
self.dialog = Dialog(
title=title,
body=HSplit([
Label(text=label_text),
self.text_area
]),
buttons=[ok_button, cancel_button],
width=D(preferred=80),
modal=True)
def __pt_container__(self):
return self.dialog
class MessageDialog:
def __init__(self, title, text):
self.future = Future()
def set_done():
self.future.set_result(None)
ok_button = Button(text='OK', handler=(lambda: set_done()))
self.dialog = Dialog(
title=title,
body=HSplit([
Label(text=text),
]),
buttons=[ok_button],
width=D(preferred=80),
modal=True)
def __pt_container__(self):
return self.dialog
body = HSplit([
text_field,
search_toolbar,
ConditionalContainer(
content=VSplit([
Window(FormattedTextControl(get_statusbar_text), style='class:status'),
Window(FormattedTextControl(get_statusbar_right_text),
style='class:status.right', width=9, align=WindowAlign.RIGHT),
], height=1),
filter=Condition(lambda: ApplicationState.show_status_bar)),
])
# Global key bindings.
bindings = KeyBindings()
@bindings.add('c-c')
def _(event):
" Focus menu. "
event.app.layout.focus(root_container.window)
#
# Handlers for menu items.
#
def do_open_file():
async def coroutine():
open_dialog = TextInputDialog(
title='Open file',
label_text='Enter the path of a file:',
completer=PathCompleter())
path = await show_dialog_as_float(open_dialog)
ApplicationState.current_path = path
if path is not None:
try:
with open(path, 'rb') as f:
text_field.text = f.read().decode('utf-8', errors='ignore')
except IOError as e:
show_message('Error', '{}'.format(e))
ensure_future(coroutine())
def do_about():
show_message('About', 'Text editor demo.\nCreated by Jonathan Slenders.')
def show_message(title, text):
async def coroutine():
dialog = MessageDialog(title, text)
await show_dialog_as_float(dialog)
ensure_future(coroutine())
async def show_dialog_as_float(dialog):
" Coroutine. "
float_ = Float(content=dialog)
root_container.floats.insert(0, float_)
app = get_app()
focused_before = app.layout.current_window
app.layout.focus(dialog)
result = await dialog.future
app.layout.focus(focused_before)
if float_ in root_container.floats:
root_container.floats.remove(float_)
return result
def do_new_file():
text_field.text = ''
def do_exit():
get_app().exit()
def do_time_date():
text = datetime.datetime.now().isoformat()
text_field.buffer.insert_text(text)
def do_go_to():
async def coroutine():
dialog = TextInputDialog(
title='Go to line',
label_text='Line number:')
line_number = await show_dialog_as_float(dialog)
try:
line_number = int(line_number)
except ValueError:
show_message('Invalid line number')
else:
text_field.buffer.cursor_position = \
text_field.buffer.document.translate_row_col_to_index(line_number - 1, 0)
ensure_future(coroutine())
def do_undo():
text_field.buffer.undo()
def do_cut():
data = text_field.buffer.cut_selection()
get_app().clipboard.set_data(data)
def do_copy():
data = text_field.buffer.copy_selection()
get_app().clipboard.set_data(data)
def do_delete():
text_field.buffer.cut_selection()
def do_find():
start_search(text_field.control)
def do_find_next():
search_state = get_app().current_search_state
cursor_position = text_field.buffer.get_search_position(
search_state, include_current_position=False)
text_field.buffer.cursor_position = cursor_position
def do_paste():
text_field.buffer.paste_clipboard_data(get_app().clipboard.get_data())
def do_select_all():
text_field.buffer.cursor_position = 0
text_field.buffer.start_selection()
text_field.buffer.cursor_position = len(text_field.buffer.text)
def do_status_bar():
ApplicationState.show_status_bar = not ApplicationState.show_status_bar
#
# The menu container.
#
root_container = MenuContainer(body=body, menu_items=[
MenuItem('File', children=[
MenuItem('New...', handler=do_new_file),
MenuItem('Open...', handler=do_open_file),
MenuItem('Save'),
MenuItem('Save as...'),
MenuItem('-', disabled=True),
MenuItem('Exit', handler=do_exit),
]),
MenuItem('Edit', children=[
MenuItem('Undo', handler=do_undo),
MenuItem('Cut', handler=do_cut),
MenuItem('Copy', handler=do_copy),
MenuItem('Paste', handler=do_paste),
MenuItem('Delete', handler=do_delete),
MenuItem('-', disabled=True),
MenuItem('Find', handler=do_find),
MenuItem('Find next', handler=do_find_next),
MenuItem('Replace'),
MenuItem('Go To', handler=do_go_to),
MenuItem('Select All', handler=do_select_all),
MenuItem('Time/Date', handler=do_time_date),
]),
MenuItem('View', children=[
MenuItem('Status Bar', handler=do_status_bar),
]),
MenuItem('Info', children=[
MenuItem('About', handler=do_about),
]),
], floats=[
Float(xcursor=True,
ycursor=True,
content=CompletionsMenu(
max_height=16,
scroll_offset=1)),
], key_bindings=bindings)
style = Style.from_dict({
'status': 'reverse',
'shadow': 'bg:#440044',
})
layout = Layout(
root_container,
focused_element=text_field)
application = Application(
layout=layout,
enable_page_navigation_bindings=True,
style=style,
mouse_support=True,
full_screen=True)
def run():
application.run()
if __name__ == '__main__':
run()

Some files were not shown because too many files have changed in this diff Show More