7

Using the LaTeX-package pythontex I one can insert python code into the latex document which is executed (and printed to your latex file if you want) if you run latex. I use auctex for editing latex files, however editing the python code inside the latex document is a bit painful since the buffer is in latex mode and not in python mode, so there is no help for proper indentation of the python code and no syntax highlighting.

So is there any reasonable way to mix the python mode with the latex mode? For example that the buffer automatically jumps to python mode if the point is inside a python code snipped? What do I have to add to my .emacs file to make it work? Any other ideas?

\documentclass[tikz]{standalone}
\usepackage{pgfplots}
\usepackage{pythontex}

\begin{document}

\begin{pycode}
print('test1')
def f( ):
    print('test2')

f()
\end{pycode}   

\pyc{f()}
\end{document}

Note that pythontex has multiple environments and commands which can contain pythoncode, for example pycode or pyverbatim as environments or \pyc or \py as commands.

6
  • 1
    This is something that's easy to do with org-mode source blocks (it also generates TeX), but this adds another layer of indirection on top of LaTeX, and sometimes makes it difficult to affect the TeX code being generated.
    – wvxvw
    Commented Feb 7, 2016 at 9:59
  • 2
    The polymode emacs package can do this. You probably have to write a new backend, but that is supposed to be easy.
    – Ista
    Commented Feb 7, 2016 at 18:33
  • @Ista: How would the relevant parts for polymode look like (just like in JeanPierre's answer for mmm-mode)?
    – student
    Commented Feb 8, 2016 at 21:27
  • @student: I don't use pythontex, and I don't have any interest in setting it up just to answer this question, so the best I can do is point you to the polymode documentation at github.com/vspinu/polymode/tree/master/…
    – Ista
    Commented Feb 9, 2016 at 18:10
  • There has been a short discussion in the comments of another question with the result that this question should get a more general heading. That makes the excellent accepted answer of this question more accessible.
    – Tobias
    Commented Apr 2, 2019 at 15:01

1 Answer 1

9

MMM-mode (multiple major modes) seems exactly what you're looking for. It is mentionned on the emacs wiki. You need to define a submode class to mix LaTeX and python, specifying that python parts are delimited by the pycode LaTeX tags. Adding the following to your init file should do it:

(require 'mmm-auto)
(mmm-add-classes
 '((latex-python
    :submode python-mode
    :face mmm-default-submode-face
    :front "\\\\begin{pycode}\n"
    :back "\\\\end{pycode}\n")))

(setq mmm-global-mode 'maybe)
(mmm-add-mode-ext-class 'latex-mode nil 'latex-python)

The :front and :back keywords specify regular expressions for delimiters. The last two lines ask that mmm-mode with the latex-python class be activated by default in all buffers whose major mode is latex-mode.

See the documentation for other options (activating it manually, based on file name, or with file variables).

There are two ways to specify several delimiter pairs. First, several classes can be joined in a group. Below, instead of defining the latex-python class we define it as a group that contains the two classes latex-python-envs and latex-python-cmds (itself recognizing the \pyc{…} and \py{…} LaTeX commands).

Second, each class can specify several several delimiter pairs: class latex-python-envs below will recognize both pycode and pyverbatim LaTeX envs (~1 in :back refers to the value matched in the first parenthesized group in :front).

(mmm-add-group 'latex-python
 '((latex-python-envs
    :submode python-mode
    :face mmm-default-submode-face
    :front "\\\\begin{\\(pycode\\|pyverbatim\\)}\n"
    :back "\\\\end{~1}\n"
    :save-matches 1)

   (latex-python-cmds
    :submode python-mode
    :face mmm-default-submode-face
    :front "\\\\pyc?{"
    :back "}")))

For delimiters to be recognized you need to mmm-parse-buffer (C-c % C-b) (or mmm-parse-region, or mmm-parse-block ie a few lines around point). If you're used to insert LaTeX envs through LaTeX-insert-environment (C-c C-e) it could be convenient to advise it to run mmm-parse-block when it's done, so that MMM immediately recognizes the just inserted tags:

(advice-add 'LaTeX-insert-environment ':after 
    '(lambda (env) (mmm-parse-block 2)))
8
  • Thanks. How can I add further environments and commands which may contain python code (for example \pyc or pyverbatim). Is there a way to make mmm-mode detect automatically if I insert a pycode environment?
    – student
    Commented Feb 8, 2016 at 21:49
  • I just realized that TAB doesn't work as expected. For example: \begin{pycode} + ENTER + then insert a for loop, e.g. for i in range(0,10): + ENTER + print(i) + ENTER + \end{pycode}. The ENTER after the for line indents this statement but not print(i) does this work for you?
    – student
    Commented Feb 8, 2016 at 22:00
  • @student MMM needs to be asked to reparse and see both delimiters for the submode to be in effect, see updated answer. Let me know if you're still in trouble.
    – JeanPierre
    Commented Feb 8, 2016 at 23:18
  • Thanks for the addition. Regarding the indentation I tested again using your hints and the described problem is fixed. However there are furher indenting issues: First if you insert a pycode environment, latex-mode intents it automatically and you have to use TAB explicitely to correct this, another problem occurs, if you use pycode inside another environment. I have made a screencast to make clear what I mean: expirebox.com/download/e348355feabb8bb5d8c8399b97bccdb8.html
    – student
    Commented Feb 9, 2016 at 9:33
  • Does the method you suggested above to include multiple environments also work if you want to match also the commands \pyc and \py?
    – student
    Commented Feb 9, 2016 at 9:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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