# Buggy code
def create_key_bindings(history, python_input, history_mapping):
    """
    Key bindings.
    """
    bindings = KeyBindings()
    handle = bindings.add

    @handle(" ", filter=has_focus(history.history_buffer))
    def _(event):
        """
        Space: select/deselect line from history pane.
        """
        b = event.current_buffer
        line_no = b.document.cursor_position_row

        if line_no in history_mapping.selected_lines:
            # Remove line.
            history_mapping.selected_lines.remove(line_no)
            history_mapping.update_default_buffer()
        else:
            # Add line.
            history_mapping.selected_lines.add(line_no)
            history_mapping.update_default_buffer()

            # Update cursor position
            default_buffer = history.default_buffer
            default_lineno = (
                sorted(history_mapping.selected_lines).index(line_no)
                + history_mapping.result_line_offset
            )
            default_buffer.cursor_position = (
                default_buffer.document.translate_row_col_to_index(default_lineno, 0)
            )

        # Also move the cursor to the next line. (This way they can hold
        # space to select a region.)
        b.cursor_position = b.document.translate_row_col_to_index(line_no + 1, 0)

    @handle(" ", filter=has_focus(DEFAULT_BUFFER))
    @handle("delete", filter=has_focus(DEFAULT_BUFFER))
    @handle("c-h", filter=has_focus(DEFAULT_BUFFER))
    def _(event):
        """
        Space: remove line from default pane.
        """
        b = event.current_buffer
        line_no = b.document.cursor_position_row - history_mapping.result_line_offset

        if line_no >= 0:
            try:
                history_lineno = sorted(history_mapping.selected_lines)[line_no]
            except IndexError:
                pass  # When `selected_lines` is an empty set.
            else:
                history_mapping.selected_lines.remove(history_lineno)

            history_mapping.update_default_buffer()

    help_focussed = has_focus(history.help_buffer)
    main_buffer_focussed = has_focus(history.history_buffer) | has_focus(
        history.default_buffer
    )

    @handle("tab", filter=main_buffer_focussed)
    @handle("c-x", filter=main_buffer_focussed, eager=True)
    # Eager: ignore the Emacs [Ctrl-X Ctrl-X] binding.
    @handle("c-w", filter=main_buffer_focussed)
    def _(event):
        "Select other window."
        _select_other_window(history)

    @handle("f4")
    def _(event):
        "Switch between Emacs/Vi mode."
        python_input.vi_mode = not python_input.vi_mode

    @handle("f1")
    def _(event):
        "Display/hide help."
        _toggle_help(history)

    @handle("enter", filter=help_focussed)
    @handle("c-c", filter=help_focussed)
    @handle("c-g", filter=help_focussed)
    @handle("escape", filter=help_focussed)
    def _(event):
        "Leave help."
        event.app.layout.focus_previous()

    @handle("q", filter=main_buffer_focussed)
    @handle("f3", filter=main_buffer_focussed)
    @handle("c-c", filter=main_buffer_focussed)
    @handle("c-g", filter=main_buffer_focussed)
    def _(event):
        "Cancel and go back."
        event.app.exit(result=None)

    @handle("enter", filter=main_buffer_focussed)
    def _(event):
        "Accept input."
        event.app.exit(result=history.default_buffer.text)

    enable_system_bindings = Condition(lambda: python_input.enable_system_bindings)

    @handle("c-z", filter=enable_system_bindings)
    def _(event):
        "Suspend to background."
        event.app.suspend_to_background()

    return bindings


# Traceback (IndexError)
Traceback (most recent call last):                                                           │
File "/home/me/.local/bin/ptpython3", line 11, in <module>                               │
sys.exit(run())                                                                            │
File "/home/me/.local/lib/python3.6/site-packages/ptpython/entry_points/run_ptpython.py", line 74, in run
title='Python REPL (ptpython)')                                                            │
File "/home/me/.local/lib/python3.6/site-packages/ptpython/repl.py", line 320, in embed  │
cli.run()                                                                                  │
File "/home/me/.local/lib/python3.6/site-packages/prompt_toolkit/interface.py", line 415, in run
self.eventloop.run(self.input, self.create_eventloop_callbacks())                          │
File "/home/me/.local/lib/python3.6/site-packages/prompt_toolkit/eventloop/posix.py", line 159, in run
t()                                                                                        │
File "/home/me/.local/lib/python3.6/site-packages/prompt_toolkit/eventloop/posix.py", line 82, in read_from_stdin
inputstream.feed(data)                                                                     │
File "/home/me/.local/lib/python3.6/site-packages/prompt_toolkit/terminal/vt100_input.py", line 398, in feed
self._input_parser.send(c)                                                                 │
File "/home/me/.local/lib/python3.6/site-packages/prompt_toolkit/terminal/vt100_input.py", line 325, in _input_parser_generator
self._call_handler(prefix[0], prefix[0])                                                   │
File "/home/me/.local/lib/python3.6/site-packages/prompt_toolkit/terminal/vt100_input.py", line 340, in _call_handler
self.feed_key_callback(KeyPress(key, insert_text))                                         │
File "/home/me/.local/lib/python3.6/site-packages/prompt_toolkit/interface.py", line 1048, in feed_key
cli.input_processor.process_keys()                                                         │
File "/home/me/.local/lib/python3.6/site-packages/prompt_toolkit/key_binding/input_processor.py", line 219, in process_keys
self._process_coroutine.send(key_press)                                                    │
File "/home/me/.local/lib/python3.6/site-packages/prompt_toolkit/key_binding/input_processor.py", line 176, in _process
self._call_handler(matches[-1], key_sequence=buffer[:])                                    │
File "/home/me/.local/lib/python3.6/site-packages/prompt_toolkit/key_binding/input_processor.py", line 247, in _call_handler
handler.call(event)                                                                        │
File "/home/me/.local/lib/python3.6/site-packages/prompt_toolkit/key_binding/registry.py", line 61, in call
return self.handler(event)                                                                 │
File "/home/me/.local/lib/python3.6/site-packages/ptpython/history_browser.py", line 443, in _
history_mapping.update_default_buffer(event.cli)                                           │
File "/home/me/.local/lib/python3.6/site-packages/ptpython/history_browser.py", line 399, in update_default_buffer
self.get_new_document(b.cursor_position), bypass_readonly=True)                            │
File "/home/me/.local/lib/python3.6/site-packages/ptpython/history_browser.py", line 383, in get_new_document
lines.append(self.history_lines[line_no])                                                  │
IndexError: list index out of range                                                            │

# Fixed code
def create_key_bindings(history, python_input, history_mapping):
    """
    Key bindings.
    """
    bindings = KeyBindings()
    handle = bindings.add

    @handle(" ", filter=has_focus(history.history_buffer))
    def _(event):
        """
        Space: select/deselect line from history pane.
        """
        b = event.current_buffer
        line_no = b.document.cursor_position_row

        if not history_mapping.history_lines:
            # If we've no history, then nothing to do
            return

        if line_no in history_mapping.selected_lines:
            # Remove line.
            history_mapping.selected_lines.remove(line_no)
            history_mapping.update_default_buffer()
        else:
            # Add line.
            history_mapping.selected_lines.add(line_no)
            history_mapping.update_default_buffer()

            # Update cursor position
            default_buffer = history.default_buffer
            default_lineno = (
                sorted(history_mapping.selected_lines).index(line_no)
                + history_mapping.result_line_offset
            )
            default_buffer.cursor_position = (
                default_buffer.document.translate_row_col_to_index(default_lineno, 0)
            )

        # Also move the cursor to the next line. (This way they can hold
        # space to select a region.)
        b.cursor_position = b.document.translate_row_col_to_index(line_no + 1, 0)

    @handle(" ", filter=has_focus(DEFAULT_BUFFER))
    @handle("delete", filter=has_focus(DEFAULT_BUFFER))
    @handle("c-h", filter=has_focus(DEFAULT_BUFFER))
    def _(event):
        """
        Space: remove line from default pane.
        """
        b = event.current_buffer
        line_no = b.document.cursor_position_row - history_mapping.result_line_offset

        if line_no >= 0:
            try:
                history_lineno = sorted(history_mapping.selected_lines)[line_no]
            except IndexError:
                pass  # When `selected_lines` is an empty set.
            else:
                history_mapping.selected_lines.remove(history_lineno)

            history_mapping.update_default_buffer()

    help_focussed = has_focus(history.help_buffer)
    main_buffer_focussed = has_focus(history.history_buffer) | has_focus(
        history.default_buffer
    )

    @handle("tab", filter=main_buffer_focussed)
    @handle("c-x", filter=main_buffer_focussed, eager=True)
    # Eager: ignore the Emacs [Ctrl-X Ctrl-X] binding.
    @handle("c-w", filter=main_buffer_focussed)
    def _(event):
        "Select other window."
        _select_other_window(history)

    @handle("f4")
    def _(event):
        "Switch between Emacs/Vi mode."
        python_input.vi_mode = not python_input.vi_mode

    @handle("f1")
    def _(event):
        "Display/hide help."
        _toggle_help(history)

    @handle("enter", filter=help_focussed)
    @handle("c-c", filter=help_focussed)
    @handle("c-g", filter=help_focussed)
    @handle("escape", filter=help_focussed)
    def _(event):
        "Leave help."
        event.app.layout.focus_previous()

    @handle("q", filter=main_buffer_focussed)
    @handle("f3", filter=main_buffer_focussed)
    @handle("c-c", filter=main_buffer_focussed)
    @handle("c-g", filter=main_buffer_focussed)
    def _(event):
        "Cancel and go back."
        event.app.exit(result=None)

    @handle("enter", filter=main_buffer_focussed)
    def _(event):
        "Accept input."
        event.app.exit(result=history.default_buffer.text)

    enable_system_bindings = Condition(lambda: python_input.enable_system_bindings)

    @handle("c-z", filter=enable_system_bindings)
    def _(event):
        "Suspend to background."
        event.app.suspend_to_background()

    return bindings