5

Goal

I am trying to create and edit a temporary file in vim (exactly the same behavior as a commit script in git/hg/svn).

Current code

I found a method to do so in this answer: call up an EDITOR (vim) from a python script

import sys, tempfile, os
from subprocess import call
EDITOR = os.environ.get('EDITOR','vim')
initial_message = "write message here:"
with tempfile.NamedTemporaryFile(suffix=".tmp") as tmp:
  tmp.write(initial_message)
  tmp.flush()
  call([EDITOR, tmp.name])
  tmp.seek(0)
  print tmp.read()

The Issue

When I run the above code, the tempfile does not read the changes made in vim. Here is the output after I have added several other lines in vim:

fgimenez@dn0a22805f> ./note.py
Please edit the file:

fgimenez@dn0a22805f>

Now for the interesting (weird) part. If I change my editor to nano or emacs, the script works just fine! So far, this only seems to break when I use vim or textedit.

As another experiment, I tried calling a couple editors in a row to see what happens. The modified code is:

with tempfile.NamedTemporaryFile(suffix=".tmp") as tmp:
  tmp.write(initial_message)
  tmp.flush()
  # CALLING TWO EDITORS HERE, VIM THEN NANO
  call(['vim', tmp.name])
  raw_input("pausing between editors, just press enter")
  call(['nano', tmp.name])
  tmp.seek(0)
  print tmp.read()

I.e. I edit with vim then nano. What happens is that nano DOES register the changes made by vim, but python doesn't register anything (same result as before):

fgimenez@dn0a22805f> ./note.py
Please edit the file:

fgimenez@dn0a22805f>

BUT, if I edit with nano first, then vim, python still registers the nano edits but not the vim ones!

with tempfile.NamedTemporaryFile(suffix=".tmp") as tmp:
  tmp.write(initial_message)
  tmp.flush()
  # CALLING TWO EDITORS HERE, NANO THEN VIM
  call(['nano', tmp.name])
  raw_input("pausing between editors, just press enter")
  call(['vim', tmp.name])
  tmp.seek(0)
  print tmp.read()

Ouput from running the program and adding a\nb\nc in nano and d\ne\nf in vim:

fgimenez@dn0a22805f> ./note.py
Please edit the file:
a
b
c

fgimenez@dn0a22805f>

It seems as if using vim or textedit eliminates the ability to append to the file. I'm completely confused here, and I just want to edit my notes in vim...

Edit 1: Clarifications

  • I am on osx Mavericks

  • I call vim from the shell (not MacVim) and end the session with ZZ (also tried :w :q)

Community
  • 1
  • 1
Francisco
  • 375
  • 2
  • 5
  • 9
  • Just as a sanity check, I assume you are writing the buffer in vim using something like `:w`, right? – Turix Apr 10 '14 at 00:34
  • Very strange. I cannot reproduce it. Which OS are you running? Check your settings: maybe vim is aliased? On the side note, on a Windows box the temporary file gets locked and cannot be edited by a subprocess whatsoever. – user58697 Apr 10 '14 at 00:50
  • Are you using terminal vim, or MacVim (gVim)? If you launch a graphical version, it will exit immediately, before you had any chance to make your changes, let alone save them (and TextMate should do the same thing). To fix, call with `vim -f` to ensure it stays in foreground. – Amadan Apr 10 '14 at 01:19
  • @user58697: I'd asume OSX, given the mention of TextMate. – Amadan Apr 10 '14 at 01:21
  • Thanks for your attention. To answer your comments: I am on osx Mavericks. I call vim from the shell (not MacVim) and end the session with ZZ (also tried :w :q). I just tried with `vim -f`, and it didn't work. Also, just to clarify, I was using textedit, not TextMate. – Francisco Apr 10 '14 at 01:47
  • 1
    I don't think vim appends to the current file. I think it rewrites the whole file to disk (which might mean its a brand new file) you can use `:w >>` to append everything to the temp file (or pass a range to `w` to only append a range) but that would get tedious really quickly. I do not know of an easy solution to fix this. – FDinoff Apr 10 '14 at 05:19
  • Oh wow, I just tried and that actually did the trick. That is annoying though. I'm wondering how git/mercurial manage to get around this issue. Do they just manually manage their temporary files? – Francisco Apr 10 '14 at 06:29
  • git create a temp file the call $EDITOR to edit – number5 Apr 10 '14 at 06:52

2 Answers2

2

I'm no Python expert, but it looks like you're keeping the handle to the temp file open while Vim is editing the file, and then attempt to read in the edited contents from the handle. By default, Vim creates a copy of the original file, writes the new contents to another file, and then renames it to the original (see :help 'backupcopy' for the details; other editors like nano apparently don't do it this way). This means that the Python handle still points to the original file (even though it may have already been deleted from the file system, depending on the Vim settings), and you get the original content.

You either need to reconfigure Vim (see :help 'writebackup'), or (better) change the Python implementation to re-open the same temp file name after Vim has exited, in order to get a handle to the new written file contents.

Ingo Karkat
  • 167,457
  • 16
  • 250
  • 324
2

I had the same problem on OS X after my code worked fine on Linux. As Ingo suggests, you can get the latest contents by re-opening the file. To do this, you probably want to create a temporary file with delete=False and then explicitly delete the file when you're done:

import sys, tempfile, os
from subprocess import call
EDITOR = os.environ.get('EDITOR','vim')
initial_message = "write message here:"
with tempfile.NamedTemporaryFile(suffix=".tmp", delete=False) as tmp:
  tmp.write(initial_message)
  tmp.flush()
  call([EDITOR, tmp.name])
  tmp.close()
  with open(tmp.name) as f:
    print f.read()
  os.unlink(tmp.name)
Aaron Feldman
  • 474
  • 4
  • 7