;;; php-mode.el --- major mode for editing PHP code ;; Copyright (C) 1999, 2000, 2001, 2003, 2004 Turadg Aleahmad ;; 2008 Aaron S. Hawley ;; Maintainer: Aaron S. Hawley ;; Author: Turadg Aleahmad, 1999-2004 ;; Keywords: php languages oop ;; Created: 1999-05-17 ;; Modified: 2008-11-04 ;; X-URL: http://php-mode.sourceforge.net/ (defconst php-mode-version-number "1.5.0" "PHP Mode version number.") ;;; License ;; 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 3 ;; of the License, 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 this file; if not, write to the Free Software ;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ;; 02110-1301, USA. ;;; Usage ;; Put this file in your Emacs lisp path (eg. site-lisp) and add to ;; your .emacs file: ;; ;; (require 'php-mode) ;; To use abbrev-mode, add lines like this: ;; (add-hook 'php-mode-hook ;; '(lambda () (define-abbrev php-mode-abbrev-table "ex" "extends"))) ;; To make php-mode compatible with html-mode, see http://php-mode.sf.net ;; Many options available under Help:Customize ;; Options specific to php-mode are in ;; Programming/Languages/Php ;; Since it inherits much functionality from c-mode, look there too ;; Programming/Languages/C ;;; Commentary: ;; PHP mode is a major mode for editing PHP 3 and 4 source code. It's ;; an extension of C mode; thus it inherits all C mode's navigation ;; functionality. But it colors according to the PHP grammar and indents ;; according to the PEAR coding guidelines. It also includes a couple ;; handy IDE-type features such as documentation search and a source ;; and class browser. ;;; Contributors: (in chronological order) ;; Juanjo, Torsten Martinsen, Vinai Kopp, Sean Champ, Doug Marcey, ;; Kevin Blake, Rex McMaster, Mathias Meyer, Boris Folgmann, Roland ;; Rosenfeld, Fred Yankowski, Craig Andrews, John Keller, Ryan ;; Sammartino, ppercot, Valentin Funk, Stig Bakken, Gregory Stark, ;; Chris Morris, Nils Rennebarth, Gerrit Riessen, Eric Mc Sween, ;; Ville Skytta, Giacomo Tesio, Lennart Borgman, Stefan Monnier, ;; Aaron S. Hawley, Ian Eure, Bill Lovett, Dias Badekas, David House ;;; Changelog: ;; 1.5 ;; Support function keywords like public, private and the ampersand ;; character for function-based commands. Support abstract, final, ;; static, public, private and protected keywords in Imenu. Fix ;; reversed order of Imenu entries. Use font-lock-preprocessor-face ;; for PHP and ASP tags. Make php-mode-modified a literal value ;; rather than a computed string. Add date and time constants of ;; PHP. (Dias Badekas) Fix false syntax highlighting of keywords ;; because of underscore character. Change HTML indentation warning ;; to match only HTML at the beginning of the line. Fix ;; byte-compiler warnings. Clean-up whitespace and audited style ;; consistency of code. Remove conditional bindings and XEmacs code ;; that likely does nothing. ;; ;; 1.4 ;; Updated GNU GPL to version 3. Ported to Emacs 22 (CC mode ;; 5.31). M-x php-mode-version shows version. Provide end-of-defun ;; beginning-of-defun functionality. Support add-log library. ;; Fix __CLASS__ constant (Ian Eure). Allow imenu to see visibility ;; declarations -- "private", "public", "protected". (Bill Lovett) ;; ;; 1.3 ;; Changed the definition of # using a tip from Stefan ;; Monnier to correct highlighting and indentation. (Lennart Borgman) ;; Changed the highlighting of the HTML part. (Lennart Borgman) ;; ;; See the ChangeLog file included with the source package. ;;; Code: (require 'speedbar) (require 'font-lock) (require 'cc-mode) (require 'cc-langs) (require 'custom) (require 'etags) (eval-when-compile (require 'regexp-opt)) ;; Local variables (defgroup php nil "Major mode `php-mode' for editing PHP code." :prefix "php-" :group 'languages) (defcustom php-default-face 'default "Default face in `php-mode' buffers." :type 'face :group 'php) (defcustom php-speedbar-config t "When set to true automatically configures Speedbar to observe PHP files. Ignores php-file patterns option; fixed to expression \"\\.\\(inc\\|php[s34]?\\)\"" :type 'boolean :set (lambda (sym val) (set-default sym val) (if (and val (boundp 'speedbar)) (speedbar-add-supported-extension "\\.\\(inc\\|php[s34]?\\|phtml\\)"))) :group 'php) (defcustom php-mode-speedbar-open nil "Normally `php-mode' starts with the speedbar closed. Turning this on will open it whenever `php-mode' is loaded." :type 'boolean :set (lambda (sym val) (set-default sym val) (when val (speedbar 1))) :group 'php) (defvar php-imenu-generic-expression '( ("Private Methods" "^\\s-*\\(?:\\(?:abstract\\|final\\)\\s-+\\)?private\\s-+\\(?:static\\s-+\\)?function\\s-+\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*(" 1) ("Protected Methods" "^\\s-*\\(?:\\(?:abstract\\|final\\)\\s-+\\)?protected\\s-+\\(?:static\\s-+\\)?function\\s-+\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*(" 1) ("Public Methods" "^\\s-*\\(?:\\(?:abstract\\|final\\)\\s-+\\)?public\\s-+\\(?:static\\s-+\\)?function\\s-+\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*(" 1) ("Classes" "^\\s-*class\\s-+\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*" 1) ("All Functions" "^\\s-*\\(?:\\(?:abstract\\|final\\|private\\|protected\\|public\\|static\\)\\s-+\\)*function\\s-+\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*(" 1) ) "Imenu generic expression for PHP Mode. See `imenu-generic-expression'." ) (defcustom php-manual-url "http://www.php.net/manual/en/" "URL at which to find PHP manual. You can replace \"en\" with your ISO language code." :type 'string :group 'php) (defcustom php-search-url "http://www.php.net/" "URL at which to search for documentation on a word." :type 'string :group 'php) (defcustom php-completion-file "" "Path to the file which contains the function names known to PHP." :type 'string :group 'php) (defcustom php-manual-path "" "Path to the directory which contains the PHP manual." :type 'string :group 'php) ;;;###autoload (defcustom php-file-patterns '("\\.php[s34]?\\'" "\\.phtml\\'" "\\.inc\\'") "List of file patterns for which to automatically invoke `php-mode'." :type '(repeat (regexp :tag "Pattern")) :set (lambda (sym val) (set-default sym val) (let ((php-file-patterns-temp val)) (while php-file-patterns-temp (add-to-list 'auto-mode-alist (cons (car php-file-patterns-temp) 'php-mode)) (setq php-file-patterns-temp (cdr php-file-patterns-temp))))) :group 'php) (defcustom php-mode-hook nil "List of functions to be executed on entry to `php-mode'." :type 'hook :group 'php) (defcustom php-mode-pear-hook nil "Hook called when a PHP PEAR file is opened with `php-mode'." :type 'hook :group 'php) (defcustom php-mode-force-pear nil "Normally PEAR coding rules are enforced only when the filename contains \"PEAR.\" Turning this on will force PEAR rules on all PHP files." :type 'boolean :group 'php) (defconst php-mode-modified "2008-11-04" "PHP Mode build date.") (defun php-mode-version () "Display string describing the version of PHP mode." (interactive) (message "PHP mode %s of %s" php-mode-version-number php-mode-modified)) (defconst php-beginning-of-defun-regexp "^\\s-*\\(?:\\(?:abstract\\|final\\|private\\|protected\\|public\\|static\\)\\s-+\\)*function\\s-+&?\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*(" "Regular expression for a PHP function.") (defun php-beginning-of-defun (&optional arg) "Move to the beginning of the ARGth PHP function from point. Implements PHP version of `beginning-of-defun-function'." (interactive "p") (let ((arg (or arg 1))) (while (> arg 0) (re-search-backward php-beginning-of-defun-regexp nil 'noerror) (setq arg (1- arg))) (while (< arg 0) (end-of-line 1) (let ((opoint (point))) (beginning-of-defun 1) (forward-list 2) (forward-line 1) (if (eq opoint (point)) (re-search-forward php-beginning-of-defun-regexp nil 'noerror)) (setq arg (1+ arg)))))) (defun php-end-of-defun (&optional arg) "Move the end of the ARGth PHP function from point. Implements PHP befsion of `end-of-defun-function' See `php-beginning-of-defun'." (interactive "p") (php-beginning-of-defun (- (or arg 1)))) (defvar php-warned-bad-indent nil) (make-variable-buffer-local 'php-warned-bad-indent) ;; Do it but tell it is not good if html tags in buffer. (defun php-check-html-for-indentation () (let ((html-tag-re "^\\s-*") (here (point))) (if (not (or (re-search-forward html-tag-re (line-end-position) t) (re-search-backward html-tag-re (line-beginning-position) t))) t (goto-char here) (setq php-warned-bad-indent t) (lwarn 'php-indent :warning "\n\t%s\n\t%s\n\t%s\n" "Indentation fails badly with mixed HTML and PHP." "Look for an Emacs Lisp library that supports \"multiple" "major modes\" like mumamo, mmm-mode or multi-mode.") nil))) (defun php-cautious-indent-region (start end &optional quiet) (if (or php-warned-bad-indent (php-check-html-for-indentation)) (funcall 'c-indent-region start end quiet))) (defun php-cautious-indent-line () (if (or php-warned-bad-indent (php-check-html-for-indentation)) (funcall 'c-indent-line))) (defconst php-tags '("" "[^_]?") '(1 font-lock-constant-face)) ;; Fontify keywords (cons (concat "[^_$]?\\<\\(" php-keywords "\\)\\>[^_]?") '(1 font-lock-keyword-face)) ;; Fontify keywords and targets, and case default tags. (list "\\<\\(break\\|case\\|continue\\)\\>\\s-+\\(-?\\sw+\\)?" '(1 font-lock-keyword-face) '(2 font-lock-constant-face t t)) ;; This must come after the one for keywords and targets. '(":" ("^\\s-+\\(\\sw+\\)\\s-+\\s-+$" (beginning-of-line) (end-of-line) (1 font-lock-constant-face))) ;; treat 'print' as keyword only when not used like a function name '("\\" . font-lock-keyword-face) ;; Fontify PHP tag (cons php-tags-key font-lock-preprocessor-face) ;; Fontify ASP-style tag '("<\\%\\(=\\)?" . font-lock-preprocessor-face) '("\\%>" . font-lock-preprocessor-face) ) "Subdued level highlighting for PHP mode.") (defconst php-font-lock-keywords-2 (append php-font-lock-keywords-1 (list ;; class declaration '("\\<\\(class\\|interface\\)\\s-+\\(\\sw+\\)?" (1 font-lock-keyword-face) (2 font-lock-type-face nil t)) ;; handle several words specially, to include following word, ;; thereby excluding it from unknown-symbol checks later ;; FIX to handle implementing multiple ;; currently breaks on "class Foo implements Bar, Baz" '("\\<\\(new\\|extends\\|implements\\)\\s-+\\$?\\(\\sw+\\)" (1 font-lock-keyword-face) (2 font-lock-type-face)) ;; function declaration '("\\<\\(function\\)\\s-+&?\\(\\sw+\\)\\s-*(" (1 font-lock-keyword-face) (2 font-lock-function-name-face nil t)) ;; class hierarchy '("\\<\\(self\\|parent\\)\\>" (1 font-lock-constant-face nil nil)) ;; method and variable features '("\\<\\(private\\|protected\\|public\\)\\s-+\\$?\\sw+" (1 font-lock-keyword-face)) ;; method features '("^\\s-*\\(abstract\\|static\\|final\\)\\s-+\\$?\\sw+" (1 font-lock-keyword-face)) ;; variable features '("^\\s-*\\(static\\|const\\)\\s-+\\$?\\sw+" (1 font-lock-keyword-face)) )) "Medium level highlighting for PHP mode.") (defconst php-font-lock-keywords-3 (append php-font-lock-keywords-2 (list ;; or for HTML ;;'(" ]*>" . font-lock-constant-face) ;;'("]*" . font-lock-constant-face) ;;'(" '("<[^>]*\\(>\\)" (1 font-lock-constant-face)) ;; HTML tags '("\\(<[a-z]+\\)[[:space:]]+\\([a-z:]+=\\)[^>]*?" (1 font-lock-constant-face) (2 font-lock-constant-face) ) '("\"[[:space:]]+\\([a-z:]+=\\)" (1 font-lock-constant-face)) ;; HTML entities ;;'("&\\w+;" . font-lock-variable-name-face) ;; warn about '$' immediately after -> '("\\$\\sw+->\\s-*\\(\\$\\)\\(\\sw+\\)" (1 font-lock-warning-face) (2 php-default-face)) ;; warn about $word.word -- it could be a valid concatenation, ;; but without any spaces we'll assume $word->word was meant. '("\\$\\sw+\\(\\.\\)\\sw" 1 font-lock-warning-face) ;; Warn about ==> instead of => '("==+>" . font-lock-warning-face) ;; exclude casts from bare-word treatment (may contain spaces) `(,(concat "(\\s-*\\(" php-types "\\)\\s-*)") 1 font-lock-type-face) ;; PHP5: function declarations may contain classes as parameters type `(,(concat "[(,]\\s-*\\(\\sw+\\)\\s-+&?\\$\\sw+\\>") 1 font-lock-type-face) ;; Fontify variables and function calls '("\\$\\(this\\|that\\)\\W" (1 font-lock-constant-face nil nil)) `(,(concat "\\$\\(" php-superglobals "\\)\\W") (1 font-lock-constant-face nil nil)) ;; $_GET & co '("\\$\\(\\sw+\\)" (1 font-lock-variable-name-face)) ;; $variable '("->\\(\\sw+\\)" (1 font-lock-variable-name-face t t)) ;; ->variable '("->\\(\\sw+\\)\\s-*(" . (1 php-default-face t t)) ;; ->function_call '("\\(\\sw+\\)::\\sw+\\s-*(?" . (1 font-lock-type-face)) ;; class::member '("::\\(\\sw+\\>[^(]\\)" . (1 php-default-face)) ;; class::constant '("\\<\\sw+\\s-*[[(]" . php-default-face) ;; word( or word[ '("\\<[0-9]+" . php-default-face) ;; number (also matches word) ;; Warn on any words not already fontified '("\\<\\sw+\\>" . font-lock-warning-face) )) "Gauchy level highlighting for PHP mode.") (provide 'php-mode) ;;; php-mode.el ends here