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.

Tobias
  • 32,569
  • 1
  • 34
  • 75
student
  • 1,007
  • 9
  • 29
  • 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 Feb 07 '16 at 09: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 Feb 07 '16 at 18:33
  • @Ista: How would the relevant parts for polymode look like (just like in JeanPierre's answer for mmm-mode)? – student Feb 08 '16 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 https://github.com/vspinu/polymode/tree/master/modes#defining-new-polymodes – Ista Feb 09 '16 at 18:10
  • There has been a short discussion in the comments of [another question](https://emacs.stackexchange.com/q/48708/2370) with the result that this question should get a more general heading. That makes the excellent accepted answer of this question more accessible. – Tobias Apr 02 '19 at 15:01
  • You can also use [edit-indirect](https://github.com/Fanael/edit-indirect) to edit parts of the buffer in different major-modes. It's not in the same buffer, but that is actually a good thing IMO. – clemera Apr 02 '19 at 15:43

1 Answers1

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)))
JeanPierre
  • 7,323
  • 1
  • 18
  • 37
  • 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 Feb 08 '16 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 Feb 08 '16 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 Feb 08 '16 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: http://expirebox.com/download/e348355feabb8bb5d8c8399b97bccdb8.html – student Feb 09 '16 at 09: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 Feb 09 '16 at 09:34
  • @student For `\pyc`: yes, see updated answer. For indentation: this is a auctex issue. This [question](http://emacs.stackexchange.com/questions/16740/indenting-specific-environment-deeper-in-auctex) may help. – JeanPierre Feb 09 '16 at 20:11
  • Thanks. For the auctex issue I have posted a new question: http://emacs.stackexchange.com/q/20183/2323. The `\pyc` part doesn't work. – student Feb 09 '16 at 21:03
  • @student It does work for me, though obviously I need to `mmm-parse-block` after finishing entering the `\pyc{…}` part (we could make this happen automagically, too). Can you elaborate on "doesn't work"? – JeanPierre Feb 10 '16 at 06:28