I have a buffer that shows documentation for Ansible modules. This buffer has its own major mode which provides all the standard stuff. Notably, it fontifies the buffer to highlight inline markup, options, sections, etc. All in all, it is pretty similar to M-x man.

At the bottom of the documentation there are usually some code examples in YAML. I'd like to fontify these as well. I could add my own font lock keywords for YAML, of course, but I'd rather prefer to re-use the fontification of YAML Mode.

How can I do that? Specifically, how can I use a different major mode to fontify a particular region of a buffer?

Note that YAML Mode doesn't need to be active in this region. The whole buffer is only a passive display buffer, and not intended to be edited. I really only need the fontification produced as if YAML Mode were active in that region.

I presume I could copy the region of the buffer to a temporary buffer, enable YAML Mode, fontify the buffer, and the copy all text properties over. Would that work? If so, how do I copy text properties, and what are the relevant properties to copy? Or is there a better approach?

  • How is the non-yaml fontification implemented? Do you apply text properties manually, or do you use font-lock-mode? – Malabarba Dec 15 '14 at 14:00
  • The links in this post sum-up at least a good chunk of the options out there: wisdomandwonder.com/link/8610/… – grettke Dec 16 '14 at 4:24
up vote 9 down vote accepted

I recently came across similar problem, I basically wanted to fontify code snippets in the documentation which I got some other source. I followed the approach mentioned towards the end of your answer and it worked fine for me. The function I ended up with some thing like the following

(defun my-fontify-yaml (text)
  (with-temp-buffer
    (erase-buffer)
    (insert text)
    (delay-mode-hooks (yaml-mode))
    (font-lock-default-function 'yaml-mode)
    (font-lock-default-fontify-region (point-min)
                                      (point-max)
                                      nil)
    (buffer-string)))

As @Malabarba pointed out in comments the simple approach above does not work if destination buffer uses font-lock-mode. However we can trick font-lock-mode into believing that the string is already font locked by setting the text property font-lock-face to the face, (we get the face property set, when we use the function above) and setting text-property fontified to t. The following function takes a string returned by the function above and does the required processing so that the string is inserted fontified (this is taken from org-mode's org-src-font-lock-fontify-block function

(defun my-fontify-using-faces (text)
  (let ((pos 0))
    (while (setq next (next-single-property-change pos 'face text))
      (put-text-property pos next 'font-lock-face (get-text-property pos 'face text) text)
      (setq pos next))
    (add-text-properties 0  (length text) '(fontified t) text)
    text))

Now you can use it as follows

(insert (my-fontify-using-faces (my-fontify-yaml "application: test\nversion: 1")))
  • This is the same solution I found for sx.el, but it's important to note it will only work if the destination buffer doesn't use font-lock-mode. – Malabarba Dec 15 '14 at 14:02
  • Right! I just realized this worked for me because I used in buffer where font-lock was not used (Help buffer) – Iqbal Ansari Dec 15 '14 at 15:17
  • @Malabarba found a way to make this work with destination buffers with font-lock-mode enabled – Iqbal Ansari Dec 15 '14 at 16:14
  • Many thanks, works perfectly! – lunaryorn Dec 16 '14 at 8:54
  • Oh nice! Glad I could help :) – Iqbal Ansari Dec 16 '14 at 12:29

Library Narrow Indirect (narrow-indirect) can help here -- have a look at the header commentary. It relies on:

  1. narrowing, which limit editing to a portion on a buffer, and
  2. indirect buffers, which copy a buffer in another one for which you can change the major mode.

Note that narrowing is disabled by default because it is considered beginner-unfriendly (the default binding is C-x n n). You can enable it by putting the following in your init file:

(put 'narrow-to-region 'disabled nil)

You can also look at for my handmade myfn-narrow-indirect in my conf.

  • Does narrowing actually affect font lock, i.e. keep it away from outside of the narrowed region? Does font lock really never remove buffer restrictions? – lunaryorn Dec 15 '14 at 22:56
  • And anyway, a wiki package is not an option. – lunaryorn Dec 15 '14 at 22:56
  • Besides, you don't need to remove the disabled property from a command to call it from Emacs Lisp. It only affects interactive use. – lunaryorn Dec 15 '14 at 22:58

I would suggest looking at org-src-font-lock-fontify-block which provides this functionality for org-mode source blocks. It seems to just copy the relevant parts to another buffer, enable the major mode there, and then copy the fontified text back. Hackish, but it seems to work.

  • 2
    This answer looks more like a comment insofar as it provides a suggested direction to deal with the problem, but not a complete answer. Please consider changing it to a comment. – Dan Dec 15 '14 at 16:14

Your Answer

 
discard

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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