3

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.

WalksB
  • 498
  • 2
  • 14
  • 1
    You can select a rectangular block with Opt+drag (on Terminal) or Cmd+Opt+drag (on iTerm2), that way you can select the code without the leading marks. – filbranden Mar 09 '20 at 02:32
  • 1
    Thanks, that helps. Best case scenario though is if there is a way to do it in vim mode directly. – WalksB Mar 09 '20 at 02:43
  • Does this answer your question? [How to Copy from IPython session without terminal prompts](https://stackoverflow.com/questions/41070403/how-to-copy-from-ipython-session-without-terminal-prompts) – filbranden Mar 09 '20 at 02:44
  • 1
    [One of the answers](https://stackoverflow.com/a/47104647/6382242) does mention copying from vi mode, but doesn't mention how to do it for some reason, nor does it talk about copying to system clipboard. The ```"+y``` command doesn't work on my IPython 7.10.1 – WalksB Mar 09 '20 at 02:52
  • I edited the question to reflect on that answer. – WalksB Mar 09 '20 at 02:57
  • This looks interesting too: https://gist.github.com/vpontis/46e5d3154cda92ce3e0f – filbranden Mar 09 '20 at 03:05
  • IPython is just using readline under the hood for “vi mode” (i think—or something similar). At any rate, it’s up to whatever is supplying the emulation. And most of them are (as you have noticed) not quite up to spec. – D. Ben Knoble Mar 09 '20 at 14:18

3 Answers3

1

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.'

CyclicUniverse
  • 133
  • 1
  • 5
  • Interesting. So what you're saying is I shouldn't run IPython in Vi mode, but I should run IPython in normal mode but from within Vim (using the :terminal command)? – WalksB Mar 11 '20 at 23:29
  • I tried it! It does work. I haven't yet messed around with this setup much, but I'm curious why anybody would choose to use IPython in Vi mode when they can just load an IPython session from within a Vim window. Any thoughts? – WalksB Mar 11 '20 at 23:32
  • IPython in vi mode is similar to readline vi mode. It does not include all features of vim, such as highlight/select. Therefore, you would need to use IPython inside vim terminal to use all vim features. vi mode in IPython is still useful though, because you can go up and down a multiline command using j & k keys. go to the end of a line using $ and such, basically everything that you could do in bash vi mode (set -o vi) – CyclicUniverse Mar 12 '20 at 06:18
  • You can use both: IPython in a vim terminal & that IPython shell should accept user input in vi mode. – CyclicUniverse Mar 12 '20 at 06:30
1

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)
severin
  • 11
  • 2
0

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()