Yank/copy selected text to clipboard in IPython Vi mode

Question:

I can’t figure out how to copy lines that I selected/highlighted in IPython in Vim mode to the normal clipboard (to be pasted outside of the IPython shell). Normally, in vim I can yank text using "+y and paste it somewhere else, but hitting those keys in IPython Vim mode doesn’t seem to work. So I end up having to highlight the desired text using my mouse and copying it with Command-C.

This is an annoyance because if I have multiple lines in IPython there will be many junk characters that I have to filter out as seen below:

In [8]: import numpy as np 
   ...: import math 
   ...:  
   ...: print("hi") 
   ...: while(True): 
   ...:     break 
   ...:  
   ...: x = 3 
   ...: y = 4 
   ...:  
   ...:   

Here I would have to filter out the In [8] and the ...: on each line. But selecting using v or V appropriately ignores these junk characters.

This answer doesn’t say how to do it in Vi mode and also doesn’t mention anything about yanking to the system’s clipboard.

Asked By: WalksB

||

Answers:

if you are running ipython inside vim terminal, you can type the following in ipython:
%history -l 10

This will print last 10 commands without the leading dots. Which can be easily copied.

You need to open the ipython in vim terminal. And then, after typing the %history command (above), you will need to go to normal mode with key-combination Ctrl-W Shift_N. Then, copy multiple lines using V (block visual model) into + register with "+y command. You can then copy it into another vim buffer using "+p or another application such as gedit using ‘right click, then paste.’

Answered By: CyclicUniverse

Here is a little plug-in script I wrote for this very purpose after digging into the docs for IPython and prompt-toolkit: y yanks to system clipboard, p pastes after the cursor (this is different from normal vi(m) behaviour). This script is to be added to the startup subdirectory of your IPython profile config directory (See IPython docs or example config)

#!/usr/bin/env python3

from IPython import get_ipython
from prompt_toolkit.enums import DEFAULT_BUFFER
from prompt_toolkit.keys import Keys
from prompt_toolkit.filters import HasFocus, ViNavigationMode, ViSelectionMode, ViInsertMode, EmacsInsertMode, HasSelection
from prompt_toolkit.key_binding.vi_state import InputMode

import pyperclip


ip = get_ipython()


def copy_selection_to_clipboard(event):
    buffer = event.current_buffer
    data = buffer.copy_selection()
    pyperclip.copy(data.text)


def paste_from_clipboard(event):
    buffer = event.current_buffer
    data = pyperclip.paste()
    event.cli.vi_state.input_mode = InputMode.INSERT
    buffer.insert_text(data)
    event.cli.vi_state.input_mode = InputMode.NAVIGATION


# Register the shortcut if IPython is using prompt_toolkit
if getattr(ip, 'pt_app', None):

    filter_ = HasFocus(DEFAULT_BUFFER) & ViSelectionMode()
    ip.pt_app.key_bindings.add_binding('y', filter=filter_)(copy_selection_to_clipboard)

    filter_ = HasFocus(DEFAULT_BUFFER) & ViNavigationMode()
    ip.pt_app.key_bindings.add_binding('p', filter=filter_)(paste_from_clipboard)
Answered By: severin

I just found a better way to use the system clipboard in ipython vi-mode that just works: Just use the PyperclipClipboard for prompt_toolkit:

In your ~/.ipython/profile_default/startup/keybindings.py (or any other startup file)

from IPython import get_ipython
from prompt_toolkit.clipboard.pyperclip import PyperclipClipboard
ip = get_ipython()
if getattr(ip, "pt_app", None):
    ip.pt_app.clipboard = PyperclipClipboard()
Answered By: Martin Bergtholdt
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.