Remove python toolkit from lib, install from pypi
|
@ -1 +0,0 @@
|
|||
comment: off
|
|
@ -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
|
|
@ -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
|
|
@ -1,11 +0,0 @@
|
|||
Authors
|
||||
=======
|
||||
|
||||
Creator
|
||||
-------
|
||||
Jonathan Slenders <jonathan AT slenders.be>
|
||||
|
||||
Contributors
|
||||
------------
|
||||
|
||||
- Amjith Ramanujam <amjith.r AT gmail.com>
|
|
@ -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.
|
|
@ -1,4 +0,0 @@
|
|||
include *rst LICENSE CHANGELOG MANIFEST.in
|
||||
recursive-include examples *.py
|
||||
recursive-include tests *.py
|
||||
prune examples/sample?/build
|
|
@ -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.)
|
|
@ -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/
|
||||
|
|
@ -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
|
|
@ -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."
|
|
@ -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
|
Before Width: | Height: | Size: 71 KiB |
Before Width: | Height: | Size: 76 KiB |
Before Width: | Height: | Size: 93 KiB |
Before Width: | Height: | Size: 93 KiB |
Before Width: | Height: | Size: 132 KiB |
Before Width: | Height: | Size: 132 KiB |
Before Width: | Height: | Size: 137 KiB |
Before Width: | Height: | Size: 136 KiB |
Before Width: | Height: | Size: 142 KiB |
Before Width: | Height: | Size: 103 KiB |
Before Width: | Height: | Size: 91 KiB |
Before Width: | Height: | Size: 114 KiB |
Before Width: | Height: | Size: 55 KiB |
Before Width: | Height: | Size: 83 KiB |
Before Width: | Height: | Size: 80 KiB |
Before Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 8.4 KiB |
Before Width: | Height: | Size: 8.0 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 9.5 KiB |
Before Width: | Height: | Size: 130 KiB |
Before Width: | Height: | Size: 101 KiB |
Before Width: | Height: | Size: 59 KiB |
Before Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 201 KiB |
Before Width: | Height: | Size: 146 KiB |
Before Width: | Height: | Size: 123 KiB |
Before Width: | Height: | Size: 167 KiB |
Before Width: | Height: | Size: 124 KiB |
Before Width: | Height: | Size: 186 KiB |
Before Width: | Height: | Size: 178 KiB |
Before Width: | Height: | Size: 196 KiB |
Before Width: | Height: | Size: 78 KiB |
|
@ -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/>`_.
|
|
@ -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
|
|
@ -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. |
|
||||
+---------------------------------------------------------------+
|
|
@ -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())
|
|
@ -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)
|
|
@ -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
|
|
@ -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.
|
|
@ -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.
|
|
@ -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`.
|
|
@ -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.
|
|
@ -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,
|
||||
)
|
||||
# ...
|
||||
)
|
|
@ -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.
|
|
@ -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()
|
|
@ -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.
|
|
@ -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
|
|
@ -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>`.
|
|
@ -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)
|
|
@ -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>`
|
|
@ -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
|
|
@ -1,10 +0,0 @@
|
|||
.. _tutorials:
|
||||
|
||||
Tutorials
|
||||
=========
|
||||
|
||||
.. toctree::
|
||||
:caption: Contents:
|
||||
:maxdepth: 1
|
||||
|
||||
repl
|
|
@ -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/
|
|
@ -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
|
||||
|
|
@ -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)
|
|
@ -1,11 +0,0 @@
|
|||
.. _upgrading:
|
||||
|
||||
Upgrading
|
||||
=========
|
||||
|
||||
.. toctree::
|
||||
:caption: Contents:
|
||||
:maxdepth: 1
|
||||
|
||||
2.0
|
||||
3.0
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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">--></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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|