From 897eee81de8b3f6adf0165f50e95600a7b89c20c Mon Sep 17 00:00:00 2001 From: Simeon Simeonov Date: Wed, 4 Feb 2015 21:41:42 +0100 Subject: Standalone lisp and snippet repo --- .emacs.d/lisp/php-mode.el | 1536 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1536 insertions(+) create mode 100644 .emacs.d/lisp/php-mode.el (limited to '.emacs.d/lisp/php-mode.el') diff --git a/.emacs.d/lisp/php-mode.el b/.emacs.d/lisp/php-mode.el new file mode 100644 index 0000000..1841c4b --- /dev/null +++ b/.emacs.d/lisp/php-mode.el @@ -0,0 +1,1536 @@ +;;; php-mode.el --- Major mode for editing PHP code + +;; Copyright (C) 1999, 2000, 2001, 2003, 2004 Turadg Aleahmad +;; 2008 Aaron S. Hawley +;; 2011, 2012, 2013, 2014, 2015 Eric James Michael Ritz + +;;; Author: Eric James Michael Ritz +;;; URL: https://github.com/ejmr/php-mode +;;; Version: 1.15.3 + +(defconst php-mode-version-number "1.15.3" + "PHP Mode version number.") + +(defconst php-mode-modified "2015-01-31" + "PHP Mode build date.") + +;;; 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 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. + +;;; Code: + +(require 'cc-mode) +(eval-when-compile + (require 'cc-langs) + (require 'cc-fonts)) + +;; Boilerplate from other `cc-mode' derived modes. See +;; http://cc-mode.sourceforge.net/derived-mode-ex.el for details on how this all +;; fits together. +(eval-and-compile + (c-add-language 'php-mode 'java-mode)) + +(require 'font-lock) +(require 'add-log) +(require 'custom) +(require 'flymake) +(require 'etags) +(require 'speedbar) +(eval-when-compile + (unless (require 'cl-lib nil t) + (require 'cl)) + (require 'regexp-opt) + (defvar c-vsemi-status-unknown-p) + (defvar syntax-propertize-via-font-lock)) + +;; Work around emacs bug#18845, cc-mode expects cl to be loaded +;; while php-mode only uses cl-lib (without compatibility aliases) +(eval-when-compile + (if (and (= emacs-major-version 24) (= emacs-minor-version 4)) + (require 'cl))) + +;; Use the recommended cl functions in php-mode but alias them to the +;; old names when we detect emacs < 24.3 +(if (and (= emacs-major-version 24) (< emacs-minor-version 3)) + (progn + (unless (fboundp 'cl-flet) + (defalias 'cl-flet 'flet)) + (unless (fboundp 'cl-set-difference) + (defalias 'cl-set-difference 'set-difference)))) + + +;; Local variables +;;;###autoload +(defgroup php nil + "Major mode `php-mode' for editing PHP code." + :prefix "php-" + :group 'languages + :link '(url-link :tag "Official Site" "https://github.com/ejmr/php-mode") + :link '(url-link :tag "PHP Mode Wiki" "https://github.com/ejmr/php-mode/wiki")) + +(defcustom php-executable "/usr/bin/php" + "The location of the PHP executable." + :type 'string + :group 'php) + +(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[s345]?\\)\"" + :type 'boolean + :set (lambda (sym val) + (set-default sym val) + (when val + (speedbar-add-supported-extension + "\\.\\(inc\\|php[s345]?\\|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) + +(defcustom php-template-compatibility t + "Should detect presence of html tags." + :type 'boolean + :group 'php) + +(defun php-mode-extra-constants-create-regexp(kwds) + "Create regexp for the list of extra constant keywords KWDS." + (concat "[^_$]?\\<\\(" + (regexp-opt + (append kwds + (when (boundp 'web-mode-extra-php-constants) web-mode-extra-php-constants))) + "\\)\\>[^_]?")) + +(defun php-mode-extra-constants-set(sym value) + "Apply the list of extra constant keywords VALUE. + +This function is called when the custom variable php-extra-constants +is updated. The web-mode-extra-constants list is appended to the list +of constants when set." + ;; remove old keywords + (when (boundp 'php-extra-constants) + (font-lock-remove-keywords + 'php-mode `((,(php-mode-extra-constants-create-regexp php-extra-constants) 1 font-lock-constant-face)))) + ;; add new keywords + (when value + (font-lock-add-keywords + 'php-mode `((,(php-mode-extra-constants-create-regexp value) 1 font-lock-constant-face)))) + (set sym value)) + +(defcustom php-lineup-cascaded-calls nil + "Indent chained method calls to the previous line" + :type 'boolean + :group 'php) + +;;;###autoload +(defcustom php-extra-constants '() + "A list of additional strings to treat as PHP constants." + :type 'list + :set 'php-mode-extra-constants-set + :group 'php) + +(defun php-create-regexp-for-method (visibility) + "Make a regular expression for methods with the given VISIBILITY. + +VISIBILITY must be a string that names the visibility for a PHP +method, e.g. 'public'. The parameter VISIBILITY can itself also +be a regular expression. + +The regular expression this function returns will check for other +keywords that can appear in method signatures, e.g. 'final' and +'static'. The regular expression will have one capture group +which will be the name of the method." + (concat + ;; Initial space with possible 'abstract' or 'final' keywords + "^\\s-*\\(?:\\(?:abstract\\|final\\)\\s-+\\)?" + ;; 'static' keyword may come either before or after visibility + "\\(?:" visibility "\\(?:\\s-+static\\)?\\|\\(?:static\\s-+\\)?" visibility "\\)\\s-+" + ;; Make sure 'function' comes next with some space after + "function\\s-+" + ;; Capture the name as the first group and the regexp and make sure + ;; by the end we see the opening parenthesis for the parameters. + "\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*(")) + +(defun php-create-regexp-for-classlike (type) + "Accepts a `type' of a 'classlike' object as a string, such as +'class' or 'interface', and returns a regexp as a string which +can be used to match against definitions for that classlike." + (concat + ;; First see if 'abstract' or 'final' appear, although really these + ;; are not valid for all values of `type' that the function + ;; accepts. + "^\\s-*\\(?:\\(?:abstract\\|final\\)\\s-+\\)?" + ;; The classlike type + type + ;; Its name, which is the first captured group in the regexp. We + ;; allow backslashes in the name to handle namespaces, but again + ;; this is not necessarily correct for all values of `type'. + "\\s-+\\(\\(?:\\sw\\|\\\\\\|\\s_\\)+\\)")) + +(defvar php-imenu-generic-expression + `(("Namespaces" + ,(php-create-regexp-for-classlike "namespace") 1) + ("Classes" + ,(php-create-regexp-for-classlike "class") 1) + ("Interfaces" + ,(php-create-regexp-for-classlike "interface") 1) + ("Traits" + ,(php-create-regexp-for-classlike "trait") 1) + ("All Methods" + ,(php-create-regexp-for-method "\\(?:\\sw\\|\\s_\\)+") 1) + ("Private Methods" + ,(php-create-regexp-for-method "private") 1) + ("Protected Methods" + ,(php-create-regexp-for-method "protected") 1) + ("Public Methods" + ,(php-create-regexp-for-method "public") 1) + ("Anonymous Functions" + "\\<\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*=\\s-*function\\s-*(" 1) + ("Named Functions" + "^\\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 +(add-to-list 'interpreter-mode-alist (cons "php" 'php-mode)) + +(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-drupal-hook nil + "Hook called when a Drupal file is opened with `php-mode'." + :type 'hook + :group 'php) + +(defcustom php-mode-wordpress-hook nil + "Hook called when a WordPress file is opened with `php-mode'." + :type 'hook + :group 'php) + +(defcustom php-mode-symfony2-hook nil + "Hook called when a Symfony2 file is opened with `php-mode'." + :type 'hook + :group 'php) + +(defcustom php-mode-psr2-hook nil + "Hook called when a PSR-2 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) + +(defcustom php-mode-warn-if-mumamo-off t + "Warn once per buffer if you try to indent a buffer without +mumamo-mode turned on. Detects if there are any HTML tags in the +buffer before warning, but this is is not very smart; e.g. if you +have any tags inside a PHP string, it will be fooled." + :type '(choice (const :tag "Warg" t) (const "Don't warn" nil)) + :group 'php) + +(defcustom php-mode-coding-style 'pear + "Select default coding style to use with php-mode. +This variable can take one of the following symbol values: + +`Default' - use a reasonable default style for PHP. + +`PEAR' - use coding styles preferred for PEAR code and modules. + +`Drupal' - use coding styles preferred for working with Drupal projects. + +`WordPress' - use coding styles preferred for working with WordPress projects. + +`Symfony2' - use coding styles preferred for working with Symfony2 projects. + +`PSR-2' - use coding styles preferred for working with projects using PSR-2 standards." + :type '(choice (const :tag "Default" default) + (const :tag "PEAR" pear) + (const :tag "Drupal" drupal) + (const :tag "WordPress" wordpress) + (const :tag "Symfony2" symfony2) + (const :tag "PSR-2" psr2)) + :group 'php + :set 'php-mode-custom-coding-style-set + :initialize 'custom-initialize-default) + +(defun php-mode-custom-coding-style-set (sym value) + (when (eq major-mode 'php-mode) + (set sym value) + (set-default sym value) + (cond ((eq value 'pear) + (php-enable-pear-coding-style)) + ((eq value 'default) + (php-enable-default-coding-style)) + ((eq value 'drupal) + (php-enable-drupal-coding-style)) + ((eq value 'wordpress) + (php-enable-wordpress-coding-style)) + ((eq value 'symfony2) + (php-enable-symfony2-coding-style)) + ((eq value 'psr2) + (php-enable-psr2-coding-style))))) + +(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)) + +(defvar php-mode-map + (let ((map (make-sparse-keymap))) + ;; (define-key map [menu-bar php] + ;; (cons "PHP" (make-sparse-keymap "PHP"))) + + ;; (define-key map [menu-bar php complete-function] + ;; '("Complete function name" . php-complete-function)) + ;; (define-key map [menu-bar php browse-manual] + ;; '("Browse manual" . php-browse-manual)) + ;; (define-key map [menu-bar php search-documentation] + ;; '("Search documentation" . php-search-documentation)) + + ;; By default PHP mode binds C-M-h to c-mark-function, which it + ;; inherits from cc-mode. But there are situations where + ;; c-mark-function fails to properly mark a function. For + ;; example, if we use c-mark-function within a method definition + ;; then the region will expand beyond the method and into the + ;; class definition itself. + ;; + ;; Changing the default to mark-defun provides behavior that users + ;; are more likely to expect. + (define-key map (kbd "C-M-h") 'mark-defun) + + ;; Many packages based on cc-mode provide the 'C-c C-w' binding + ;; to toggle Subword Mode. See the page + ;; + ;; https://www.gnu.org/software/emacs/manual/html_node/ccmode/Subword-Movement.html + ;; + ;; for more information about Submode Word. + (if (boundp 'subword-mode) + (if subword-mode + (subword-mode nil) + (subword-mode t))) + + ;; We inherit c-beginning-of-defun and c-end-of-defun from CC Mode + ;; but we have two replacement functions specifically for PHP. We + ;; remap the commands themselves and not their default + ;; key-bindings so that our PHP-specific versions will work even + ;; if the user has reconfigured their keys, e.g. if they rebind + ;; c-end-of-defun to something other than C-M-e. + (define-key map [remap c-beginning-of-defun] 'php-beginning-of-defun) + (define-key map [remap c-end-of-defun] 'php-end-of-defun) + + (define-key map [(control c) (control f)] 'php-search-documentation) + (define-key map [(meta tab)] 'php-complete-function) + (define-key map [(control c) (control m)] 'php-browse-manual) + (define-key map [(control .)] 'php-show-arglist) + (define-key map [(control c) (control r)] 'php-send-region) + ;; Use the Emacs standard indentation binding. This may upset c-mode + ;; which does not follow this at the moment, but I see no better + ;; choice. + (define-key map [tab] 'indent-for-tab-command) + map) + "Keymap for `php-mode'") + +(c-lang-defconst c-mode-menu + php (append '(["Complete function name" php-complete-function t] + ["Browse manual" php-browse-manual t] + ["Search documentation" php-search-documentation t] + ["----" t]) + (c-lang-const c-mode-menu))) + +(c-lang-defconst c-at-vsemi-p-fn + php 'php-c-at-vsemi-p) + +(c-lang-defconst c-vsemi-status-unknown-p-fn + php 'php-c-vsemi-status-unknown-p) + +;; Make php-mode recognize opening tags as preprocessor macro's. +;; +;; This is a workaround, the tags must be recognized as something +;; in order for the syntactic guesses of code below the tag +;; to be correct and as a result not break indentation. +;; +;; Note that submatches or \\| here are not expected by cc-mode. +(c-lang-defconst c-opt-cpp-prefix + php "\\s-*<\\?") + +(c-lang-defconst c-identifier-ops + php '( + (left-assoc "\\" "::" "->") + (prefix "\\" "::"))) + +;; Allow '\' when scanning from open brace back to defining +;; construct like class +(c-lang-defconst c-block-prefix-disallowed-chars + php (cl-set-difference (c-lang-const c-block-prefix-disallowed-chars) + '(?\\))) + +;; Allow $ so variables are recognized in cc-mode and remove @. This +;; makes cc-mode highlight variables and their type hints in arglists. +(c-lang-defconst c-symbol-start + php (concat "[" c-alpha "_$]")) + +;; All string literals can possibly span multiple lines +(c-lang-defconst c-multiline-string-start-char + php t) + +(c-lang-defconst c-assignment-operators + ;; falls back to java, so no need to specify the language + php (append (remove ">>>=" (c-lang-const c-assignment-operators)) + '(".="))) + +(c-lang-defconst beginning-of-defun-function + php 'php-beginning-of-defun) + +(c-lang-defconst end-of-defun-function + php 'php-end-of-defun) + +(c-lang-defconst c-primitive-type-kwds + php '("int" "integer" "bool" "boolean" "float" "double" "real" + "string" "object")) + +(c-lang-defconst c-class-decl-kwds + "Keywords introducing declarations where the following block (if any) +contains another declaration level that should be considered a class." + php '("class" "trait" "interface")) + +(c-lang-defconst c-brace-list-decl-kwds + "Keywords introducing declarations where the following block (if +any) is a brace list. + +PHP does not have an \"enum\"-like keyword." + php nil) + +(c-lang-defconst c-typeless-decl-kwds + php (append (c-lang-const c-class-decl-kwds) '("function"))) + +(c-lang-defconst c-modifier-kwds + php '("abstract" "const" "final" "native" "static" "strictfp" + "synchronized" "transient" "volatile")) + +(c-lang-defconst c-protection-kwds + "Access protection label keywords in classes." + php '("private" "protected" "public")) + +(c-lang-defconst c-postfix-decl-spec-kwds + php '("implements" "extends")) + +(c-lang-defconst c-type-list-kwds + php '("new" "use" "implements" "extends" "namespace" "instanceof" "insteadof")) + +(c-lang-defconst c-ref-list-kwds + php nil) + +(c-lang-defconst c-block-stmt-2-kwds + php (append '("elseif" "foreach" "declare") + (remove "synchronized" (c-lang-const c-block-stmt-2-kwds)))) + +(c-lang-defconst c-simple-stmt-kwds + php (append '("include" "include_once" "require" "require_once" + "echo" "print" "die" "exit") + (c-lang-const c-simple-stmt-kwds))) + +(c-lang-defconst c-constant-kwds + php '("true" + "false" + "null")) + +(c-lang-defconst c-lambda-kwds + php '("function")) + +(c-lang-defconst c-other-kwds + "Keywords not accounted for by any other `*-kwds' language constant." + php '( + "__halt_compiler" + "and" + "array" + "callable" + "as" + "break" + "catch all" + "catch" + "clone" + "default" + "empty" + "enddeclare" + "endfor" + "endforeach" + "endif" + "endswitch" + "endwhile" + "eval" + "global" + "isset" + "list" + "or" + "parent" + "static" + "unset" + "var" + "xor" + "yield" + + ;; Below keywords are technically not reserved keywords, but + ;; threated no differently by php-mode from actual reserved + ;; keywords + ;; + ;;; declare directives: + "encoding" + "ticks" + + ;;; self for static references: + "self" + )) + +;; PHP does not have <> templates/generics +(c-lang-defconst c-recognize-<>-arglists + php nil) + +(c-lang-defconst c-enums-contain-decls + php nil) + +(c-lang-defconst c-nonlabel-token-key + "Regexp matching things that can't occur in generic colon labels. + +This overrides cc-mode `c-nonlabel-token-key' to support switching on +double quoted strings and true/false/null. + +Note: this regexp is also applied to goto-labels, a future improvement +might be to handle switch and goto labels differently." + php (concat + ;; All keywords except `c-label-kwds' and `c-constant-kwds'. + (c-make-keywords-re t + (cl-set-difference (c-lang-const c-keywords) + (append (c-lang-const c-label-kwds) + (c-lang-const c-constant-kwds)) + :test 'string-equal)))) + +(defun php-lineup-cascaded-calls (langelem) + "Line up chained methods using `c-lineup-cascaded-calls', +but only if the setting is enabled" + (if php-lineup-cascaded-calls + (c-lineup-cascaded-calls langelem))) + +(c-add-style + "php" + '((c-basic-offset . 4) + (c-doc-comment-style . javadoc) + (c-offsets-alist . ((arglist-close . php-lineup-arglist-close) + (arglist-cont . (first php-lineup-cascaded-calls 0)) + (arglist-cont-nonempty . (first php-lineup-cascaded-calls c-lineup-arglist)) + (arglist-intro . php-lineup-arglist-intro) + (case-label . +) + (class-open . -) + (comment-intro . 0) + (inlambda . 0) + (inline-open . 0) + (label . +) + (statement-cont . (first php-lineup-cascaded-calls php-lineup-string-cont +)) + (substatement-open . 0) + (topmost-intro-cont . (first php-lineup-cascaded-calls +)))))) + +(defun php-enable-default-coding-style () + "Set PHP Mode to use reasonable default formatting." + (interactive) + (c-set-style "php")) + +(c-add-style + "pear" + '("php" + (c-basic-offset . 4) + (c-offsets-alist . ((case-label . 0))))) + +(defun php-enable-pear-coding-style () + "Sets up php-mode to use the coding styles preferred for PEAR +code and modules." + (interactive) + (setq tab-width 4 + indent-tabs-mode nil) + (c-set-style "pear") + + ;; Undo drupal/PSR-2 coding style whitespace effects + (set (make-local-variable 'show-trailing-whitespace) + (default-value 'show-trailing-whitespace))) + +(c-add-style + "drupal" + '("php" + (c-basic-offset . 2))) + +(defun php-enable-drupal-coding-style () + "Makes php-mode use coding styles that are preferable for +working with Drupal." + (interactive) + (setq tab-width 2 + indent-tabs-mode nil + fill-column 78) + (set (make-local-variable 'show-trailing-whitespace) t) + (add-hook 'before-save-hook 'delete-trailing-whitespace nil t) + (c-set-style "drupal")) + +(c-add-style + "wordpress" + '("php" + (c-basic-offset . 4))) + +(defun php-enable-wordpress-coding-style () + "Makes php-mode use coding styles that are preferable for +working with Wordpress." + (interactive) + (setq indent-tabs-mode t + fill-column 78 + tab-width 4 + c-indent-comments-syntactically-p t) + (c-set-style "wordpress") + + ;; Undo drupal/PSR-2 coding style whitespace effects + (set (make-local-variable 'show-trailing-whitespace) + (default-value 'show-trailing-whitespace))) + +(c-add-style + "symfony2" + '("php" + (c-offsets-alist . ((statement-cont . php-lineup-hanging-semicolon))))) + +(defun php-enable-symfony2-coding-style () + "Makes php-mode use coding styles that are preferable for +working with Symfony2." + (interactive) + (setq indent-tabs-mode nil + fill-column 78 + c-indent-comments-syntactically-p t + require-final-newline t) + (c-set-style "symfony2") + + ;; Undo drupal/PSR-2 coding style whitespace effects + (set (make-local-variable 'show-trailing-whitespace) + (default-value 'show-trailing-whitespace))) + +(c-add-style + "psr2" + '("php")) + +(defun php-enable-psr2-coding-style () + "Makes php-mode comply to the PSR-2 coding style" + (interactive) + (setq indent-tabs-mode nil + fill-column 78 + c-indent-comments-syntactically-p t + require-final-newline t) + (c-set-style "psr2") + + ;; Apply drupal-like coding style whitespace effects + (set (make-local-variable 'require-final-newline) t) + (set (make-local-variable 'show-trailing-whitespace) t) + (add-hook 'before-save-hook 'delete-trailing-whitespace nil t)) + +(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) + +;; 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))) + (goto-char (line-beginning-position)) + (if (or (when (boundp 'mumamo-multi-major-mode) mumamo-multi-major-mode) + ;; Fix-me: no idea how to check for mmm or multi-mode + (save-match-data + (not (or (re-search-forward html-tag-re (line-end-position) t) + (re-search-backward html-tag-re (line-beginning-position) t))))) + (progn + (goto-char here) + t) + (goto-char here) + (setq php-warned-bad-indent t) + (let* ((known-multi-libs '(("mumamo" mumamo (lambda () (nxhtml-mumamo))) + ("mmm-mode" mmm-mode (lambda () (mmm-mode 1))) + ("multi-mode" multi-mode (lambda () (multi-mode 1))) + ("web-mode" web-mode (lambda () (web-mode))))) + (known-names (mapcar (lambda (lib) (car lib)) known-multi-libs)) + (available-multi-libs (delq nil + (mapcar + (lambda (lib) + (when (locate-library (car lib)) lib)) + known-multi-libs))) + (available-names (mapcar (lambda (lib) (car lib)) available-multi-libs)) + (base-msg + (concat + "Indentation fails badly with mixed HTML/PHP in the HTML part in +plain `php-mode'. To get indentation to work you must use an +Emacs library that supports 'multiple major modes' in a buffer. +Parts of the buffer will then be in `php-mode' and parts in for +example `html-mode'. Known such libraries are:\n\t" + (mapconcat 'identity known-names ", ") + "\n" + (if available-multi-libs + (concat + "You have these available in your `load-path':\n\t" + (mapconcat 'identity available-names ", ") + "\n\n" + "Do you want to turn any of those on? ") + "You do not have any of those in your `load-path'."))) + (is-using-multi + (catch 'is-using + (dolist (lib available-multi-libs) + (when (and (boundp (cadr lib)) + (symbol-value (cadr lib))) + (throw 'is-using t)))))) + (unless is-using-multi + (if available-multi-libs + (if (not (y-or-n-p base-msg)) + (message "Did not do indentation, but you can try again now if you want") + (let* ((name + (if (= 1 (length available-multi-libs)) + (car available-names) + ;; Minibuffer window is more than one line, fix that first: + (message "") + (completing-read "Choose multiple major mode support library: " + available-names nil t + (car available-names) + '(available-names . 1) + ))) + (mode (when name + (caddr (assoc name available-multi-libs))))) + (when mode + ;; Minibuffer window is more than one line, fix that first: + (message "") + (load name) + (funcall mode)))) + (lwarn 'php-indent :warning base-msg))) + nil)))) + +(defun php-cautious-indent-region (start end &optional quiet) + (if (or (not php-mode-warn-if-mumamo-off) + php-warned-bad-indent + (php-check-html-for-indentation)) + (funcall 'c-indent-region start end quiet))) + +(defun php-cautious-indent-line () + (if (or (not php-mode-warn-if-mumamo-off) + php-warned-bad-indent + (php-check-html-for-indentation)) + (let ((here (point)) + doit) + (move-beginning-of-line nil) + ;; Don't indent heredoc end mark + (save-match-data + (unless (looking-at "[a-zA-Z0-9_]+;\n") + (setq doit t))) + (goto-char here) + (when doit + (funcall 'c-indent-line))))) + +(defun php-c-at-vsemi-p (&optional pos) + "Return t on html lines (including php region border), otherwise nil. +POS is a position on the line in question. + +This is was done due to the problem reported here: + + URL `https://answers.launchpad.net/nxhtml/+question/43320'" + (if (not php-template-compatibility) + nil + (setq pos (or pos (point))) + (let ((here (point)) + ret) + (save-match-data + (goto-char pos) + (beginning-of-line) + (setq ret (looking-at + (rx + (or (seq + bol + (0+ space) + "<" + (in "a-z\\?")) + (seq + (0+ not-newline) + (in "a-z\\?") + ">" + (0+ space) + eol)))))) + (goto-char here) + ret))) + +(defun php-c-vsemi-status-unknown-p () + "See `php-c-at-vsemi-p'." + ) + +(defun php-lineup-string-cont (langelem) + "Line up string toward equal sign or dot +e.g. +$str = 'some' + . 'string'; +this ^ lineup" + (save-excursion + (goto-char (cdr langelem)) + (when (or (search-forward "=" (line-end-position) t) + (search-forward "." (line-end-position) t)) + (vector (1- (current-column)))))) + +(defun php-lineup-arglist-intro (langelem) + (save-excursion + (goto-char (cdr langelem)) + (vector (+ (current-column) c-basic-offset)))) + +(defun php-lineup-arglist-close (langelem) + (save-excursion + (goto-char (cdr langelem)) + (vector (current-column)))) + +(defun php-lineup-arglist (langelem) + (save-excursion + (beginning-of-line) + (if (looking-at-p "\\s-*->") '+ 0))) + +(defun php-lineup-hanging-semicolon (langelem) + (save-excursion + (beginning-of-line) + (if (looking-at-p "\\s-*;\\s-*$") 0 '+))) + +(defconst php-heredoc-start-re + "<<<\\(?:\\w+\\|'\\w+'\\)$" + "Regular expression for the start of a PHP heredoc.") + +(defun php-heredoc-end-re (heredoc-start) + "Build a regular expression for the end of a heredoc started by +the string HEREDOC-START." + ;; Extract just the identifier without <<< and quotes. + (string-match "\\w+" heredoc-start) + (concat "^\\(" (match-string 0 heredoc-start) "\\)\\W")) + +(defsubst php-in-string-p () + (nth 3 (syntax-ppss))) + +(defsubst php-in-comment-p () + (nth 4 (syntax-ppss))) + +(defun php-syntax-propertize-function (start end) + "Apply propertize rules from START to END." + ;; (defconst php-syntax-propertize-function + ;; (syntax-propertize-rules + ;; (php-heredoc-start-re (0 (ignore (php-heredoc-syntax)))))) + (goto-char start) + (while (and (< (point) end) + (re-search-forward php-heredoc-start-re end t)) + (php-heredoc-syntax)) + (goto-char start) + (while (re-search-forward "['\"]" end t) + (when (php-in-comment-p) + (c-put-char-property (match-beginning 0) + 'syntax-table (string-to-syntax "_"))))) + +(defun php-heredoc-syntax () + "Mark the boundaries of searched heredoc." + (goto-char (match-beginning 0)) + (c-put-char-property (point) 'syntax-table (string-to-syntax "|")) + (if (re-search-forward (php-heredoc-end-re (match-string 0)) nil t) + (goto-char (match-end 1)) + ;; Did not find the delimiter so go to the end of the buffer. + (goto-char (point-max))) + (c-put-char-property (1- (point)) 'syntax-table (string-to-syntax "|"))) + +(defun php-syntax-propertize-extend-region (start end) + "Extend the propertize region if START or END falls inside a +PHP heredoc." + (let ((new-start) + (new-end)) + (goto-char start) + (when (re-search-backward php-heredoc-start-re nil t) + (let ((maybe (point))) + (when (and (re-search-forward + (php-heredoc-end-re (match-string 0)) nil t) + (> (point) start)) + (setq new-start maybe)))) + (goto-char end) + (when (re-search-backward php-heredoc-start-re nil t) + (if (re-search-forward + (php-heredoc-end-re (match-string 0)) nil t) + (when (> (point) end) + (setq new-end (point))) + (setq new-end (point-max)))) + (when (or new-start new-end) + (cons (or new-start start) (or new-end end))))) + +(easy-menu-define php-mode-menu php-mode-map "PHP Mode Commands" + (cons "PHP" (c-lang-const c-mode-menu php))) + +;;;###autoload +(define-derived-mode php-mode c-mode "PHP" + "Major mode for editing PHP code. + +\\{php-mode-map}" + + (c-initialize-cc-mode t) + (c-init-language-vars php-mode) + (c-common-init 'php-mode) + + (modify-syntax-entry ?_ "_" php-mode-syntax-table) + (modify-syntax-entry ?` "\"" php-mode-syntax-table) + (modify-syntax-entry ?\" "\"" php-mode-syntax-table) + (modify-syntax-entry ?# "< b" php-mode-syntax-table) + (modify-syntax-entry ?\n "> b" php-mode-syntax-table) + + (set (make-local-variable 'syntax-propertize-via-font-lock) + '(("\\(\"\\)\\(\\\\.\\|[^\"\n\\]\\)*\\(\"\\)" (1 "\"") (3 "\"")) + ("\\(\'\\)\\(\\\\.\\|[^\'\n\\]\\)*\\(\'\\)" (1 "\"") (3 "\"")))) + + (when (boundp 'syntax-propertize-function) + (add-to-list (make-local-variable 'syntax-propertize-extend-region-functions) + #'php-syntax-propertize-extend-region) + (set (make-local-variable 'syntax-propertize-function) + #'php-syntax-propertize-function)) + + (setq font-lock-maximum-decoration t + imenu-generic-expression php-imenu-generic-expression) + + ;; PHP vars are case-sensitive + (setq case-fold-search t) + + ;; Do not force newline at end of file. Such newlines can cause + ;; trouble if the PHP file is included in another file before calls + ;; to header() or cookie(). + (set (make-local-variable 'require-final-newline) nil) + (set (make-local-variable 'next-line-add-newlines) nil) + + ;; PEAR coding standards + (add-hook 'php-mode-pear-hook 'php-enable-pear-coding-style + nil t) + + ;; ;; Drupal coding standards + (add-hook 'php-mode-drupal-hook 'php-enable-drupal-coding-style + nil t) + + ;; ;; WordPress coding standards + (add-hook 'php-mode-wordpress-hook 'php-enable-wordpress-coding-style + nil t) + + ;; ;; Symfony2 coding standards + (add-hook 'php-mode-symfony2-hook 'php-enable-symfony2-coding-style + nil t) + + ;; ;; PSR-2 coding standards + (add-hook 'php-mode-psr2-hook 'php-enable-psr2-coding-style + nil t) + + (cond ((eq php-mode-coding-style 'pear) + (php-enable-pear-coding-style) + (run-hooks 'php-mode-pear-hook)) + ((eq php-mode-coding-style 'drupal) + (php-enable-drupal-coding-style) + (run-hooks 'php-mode-drupal-hook)) + ((eq php-mode-coding-style 'wordpress) + (php-enable-wordpress-coding-style) + (run-hooks 'php-mode-wordpress-hook)) + ((eq php-mode-coding-style 'symfony2) + (php-enable-symfony2-coding-style) + (run-hooks 'php-mode-symfony2-hook)) + ((eq php-mode-coding-style 'psr2) + (php-enable-psr2-coding-style) + (run-hooks 'php-mode-psr2-hook))) + + (if (or php-mode-force-pear + (and (stringp buffer-file-name) + (string-match "PEAR\\|pear" + (buffer-file-name)) + (string-match "\\.php$" (buffer-file-name)))) + (run-hooks 'php-mode-pear-hook)) + + (setq indent-line-function 'php-cautious-indent-line) + (setq indent-region-function 'php-cautious-indent-region) + (setq c-at-vsemi-p-fn 'php-c-at-vsemi-p) + (setq c-vsemi-status-unknown-p 'php-c-vsemi-status-unknown-p) + + (set (make-local-variable 'syntax-begin-function) + 'c-beginning-of-syntax) + + ;; We map the php-{beginning,end}-of-defun functions so that they + ;; replace the similar commands that we inherit from CC Mode. + ;; Because of our remapping we may not actually need to keep the + ;; following two local variables, but we keep them for now until we + ;; are completely sure their removal will not break any current + ;; behavior or backwards compatibility. + (set (make-local-variable 'beginning-of-defun-function) + 'php-beginning-of-defun) + (set (make-local-variable 'end-of-defun-function) + 'php-end-of-defun) + + (set (make-local-variable 'open-paren-in-column-0-is-defun-start) + nil) + (set (make-local-variable 'defun-prompt-regexp) + "^\\s-*function\\s-+&?\\s-*\\(\\(\\sw\\|\\s_\\)+\\)\\s-*") + (set (make-local-variable 'add-log-current-defun-header-regexp) + php-beginning-of-defun-regexp)) + +;; Define function name completion function +(defvar php-completion-table nil + "Obarray of tag names defined in current tags table and functions known to PHP.") + +(defun php-complete-function () + "Perform function completion on the text around point. +Completes to the set of names listed in the current tags table +and the standard php functions. +The string to complete is chosen in the same way as the default +for \\[find-tag] (which see)." + (interactive) + (let ((pattern (php-get-pattern)) + beg + completion + (php-functions (php-completion-table))) + (if (not pattern) (message "Nothing to complete") + (if (not (search-backward pattern nil t)) + (message "Can't complete here") + (setq beg (point)) + (forward-char (length pattern)) + (setq completion (try-completion pattern php-functions nil)) + (cond ((eq completion t)) + ((null completion) + (message "Can't find completion for \"%s\"" pattern) + (ding)) + ((not (string= pattern completion)) + (delete-region beg (point)) + (insert completion)) + (t + (message "Making completion list...") + (with-output-to-temp-buffer "*Completions*" + (display-completion-list + (all-completions pattern php-functions))) + (message "Making completion list...%s" "done"))))))) + +(defun php-completion-table () + "Build variable `php-completion-table' on demand. +The table includes the PHP functions and the tags from the +current `tags-file-name'." + (or (and tags-file-name + (save-excursion (tags-verify-table tags-file-name)) + php-completion-table) + (let ((tags-table + (when tags-file-name + (with-current-buffer (get-file-buffer tags-file-name) + (etags-tags-completion-table)))) + (php-table + (cond ((and (not (string= "" php-completion-file)) + (file-readable-p php-completion-file)) + (php-build-table-from-file php-completion-file)) + (php-manual-path + (php-build-table-from-path php-manual-path)) + (t nil)))) + (unless (or php-table tags-table) + (error + (concat "No TAGS file active nor are " + "`php-completion-file' or `php-manual-path' set"))) + (when tags-table + ;; Combine the tables. + (mapatoms (lambda (sym) (intern (symbol-name sym) php-table)) + tags-table)) + (setq php-completion-table php-table)))) + +(defun php-build-table-from-file (filename) + (let ((table (make-vector 1022 0)) + (buf (find-file-noselect filename))) + (with-current-buffer buf + (goto-char (point-min)) + (while (re-search-forward + "^\\([-a-zA-Z0-9_.]+\\)\n" + nil t) + (intern (buffer-substring (match-beginning 1) (match-end 1)) + table))) + (kill-buffer buf) + table)) + +(defun php-build-table-from-path (path) + (let ((table (make-vector 1022 0)) + (files (directory-files + path + nil + "^function\\..+\\.html$"))) + (mapc (lambda (file) + (string-match "\\.\\([-a-zA-Z_0-9]+\\)\\.html$" file) + (intern + (replace-regexp-in-string + "-" "_" (substring file (match-beginning 1) (match-end 1)) t) + table)) + files) + table)) + +;; Find the pattern we want to complete +;; find-tag-default from GNU Emacs etags.el +(defun php-get-pattern () + (save-excursion + (while (looking-at "\\sw\\|\\s_") + (forward-char 1)) + (if (or (re-search-backward "\\sw\\|\\s_" + (save-excursion (beginning-of-line) (point)) + t) + (re-search-forward "\\(\\sw\\|\\s_\\)+" + (save-excursion (end-of-line) (point)) + t)) + (progn (goto-char (match-end 0)) + (buffer-substring-no-properties + (point) + (progn (forward-sexp -1) + (while (looking-at "\\s'") + (forward-char 1)) + (point)))) + nil))) + +(defun php-show-arglist () + (interactive) + (let* ((tagname (php-get-pattern)) + (buf (find-tag-noselect tagname nil nil)) + arglist) + (with-current-buffer buf + (goto-char (point-min)) + (when (re-search-forward + (format "function\\s-+%s\\s-*(\\([^{]*\\))" tagname) + nil t) + (setq arglist (buffer-substring-no-properties + (match-beginning 1) (match-end 1))))) + (if arglist + (message "Arglist for %s: %s" tagname arglist) + (message "Unknown function: %s" tagname)))) + +(defcustom php-search-documentation-browser-function nil + "Function to display PHP documentation in a WWW browser. + +If non-nil, this shadows the value of `browse-url-browser-function' when +calling `php-search-documentation' or `php-search-local-documentation'." + :type '(choice (const :tag "default" nil) function) + :link '(variable-link browse-url-browser-function) + :group 'php) + +(defun php-browse-documentation-url (url) + "Browse a documentation URL using the configured browser function. + +See `php-search-documentation-browser-function'." + (let ((browse-url-browser-function + (or php-search-documentation-browser-function + browse-url-browser-function))) + (browse-url url))) + +(defvar php-search-local-documentation-types + (list "function" "control-structures" "class" "book") + ;; "intro" and "ref" also look interesting, but for all practical purposes + ;; their terms are sub-sets of the "book" terms (with the few exceptions + ;; being very unlikely search terms). + "The set (and priority sequence) of documentation file prefixes +under which to search for files in the local documentation directory.") + +(defvar php-search-local-documentation-words-cache nil) + +(defun php--search-documentation-read-arg () + "Obtain interactive argument for searching documentation." + ;; Cache the list of documentation words available for completion, + ;; based on the defined types-of-interest. + (let ((types-list php-search-local-documentation-types) + (words-cache php-search-local-documentation-words-cache) + (local-manual (and (stringp php-manual-path) + (not (string= php-manual-path ""))))) + (when (and local-manual + (not (assq types-list words-cache))) + ;; Generate the cache on the first run, or if the types changed. + ;; We read the filenames matching our types list in the local + ;; documention directory, and extract the 'middle' component + ;; of each. e.g. "function.array-map.html" => "array_map". + (let* ((types-opt (regexp-opt types-list)) + (pattern (concat "\\`" types-opt "\\.\\(.+\\)\\.html\\'")) + (collection + (mapcar (lambda (filename) (subst-char-in-string + ?- ?_ (replace-regexp-in-string + pattern "\\1" filename))) + (directory-files php-manual-path nil pattern)))) + ;; Replace the entire cache. If the types changed, we don't need + ;; to retain the collection for the previous value. + (setq words-cache (list (cons types-list collection))) + (setq php-search-local-documentation-words-cache words-cache))) + ;; By default we search for (current-word) immediately, without prompting. + ;; With a prefix argument, or if there is no (current-word), we perform a + ;; completing read for a word from the cached collection. + (let* ((default (current-word)) + (prompt (if default + (format "Search PHP docs (%s): " default) + "Search PHP docs: ")) + (collection (and local-manual + (cdr (assq types-list words-cache)))) + (word (if (or current-prefix-arg (not default)) + (completing-read prompt collection nil nil nil nil default) + default))) + ;; Return interactive argument list. + (list word)))) + +(defun php-search-local-documentation (word) + "Search the local PHP documentation (i.e. in `php-manual-path') for +the word at point. The function returns t if the requested documentation +exists, and nil otherwise. + +With a prefix argument, prompt (with completion) for a word to search for." + (interactive (php--search-documentation-read-arg)) + (cl-flet ((php-file-for (type name) + (expand-file-name + (format "%s.%s.html" type + (replace-regexp-in-string + "_" "-" (downcase name))) + php-manual-path)) + (php-file-url (file) + ;; Some browsers require the file:// prefix. + ;; Others do not seem to care. But it should + ;; never be incorrect to use the prefix. + (if (string-prefix-p "file://" file) + file + (concat "file://" file)))) + (let ((file (catch 'found + (loop for type in php-search-local-documentation-types do + (let ((file (php-file-for type word))) + (when (file-exists-p file) + (throw 'found file))))))) + (when file + (php-browse-documentation-url (php-file-url file)) + t)))) + +;; Define function documentation function +(defun php-search-documentation (word) + "Search PHP documentation for the word at point. + +If `php-manual-path' has a non-empty string value then the command +will first try searching the local documentation. If the requested +documentation does not exist it will fallback to searching the PHP +website. + +With a prefix argument, prompt for a documentation word to search +for. If the local documentation is available, it is used to build +a completion list." + (interactive (php--search-documentation-read-arg)) + (cl-flet ((php-search-web-documentation (name) + (php-browse-documentation-url + (concat php-search-url name)))) + (if (and (stringp php-manual-path) + (not (string= php-manual-path ""))) + (or (php-search-local-documentation word) + (php-search-web-documentation word)) + (php-search-web-documentation word)))) + +;; Define function for browsing manual +(defun php-browse-manual () + "Bring up manual for PHP." + (interactive) + (browse-url php-manual-url)) + +(defconst php-font-lock-keywords-1 (c-lang-const c-matchers-1 php) + "Basic highlighting for PHP mode.") + +(defconst php-font-lock-keywords-2 (c-lang-const c-matchers-2 php) + "Medium level highlighting for PHP mode.") + +(defconst php-font-lock-keywords-3 + (append + ;; php-mode patterns *before* cc-mode: + ;; only add patterns here if you want to prevent cc-mode from applying + ;; a different face. + '( + ;; Highlight variables, e.g. 'var' in '$var' and '$obj->var', but + ;; not in $obj->var() + ("->\\(\\sw+\\)\\s-*(" 1 'default) + + ;; Highlight special variables + ("\\$\\(this\\|that\\)" 1 font-lock-constant-face) + ("\\(\\$\\|->\\)\\([a-zA-Z0-9_]+\\)" 2 font-lock-variable-name-face) + + ;; Highlight function/method names + ("\\var', but + ;; not in $obj->var() + ("->\\(\\sw+\\)\\s-*(" 1 'default) + + ("\\(\\$\\|->\\)\\([a-zA-Z0-9_]+\\)" 2 font-lock-variable-name-face) + + ;; Highlight all upper-cased symbols as constant + ("\\<\\([A-Z_][A-Z0-9_]+\\)\\>" 1 font-lock-constant-face) + + ;; Highlight all statically accessed class names as constant, + ;; another valid option would be using type-face, but using + ;; constant-face because this is how it works in c++-mode. + ("\\(\\sw+\\)::" 1 font-lock-constant-face) + + ;; Highlight class name after "use .. as" + ("\\" "")) 0 font-lock-preprocessor-face))) + "Detailed highlighting for PHP mode.") + +(defvar php-font-lock-keywords php-font-lock-keywords-3 + "Default expressions to highlight in PHP mode.") + +;;; Provide support for Flymake so that users can see warnings and +;;; errors in real-time as they write code. + +(defun flymake-php-init () + (let* ((temp-file (flymake-init-create-temp-buffer-copy + 'flymake-create-temp-inplace)) + (local-file (file-relative-name + temp-file + (file-name-directory buffer-file-name)))) + (list php-executable (list "-f" local-file "-l")))) + +(add-to-list 'flymake-allowed-file-name-masks + '("\\.php[345s]?$" + flymake-php-init + flymake-simple-cleanup + flymake-get-real-file-name)) + +(add-to-list 'flymake-err-line-patterns + '("\\(Parse\\|Fatal\\) error: \\(.*?\\) in \\(.*?\\) on line \\([0-9]+\\)" 3 4 nil 2)) + + +(defun php-send-region (start end) + "Send the region between `start' and `end' to PHP for execution. +The output will appear in the buffer *PHP*." + (interactive "r") + (let ((php-buffer (get-buffer-create "*PHP*")) + (code (buffer-substring start end))) + ;; Calling 'php -r' will fail if we send it code that starts with + ;; '\\|::") + (no-front-space "->\\|::")) + (when (and (eq major-mode 'php-mode) + (or (looking-at-p (concat " \\(" no-behind-space "\\)")) + (save-excursion + (forward-char -2) + (looking-at-p no-front-space)))) + (delete-char 1)))) + +(ad-activate 'fixup-whitespace) + +;; Advice `font-lock-fontify-keywords-region' to support namespace +;; separators in class names. Use word syntax for backslashes when +;; doing keyword fontification, but not when doing syntactic +;; fontification because that breaks \ as escape character in strings. +;; +;; Special care is taken to restore the original syntax, because we +;; want \ not to be word for functions like forward-word. +(defadvice font-lock-fontify-keywords-region (around backslash-as-word activate) + "Fontify keywords with backslash as word character" + (let ((old-syntax (string (char-syntax ?\\)))) + (modify-syntax-entry ?\\ "w") + ad-do-it + (modify-syntax-entry ?\\ old-syntax))) + + +;;;###autoload +(dolist (pattern '("\\.php[s345t]?\\'" "\\.phtml\\'" "Amkfile" "\\.amk$")) + (add-to-list 'auto-mode-alist `(,pattern . php-mode) t)) + +(provide 'php-mode) + +;;; php-mode.el ends here -- cgit v1.3