summaryrefslogtreecommitdiffstats
path: root/emacs.d/lisp/multi-mode/html-php.el
blob: 22cc210fc66c3eef787049c021320d84ebba5be0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
;;; html-php.el --- multi-mode PHP embedded in HTML

;; Copyright (C) 2008  Dave Love

;; Author: Dave Love <fx@gnu.org>
;; Keywords: languages
;; $Revision: 2$
;; URL: http://www.loveshack.ukfsn.org/emacs

;; This file 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 2, or (at your option)
;; any later version.

;; This file 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 GNU Emacs; see the file COPYING.  If not, write to
;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.

;;; Commentary:

;; Multiple-mode editing of PHP embedded in HTML.  Subject to the
;; limitations of multi-mode.el.  Note that there's no attempt to deal
;; with commented processing instructions markup.  Note also that this
;; only works properly with the basic HTML mode -- not PSGML or NXML.
;; Tested with the PHP mode from the hacked CC mode at the above URL.

;;; Code:

(require 'multi-mode)

(defun html-php-mode ()
  "Mode for editing PHP embedded in HTML, using multi-mode."
  (interactive)
  (set (make-local-variable 'multi-alist)
       '((html-mode)
	 (php-mode . html-php-chunk-region)))
  (multi-mode-install-modes))

(defun html-php-chunk-region (pos)
  "Mode-selecting function for PHP embedded in HTML.
See `multi-alist'."
  (let ((case-fold-search t)
	pi-start pi-end next-pi)
    (save-excursion
      (save-restriction
	(widen)
	(goto-char pos)
	(save-excursion
	  (let* ((p1 (save-excursion
		       ;; Check whether we're on the processing
		       ;; instruction start.  Skip definitely clear of
		       ;; it and then search backwards.
		       (goto-char (min (point-max) (+ (point) 5)))
		       (search-backward "<?php" (- (point) 9) t)))
		 (match-end (if p1 (match-end 0)))
		 ;; Otherwise search backwards simply.
		 (p2 (unless p1 (search-backward "<?php" nil t))))
	    (if p2 (setq match-end (match-end 0)))
	    (setq pi-start (or p1 p2))
	    ;; Ready to search for matching terminator or next
	    ;; processing instruction.
	    (goto-char (or match-end pos)))
	  (if pi-start
	      ;; Look forward for the PI terminator.
	      (let* ((p1 (save-excursion
			   ;; Check whether we're on the terminator.
			   (backward-char 1)
			   (search-backward "?>" (- (point) 2) t)))
		     (p2 (unless p1 (search-forward "?>" nil t))))
		(setq pi-end (or p1 p2 (point-max))))
	    (goto-char pos))
	  (if (and pi-start pi-end (< pos pi-end))
	      ;; We were between PI start and terminator.
	      (list 'php-mode pi-start pi-end)
	    ;; Otherwise, look forward for a PI to delimit the HTML
	    ;; region.
	    (setq next-pi (if (search-forward "<?php" nil t)
			      (match-beginning 0)
			    (point-max)))
	    (if pi-start
		(list 'html-mode (or pi-end (point-min)) next-pi)
	      (list 'html-mode (point-min) next-pi))))))))

(provide 'html-php)
;;; html-php.el ends here