prompt-toolkit / python-prompt-toolkit

Library for building powerful interactive command line applications in Python
https://python-prompt-toolkit.readthedocs.io/
BSD 3-Clause "New" or "Revised" License
9.21k stars 715 forks source link

Customizable prompt with various tokens #718

Open eirnym opened 5 years ago

eirnym commented 5 years ago

The request is to create beautiful prompts to have an ability to customize prompt string with extendable list of parameters and coloring.

For some programs like iPython or ptpython users usually don't require something very specific like time or database or path, but users for other applications like mycli or pgcli usually require some parameters specified in the prompt.

It's fine when you able to specify coloring for whole line if it's short or isn't informative. But if you in mycli/pgcli add date, user, host and a database, I'd like to have whole line be colored as I do it in my shell.

Simplified version of my PS1 setup in my .zshrc (without custom VCS calls) looks like on picture and a script below (database is a plain string).

I'd like to have the the same simple mechanism to specify variables and custom colors for them. This library able to color complex syntax while input and it seems to be capable to handle such prompt configuration as well.

This includes rprompt parameter too, but for me the priority is the prompt string itself.

zrzut ekranu 2018-09-06 o 14 55 12

autoload colors
colors

export PS1="[%{%F{165}%}%D %{%F{226}%}%*%{$reset_color%}] %{%F{214}%}%U%n%u%{$reset_color%}@%{%F{46}%}%M%{$reset_color%} (%{${fg_bold[yellow]}%}database%{$reset_color%})> "

Short info on format script above:

jonathanslenders commented 5 years ago

Hi @eirnym,

Actually, you can already achieve this very easily in the following way.

Using ANSI escapes

  1. As an application author, create a list of variables that you want to expose to the prompt. This could be a dictionary. Let's say this is called params.

    params = {
    'user': 'john',
    'host': 'debian'
    }
  2. As a user of the library, create a string for the prompt in the configuration file. Let's say it looks like this:

    ansi_prompt="\x1b[31m{user}@\x1b[30m{host}"
  3. Then, in the application, where you create the prompt, do:

    
    from prompt_toolkit.formatted_text import ANSI
    from prompt_toolkit.shortcuts import PromptSession

session = PromptSession(ANSI(ansi_prompt.format(** params))) while True: session.prompt()


Notice: this ``format()`` call doesn't ANSI-escape parameters yet. I'm going to add this to prompt toolkit, so that this becomes a safe operation as well. Then it will become ``ANSI(prompt).format(**params)``.

Also notice that it's not strictly necessary to create a ``PromptSession``. Formatted text is a very central concept in prompt_toolkit 2.0 and can be used in many different places. It also works for rprompts or toolbars.

Also notice that this ``params`` dict is now precomputed in this example. I guess you could pass any object that implements ``__getitem__`` to the format function and make it lazy if needed.

Using HTML
=======

Further, prompt_toolkit does support the same kind of string formatting for HTML, for those applications that prefer it.

```python
html_prompt="<bold>{user}</bold>@<style fg="ansired" bg="purple">{host}</style>"

and

from prompt_toolkit.formatted_text import HTML
from prompt_toolkit.shortcuts import PromptSession

session = PromptSession(HTML(html_prompt).format(** params))
while True:
    session.prompt()

Notice that we call the format() function on the HTML object itself. Not on the string. This ensures that all parameters are properly escaped.

So, I don't think there is much in prompt_toolkit itself to be done, except maybe improving the documentation. Let me know if I'm missing something.

eirnym commented 5 years ago

The idea wasn't only token-specific coloring, but also providing common API to create custom tokens and insert them automatically. Coloring could be done by ANSI

jonathanslenders commented 5 years ago

Hi @eirnym,

Prompt_toolkit tries to be application agnostic. While this formatting is very application specific. For hostname, for instance, in the case an an SQL client, that's not the local hostname.

Further, I think this can be perfectly developed on top of prompt_toolkit. Is this something you are willing to do? You can create a library that takes such a string, and turns it into FormattedText for use in a prompt.

eirnym commented 5 years ago

Hi @jonathanslenders,

I gave an example to show what developers and users can achieve with this option without generating a lot of code to support it.

Actual tokens are defined by an actual application, and how to put these tokens together is defined by application and/or a end user.

The only token could be defined by prompt toolkit is date with ability to define a format string