Itamar Katz
Itamar Katz

Reputation: 9645

Send literal string from python-vim script to a tmux pane

I am using Vim (8.0) and tmux (2.3) together in the following way: In a tmux session I have a window split to 2 panes, one pane has some text file open in Vim, the other pane has some program to which I want to send lines of text. A typical use case is sending lines from a Python script to IPython session running in the other pane.

I am doing this by a Vim script which uses python, code snippet example (assuming the target tmux pane is 0):

py import vim
python << endpython
cmd = "print 1+2"
vim_cmd = "silent !tmux send-keys -t 0 -l \"" + cmd + "\"" # -l for literal
vim.command(vim_cmd)
endpython

This works well, except for when cmd has some characters which has to be escaped, like %, #, $, etc. The cmd variable is read from the current line in the text file opened in Vim, so I can do something like cmd = cmd.replace('%', '\%') etc., but this has 2 disadvantages: first, I don't know all the vim characters which have to be escaped, so it has been trial and error up until now, and second, the characters " is not escaped properly - that is in the string Vim gets, the " just disappears, even if I do cmd = cmd.replace('"', '\"'). So, is there a general way to tell Vim to not interpret anything, just get a raw string and send it as is? If not, why is the " not escaped properly?

Upvotes: 5

Views: 856

Answers (1)

Ingo Karkat
Ingo Karkat

Reputation: 172608

Vimscript

You're looking for the shellescape() function. If you use the :! Vim command, the {special} argument needs to be 1.

silent execute '!tmux send-keys -t 0 -l ' . shellescape(cmd, 1)

But as you're not interested in (displaying) the shell output, and do not need to interact with the launched script, I would switch from :! to the lower-level system() command.

call system('tmux send-keys -t 0 -l ' . shellescape(cmd))

Python

The use of Python (instead of pure Vimscript) doesn't have any benefits (at least in the small snippet in your question). Instead, if you embed the Python cmd variable in a Vimscript expression, now you also need a Python function to escape the value as a Vimscript string (something like '%s'" % str(cmd).replace("'", "''"))). Alternatively, you could maintain the value in a Vim variable, and access it from Python via vim.vars.

Upvotes: 4

Related Questions