##// END OF EJS Templates
Deprecate inputtransformer since 7.0...
Deprecate inputtransformer since 7.0 Actually emit deprecation warnings when using inputtransformer which is deprecated.

File last commit:

r28557:e77ba5f0
r28985:8c051e61
Show More
details.rst
321 lines | 11.9 KiB | text/x-rst | RstLexer

Specific config details

Custom Prompts

From IPython 5, prompts are produced as a list of Pygments tokens, which are tuples of (token_type, text). You can customise prompts by writing a method which generates a list of tokens.

There are four kinds of prompt:

  • The in prompt is shown before the first line of input (default like In [1]:).
  • The continuation prompt is shown before further lines of input (default like ...:).
  • The rewrite prompt is shown to highlight how special syntax has been interpreted (default like ----->).
  • The out prompt is shown before the result from evaluating the input (default like Out[1]:).

Custom prompts are supplied together as a class. If you want to customise only some of the prompts, inherit from :class:`IPython.terminal.prompts.Prompts`, which defines the defaults. The required interface is like this:

Prompt style definition. shell is a reference to the :class:`~.TerminalInteractiveShell` instance.

Here is an example Prompt class that will show the current working directory in the input prompt:

from IPython.terminal.prompts import Prompts, Token
import os

class MyPrompt(Prompts):
     def in_prompt_tokens(self):
         return [(Token, os.getcwd()),
                 (Token.Prompt, ' >>>')]

To set the new prompt, assign it to the prompts attribute of the IPython shell:

In [2]: ip = get_ipython()
   ...: ip.prompts = MyPrompt(ip)

/home/bob >>> # it works

See IPython/example/utils/cwd_prompt.py for an example of how to write extensions to customise prompts.

Inside IPython or in a startup script, you can use a custom prompts class by setting get_ipython().prompts to an instance of the class. In configuration, TerminalInteractiveShell.prompts_class may be set to either the class object, or a string of its full importable name.

To include invisible terminal control sequences in a prompt, use Token.ZeroWidthEscape as the token type. Tokens with this type are ignored when calculating the width.

Colours in the prompt are determined by the token types and the highlighting style; see below for more details. The tokens used in the default prompts are Prompt, PromptNum, OutPrompt and OutPromptNum.

Terminal Colors

There are two main configuration options controlling colours.

InteractiveShell.colors sets the colour of tracebacks and object info (the output from e.g. zip?). It may also affect other things if the option below is set to 'legacy'. It has four case-insensitive values: 'nocolor', 'neutral', 'linux', 'lightbg'. The default is neutral, which should be legible on either dark or light terminal backgrounds. linux is optimised for dark backgrounds and lightbg for light ones.

TerminalInteractiveShell.highlighting_style determines prompt colours and syntax highlighting. It takes the name (as a string) or class (as a subclass of pygments.style.Style) of a Pygments style, or the special value 'legacy' to pick a style in accordance with InteractiveShell.colors.

You can see the Pygments styles available on your system by running:

from pygments.styles import get_all_styles
list(get_all_styles())

Additionally, TerminalInteractiveShell.highlighting_style_overrides can override specific styles in the highlighting. It should be a dictionary mapping Pygments token types to strings defining the style. See Pygments' documentation for the language used to define styles.

Colors in the pager

On some systems, the default pager has problems with ANSI colour codes. To configure your default pager to allow these:

  1. Set the environment PAGER variable to less.
  2. Set the environment LESS variable to -r (plus any other options you always want to pass to less by default). This tells less to properly interpret control sequences, which is how color information is given to your terminal.

Editor configuration

IPython can integrate with text editors in a number of different ways:

  • Editors (such as (X)Emacs, vim and TextMate) can send code to IPython for execution.
  • IPython's %edit magic command can open an editor of choice to edit a code block.

The %edit command (and its alias %ed) will invoke the editor set in your environment as :envvar:`EDITOR`. If this variable is not set, it will default to vi under Linux/Unix and to notepad under Windows. You may want to set this variable properly and to a lightweight editor which doesn't take too long to start (that is, something other than a new instance of Emacs). This way you can edit multi-line code quickly and with the power of a real editor right inside IPython.

You can also control the editor by setting :attr:`TerminalInteractiveShell.editor` in :file:`ipython_config.py`.

Vim

Paul Ivanov's vim-ipython provides powerful IPython integration for vim.

(X)Emacs

If you are a dedicated Emacs user, and want to use Emacs when IPython's %edit magic command is called you should set up the Emacs server so that new requests are handled by the original process. This means that almost no time is spent in handling the request (assuming an Emacs process is already running). For this to work, you need to set your EDITOR environment variable to 'emacsclient'. The code below, supplied by Francois Pinard, can then be used in your :file:`.emacs` file to enable the server:

(defvar server-buffer-clients)
(when (and (fboundp 'server-start) (string-equal (getenv "TERM") 'xterm))
  (server-start)
  (defun fp-kill-server-with-buffer-routine ()
    (and server-buffer-clients (server-done)))
  (add-hook 'kill-buffer-hook 'fp-kill-server-with-buffer-routine))

Thanks to the work of Alexander Schmolck and Prabhu Ramachandran, currently (X)Emacs and IPython get along very well in other ways.

With (X)EMacs >= 24, You can enable IPython in python-mode with:

(require 'python)
(setq python-shell-interpreter "ipython")

Keyboard Shortcuts

You can modify, disable or modify keyboard shortcuts for IPython Terminal using :std:configtrait:`TerminalInteractiveShell.shortcuts` traitlet.

The list of shortcuts is available in the Configuring IPython :ref:`terminal-shortcuts-list` section.

Advanced configuration

Creating custom commands requires adding custom code to a :ref:`startup file <startup_files>`:

from IPython import get_ipython
from prompt_toolkit.enums import DEFAULT_BUFFER
from prompt_toolkit.keys import Keys
from prompt_toolkit.filters import HasFocus, HasSelection, ViInsertMode, EmacsInsertMode

ip = get_ipython()
insert_mode = ViInsertMode() | EmacsInsertMode()

def insert_unexpected(event):
    buf = event.current_buffer
    buf.insert_text('The Spanish Inquisition')
# Register the shortcut if IPython is using prompt_toolkit
if getattr(ip, 'pt_app', None):
    registry = ip.pt_app.key_bindings
    registry.add_binding(Keys.ControlN,
                     filter=(HasFocus(DEFAULT_BUFFER)
                             & ~HasSelection()
                             & insert_mode))(insert_unexpected)

Here is a second example that bind the key sequence j, k to switch to VI input mode to Normal when in insert mode:

from IPython import get_ipython
from prompt_toolkit.enums import DEFAULT_BUFFER
from prompt_toolkit.filters import HasFocus, ViInsertMode
from prompt_toolkit.key_binding.vi_state import InputMode

ip = get_ipython()

def switch_to_navigation_mode(event):
   vi_state = event.cli.vi_state
   vi_state.input_mode = InputMode.NAVIGATION

if getattr(ip, 'pt_app', None):
   registry = ip.pt_app.key_bindings
   registry.add_binding(u'j',u'k',
                        filter=(HasFocus(DEFAULT_BUFFER)
                                 & ViInsertMode()))(switch_to_navigation_mode)

For more information on filters and what you can do with the event object, see the prompt_toolkit docs.

Enter to execute

In the Terminal IPython shell – which by default uses the prompt_toolkit interface, the semantic meaning of pressing the :kbd:`Enter` key can be ambiguous. In some case :kbd:`Enter` should execute code, and in others it should add a new line. IPython uses heuristics to decide whether to execute or insert a new line at cursor position. For example, if we detect that the current code is not valid Python, then the user is likely editing code and the right behavior is to likely to insert a new line. If the current code is a simple statement like ord('*'), then the right behavior is likely to execute. Though the exact desired semantics often varies from users to users.

As the exact behavior of :kbd:`Enter` is ambiguous, it has been special cased to allow users to completely configure the behavior they like. Hence you can have enter always execute code. If you prefer fancier behavior, you need to get your hands dirty and read the prompt_toolkit and IPython documentation though. See :ghpull:`10500`, set the c.TerminalInteractiveShell.handle_return option and get inspiration from the following example that only auto-executes the input if it begins with a bang or a modulo character (! or %). To use the following code, add it to your IPython configuration:

def custom_return(shell):

    """This function is required by the API. It takes a reference to
    the shell, which is the same thing `get_ipython()` evaluates to.
    This function must return a function that handles each keypress
    event. That function, named `handle` here, references `shell`
    by closure."""

    def handle(event):

        """This function is called each time `Enter` is pressed,
        and takes a reference to a Prompt Toolkit event object.
        If the current input starts with a bang or modulo, then
        the input is executed, otherwise a newline is entered,
        followed by any spaces needed to auto-indent."""

        # set up a few handy references to nested items...

        buffer = event.current_buffer
        document = buffer.document
        text = document.text

        if text.startswith('!') or text.startswith('%'): # execute the input...

            buffer.accept_action.validate_and_handle(event.cli, buffer)

        else: # insert a newline with auto-indentation...

            if document.line_count > 1: text = text[:document.cursor_position]
            indent = shell.check_complete(text)[1]
            buffer.insert_text('\n' + indent)

            # if you just wanted a plain newline without any indentation, you
            # could use `buffer.insert_text('\n')` instead of the lines above

    return handle

c.TerminalInteractiveShell.handle_return = custom_return