I think polymode can provide some help for this. By itself, polymode
is
framework for combining multiple major modes in a systematic way. Among the the
examples, there is a polymode
available that creates a new major mode based on
markdown-mode
that can display any other major-mode recognized by Emacs. The
example can be seen here and is installed with polymode
by default from
Melpa.
There are some caveats though, polymode
needs to figure out which major-mode somehow and thus the name must match the major mode used by Emacs. E.g., instead of writing shell
,
you have to write sh-script
. See the samples folder on polymode for an some examples of this.
It is probably possible to fix that however by using some kind of look-up
function, but that would require non-trivial changes. Furthermore, I believe it
would be possible to create a ReST
polymode
in a similar fashion, but that
would probably require a significant amount of hacking.
The configuration I ended up using for getting all of this to work is this:
(use-package polymode
:ensure t
:defer t)
(use-package poly-markdown
:ensure polymode
:defer t
:mode ("\\.md" . poly-markdown-mode))
A word of warning though: It is important to know that mixing major-modes can
cause a wide variety of issues. Usually, this means that font-locking or
indenting can start to behave strangely, or the performance might degrade
significantly. Personally though, I haven't run into any issues yet but then
again, I haven't worked with any really large markdown files either.
EDIT
After getting slightly bored at work, I actually implemented the ReST equivalent to the poly-markdown-mode
:
;;; poly-rest-mode.el -- Polymode for ReST. -*- lexical-binding: t -*-
;;
;;; Commentary:
;; A mode for interacting with multiple kinds of code inside a ReST host-mode.
;;
;;; Code:
(require 'polymode)
(defcustom pm-host/ReST
(pm-bchunkmode "ReST"
:mode 'rst-mode
:init-functions '(poly-rest-fixes))
"Restructued Text host chunkmode."
:group 'hostmodes
:type 'object)
(defvar pm-ReST-code-regexp
(regexp-opt '("code" "code-block" "sourcecode" "highlight"))
"Regular expression to match all possible ReST code blocks.")
(defvar pm-ReST-head-regexp
(concat "^[^ ]*\\( *\.\. +" pm-ReST-code-regexp "::.*\n"
"\\(?: +:.+\n\\)*\\)") ;; Match 0 or more option lines.
"Regular expression to match the `head' of a ReST code block.")
(defvar pm-ReST-retriever-regexp
(concat "^[^ ]*\\(?: *\.\. +" pm-ReST-code-regexp ":: \\(.+\\)\\)$")
"Regular expression to retrieve the mode of the code block.")
(pm-create-indented-block-matchers "ReST" pm-ReST-head-regexp)
(defcustom pm-inner/ReST-code
(pm-hbtchunkmode-auto "ReST"
:head-reg #'pm-ReST-head-matcher
:tail-reg #'pm-ReST-tail-matcher
:head-mode 'host
:tail-mode 'host
:retriever-regexp pm-ReST-retriever-regexp
:font-lock-narrow t)
"Restructured Text inner code block mode."
:group 'innermodes
:type 'object)
(defcustom pm-poly/ReST
(pm-polymode-multi-auto "ReST"
:hostmode 'pm-host/ReST
:auto-innermode 'pm-inner/ReST-code)
"Restructured Text typical `polymode' configuration."
:group 'polymodes
:type 'object)
;;;###autoload (autoload #'poly-rest-mode "poly-rest-mode")
(define-polymode poly-rest-mode pm-poly/ReST)
(defun poly-rest-fixes ()
"Fix various minor issues that can occur in the poly-ReST-mode."
(remove-hook 'prog-mode-hook #'whitespace-mode)
(remove-hook 'python-mode-hook #'mmm-mode))
(provide 'poly-rest-mode)
;;; poly-rest-mode.el ends here
Now, it is likely that I've missed some detail where this doesn't work perfectly, I'm simply not familiar enough with ReST to tell.
It does seem to work fairly well on a rather complete example:

Edit
The concerns mentioned in the comments regarding nested indentations have been fixed in the above code snippet.