6
\$\begingroup\$

Motivation

I'd like to know how integrate the use of text editors (e.g. emacs, vim, etc.) into command-line Python programs.

Features

I'd like to be able to do the following:

  • Call a text editor from within a program in order to edit a file or buffer

  • Regain control after the text editor exits

  • Use temporary files, i.e. don't leave anything lying around after the program exits

  • Prepopulate the file or buffer with data

  • Get the edited text back for use in the program

Implementation

I wrote a small module named callvim.py (betraying my preferred choice of text editor) which creates a temporary file, populates it with some text, opens it with a text editor (defaults to vim), and prints the modified text:

#!/usr/bin/env python
# -*- encoding: ascii -*-
"""callvim.py

Demonstrates calling a text-editor (e.g. Vim) from within a Python script,
including passing input to the editor and reading output from the editor.
"""

import tempfile
import os
from subprocess import call

# Get the text editor from the shell, otherwise default to Vim
EDITOR = os.environ.get('EDITOR','vim')

# Set initial input with which to populate the buffer
initial_message = "Hello world!"

# Open a temporary file to communicate through (`tempfile` should avoid any filename conflicts)
#
# NOTE: Don't autodelete the file on close!
#       We want to reopen the file incase the editor uses a swap-file.
#
with tempfile.NamedTemporaryFile(suffix=".tmp", delete=False) as tf:

    # Write the initial content to the file I/O buffer
    tf.write(initial_message)

    # Flush the I/O buffer to make sure the data is written to the file
    tf.flush()

    # Open the file with the text editor
    call([EDITOR, tf.name])

# Reopen the file to read the edited data
with open(tf.name, 'r') as tf:

    # Read the file data into a variable
    edited_message = tf.read()

    # Output the data
    print(edited_message)
\$\endgroup\$
1
\$\begingroup\$

If I read it correctly, your edited_message would also contain your initial_message, is this expected?

I think this could be fixed by wrapping your input message this way in the file :

<Input message>

Input above this line will be ignored
###########################

<end of file>

You could then do :

edited_message = tf.read()
start_input_index = edited_message.find("###########################")

# Use the +2 to account for the \n
edited_message = edited_message[start_input_index + 2 :]

Maybe this exact code wouldn't work, I didn't test it, but the main idea is there, it would make more sense to your code.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.