;;; indirect-font-lock.el --- Highlight parts of comments and strings as code -*- lexical-binding: t; -*- ;; Copyright (C) 2016 Clément Pit-Claudel ;; Author: Clément Pit-Claudel ;; Keywords: faces ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see . ;;; Commentary: ;; ;;; Code: (defvar-local indirect-font-lock--temp-buffers nil "Alist of (MODE-FN . BUFFER). These are temporary buffers, used for highlighting.") (defun indirect-font-lock--kill-temp-buffers () "Kill buffers in `indirect-font-lock--temp-buffers'." (mapc #'kill-buffer (mapcar #'cdr indirect-font-lock--temp-buffers)) (setq indirect-font-lock--temp-buffers nil)) (defun indirect-font-lock--make-buffer-for-mode (mode-fn) "Create a temporary buffer for MODE-FN. The buffer is created and initialized with MODE-FN only once; further calls with the same MODE-FN reuse the same buffer." (let ((buffer (cdr (assoc mode-fn indirect-font-lock--temp-buffers)))) (unless buffer (setq buffer (generate-new-buffer (format " *%S-highlight*" mode-fn))) (push (cons mode-fn buffer) indirect-font-lock--temp-buffers) (with-current-buffer buffer (funcall mode-fn) (setq-local kill-buffer-query-functions nil))) (with-current-buffer buffer (setq buffer-read-only nil) (erase-buffer)) buffer)) (defun indirect-font-lock--copy-faces-to (buffer offset) "Copy faces from current buffer to BUFFER, starting at OFFSET." (let ((start (point-min)) (making-progress t) (offset (- offset (point-min)))) (while making-progress (let ((end (next-single-property-change start 'face nil (point-max)))) (if (< start end) (font-lock-prepend-text-property (+ start offset) (+ end offset) 'face (get-text-property start 'face) buffer) (setq making-progress nil)) (setq start end))))) (defun indirect-font-lock--fontify-as (mode-fn from to) "Use buffer in MODE-FN to fontify FROM..TO. In other word, fontify FROM..TO would as if it had been alone in its own buffer, in major mode MODE-FN." (let ((str (buffer-substring-no-properties from to)) (original-buffer (current-buffer))) (with-current-buffer (indirect-font-lock--make-buffer-for-mode mode-fn) (insert str) (font-lock-fontify-region (point-min) (point-max)) (indirect-font-lock--copy-faces-to original-buffer from)))) (defun indirect-font-lock-highlighter (group mode-fn) "Font-lock highlighter using an indirect buffer. Fontify GROUP as if it had been alone in its own buffer, in major mode MODE-FN." (save-match-data (indirect-font-lock--fontify-as mode-fn (match-beginning group) (match-end group))) '(face nil)) (provide 'indirect-font-lock) ;;; indirect-font-lock.el ends here