diff options
Diffstat (limited to '.emacs.d/lisp/php-mode.el')
| -rw-r--r-- | .emacs.d/lisp/php-mode.el | 1536 |
1 files changed, 1536 insertions, 0 deletions
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 @@ | |||
| 1 | ;;; php-mode.el --- Major mode for editing PHP code | ||
| 2 | |||
| 3 | ;; Copyright (C) 1999, 2000, 2001, 2003, 2004 Turadg Aleahmad | ||
| 4 | ;; 2008 Aaron S. Hawley | ||
| 5 | ;; 2011, 2012, 2013, 2014, 2015 Eric James Michael Ritz | ||
| 6 | |||
| 7 | ;;; Author: Eric James Michael Ritz | ||
| 8 | ;;; URL: https://github.com/ejmr/php-mode | ||
| 9 | ;;; Version: 1.15.3 | ||
| 10 | |||
| 11 | (defconst php-mode-version-number "1.15.3" | ||
| 12 | "PHP Mode version number.") | ||
| 13 | |||
| 14 | (defconst php-mode-modified "2015-01-31" | ||
| 15 | "PHP Mode build date.") | ||
| 16 | |||
| 17 | ;;; License | ||
| 18 | |||
| 19 | ;; This file is free software; you can redistribute it and/or | ||
| 20 | ;; modify it under the terms of the GNU General Public License | ||
| 21 | ;; as published by the Free Software Foundation; either version 3 | ||
| 22 | ;; of the License, or (at your option) any later version. | ||
| 23 | |||
| 24 | ;; This file is distributed in the hope that it will be useful, | ||
| 25 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 26 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 27 | ;; GNU General Public License for more details. | ||
| 28 | |||
| 29 | ;; You should have received a copy of the GNU General Public License | ||
| 30 | ;; along with this file; if not, write to the Free Software | ||
| 31 | ;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 32 | ;; 02110-1301, USA. | ||
| 33 | |||
| 34 | ;;; Usage | ||
| 35 | |||
| 36 | ;; Put this file in your Emacs lisp path (eg. site-lisp) and add to | ||
| 37 | ;; your .emacs file: | ||
| 38 | ;; | ||
| 39 | ;; (require 'php-mode) | ||
| 40 | |||
| 41 | ;; To use abbrev-mode, add lines like this: | ||
| 42 | ;; (add-hook 'php-mode-hook | ||
| 43 | ;; '(lambda () (define-abbrev php-mode-abbrev-table "ex" "extends"))) | ||
| 44 | |||
| 45 | ;; To make php-mode compatible with html-mode, see http://php-mode.sf.net | ||
| 46 | |||
| 47 | ;; Many options available under Help:Customize | ||
| 48 | ;; Options specific to php-mode are in | ||
| 49 | ;; Programming/Languages/Php | ||
| 50 | ;; Since it inherits much functionality from c-mode, look there too | ||
| 51 | ;; Programming/Languages/C | ||
| 52 | |||
| 53 | ;;; Commentary: | ||
| 54 | |||
| 55 | ;; PHP mode is a major mode for editing PHP source code. It's an | ||
| 56 | ;; extension of C mode; thus it inherits all C mode's navigation | ||
| 57 | ;; functionality. But it colors according to the PHP grammar and | ||
| 58 | ;; indents according to the PEAR coding guidelines. It also includes | ||
| 59 | ;; a couple handy IDE-type features such as documentation search and a | ||
| 60 | ;; source and class browser. | ||
| 61 | |||
| 62 | ;;; Code: | ||
| 63 | |||
| 64 | (require 'cc-mode) | ||
| 65 | (eval-when-compile | ||
| 66 | (require 'cc-langs) | ||
| 67 | (require 'cc-fonts)) | ||
| 68 | |||
| 69 | ;; Boilerplate from other `cc-mode' derived modes. See | ||
| 70 | ;; http://cc-mode.sourceforge.net/derived-mode-ex.el for details on how this all | ||
| 71 | ;; fits together. | ||
| 72 | (eval-and-compile | ||
| 73 | (c-add-language 'php-mode 'java-mode)) | ||
| 74 | |||
| 75 | (require 'font-lock) | ||
| 76 | (require 'add-log) | ||
| 77 | (require 'custom) | ||
| 78 | (require 'flymake) | ||
| 79 | (require 'etags) | ||
| 80 | (require 'speedbar) | ||
| 81 | (eval-when-compile | ||
| 82 | (unless (require 'cl-lib nil t) | ||
| 83 | (require 'cl)) | ||
| 84 | (require 'regexp-opt) | ||
| 85 | (defvar c-vsemi-status-unknown-p) | ||
| 86 | (defvar syntax-propertize-via-font-lock)) | ||
| 87 | |||
| 88 | ;; Work around emacs bug#18845, cc-mode expects cl to be loaded | ||
| 89 | ;; while php-mode only uses cl-lib (without compatibility aliases) | ||
| 90 | (eval-when-compile | ||
| 91 | (if (and (= emacs-major-version 24) (= emacs-minor-version 4)) | ||
| 92 | (require 'cl))) | ||
| 93 | |||
| 94 | ;; Use the recommended cl functions in php-mode but alias them to the | ||
| 95 | ;; old names when we detect emacs < 24.3 | ||
| 96 | (if (and (= emacs-major-version 24) (< emacs-minor-version 3)) | ||
| 97 | (progn | ||
| 98 | (unless (fboundp 'cl-flet) | ||
| 99 | (defalias 'cl-flet 'flet)) | ||
| 100 | (unless (fboundp 'cl-set-difference) | ||
| 101 | (defalias 'cl-set-difference 'set-difference)))) | ||
| 102 | |||
| 103 | |||
| 104 | ;; Local variables | ||
| 105 | ;;;###autoload | ||
| 106 | (defgroup php nil | ||
| 107 | "Major mode `php-mode' for editing PHP code." | ||
| 108 | :prefix "php-" | ||
| 109 | :group 'languages | ||
| 110 | :link '(url-link :tag "Official Site" "https://github.com/ejmr/php-mode") | ||
| 111 | :link '(url-link :tag "PHP Mode Wiki" "https://github.com/ejmr/php-mode/wiki")) | ||
| 112 | |||
| 113 | (defcustom php-executable "/usr/bin/php" | ||
| 114 | "The location of the PHP executable." | ||
| 115 | :type 'string | ||
| 116 | :group 'php) | ||
| 117 | |||
| 118 | (defcustom php-default-face 'default | ||
| 119 | "Default face in `php-mode' buffers." | ||
| 120 | :type 'face | ||
| 121 | :group 'php) | ||
| 122 | |||
| 123 | (defcustom php-speedbar-config t | ||
| 124 | "When set to true automatically configures Speedbar to observe PHP files. | ||
| 125 | Ignores php-file patterns option; fixed to expression \"\\.\\(inc\\|php[s345]?\\)\"" | ||
| 126 | :type 'boolean | ||
| 127 | :set (lambda (sym val) | ||
| 128 | (set-default sym val) | ||
| 129 | (when val | ||
| 130 | (speedbar-add-supported-extension | ||
| 131 | "\\.\\(inc\\|php[s345]?\\|phtml\\)"))) | ||
| 132 | :group 'php) | ||
| 133 | |||
| 134 | (defcustom php-mode-speedbar-open nil | ||
| 135 | "Normally `php-mode' starts with the speedbar closed. | ||
| 136 | Turning this on will open it whenever `php-mode' is loaded." | ||
| 137 | :type 'boolean | ||
| 138 | :set (lambda (sym val) | ||
| 139 | (set-default sym val) | ||
| 140 | (when val | ||
| 141 | (speedbar 1))) | ||
| 142 | :group 'php) | ||
| 143 | |||
| 144 | (defcustom php-template-compatibility t | ||
| 145 | "Should detect presence of html tags." | ||
| 146 | :type 'boolean | ||
| 147 | :group 'php) | ||
| 148 | |||
| 149 | (defun php-mode-extra-constants-create-regexp(kwds) | ||
| 150 | "Create regexp for the list of extra constant keywords KWDS." | ||
| 151 | (concat "[^_$]?\\<\\(" | ||
| 152 | (regexp-opt | ||
| 153 | (append kwds | ||
| 154 | (when (boundp 'web-mode-extra-php-constants) web-mode-extra-php-constants))) | ||
| 155 | "\\)\\>[^_]?")) | ||
| 156 | |||
| 157 | (defun php-mode-extra-constants-set(sym value) | ||
| 158 | "Apply the list of extra constant keywords VALUE. | ||
| 159 | |||
| 160 | This function is called when the custom variable php-extra-constants | ||
| 161 | is updated. The web-mode-extra-constants list is appended to the list | ||
| 162 | of constants when set." | ||
| 163 | ;; remove old keywords | ||
| 164 | (when (boundp 'php-extra-constants) | ||
| 165 | (font-lock-remove-keywords | ||
| 166 | 'php-mode `((,(php-mode-extra-constants-create-regexp php-extra-constants) 1 font-lock-constant-face)))) | ||
| 167 | ;; add new keywords | ||
| 168 | (when value | ||
| 169 | (font-lock-add-keywords | ||
| 170 | 'php-mode `((,(php-mode-extra-constants-create-regexp value) 1 font-lock-constant-face)))) | ||
| 171 | (set sym value)) | ||
| 172 | |||
| 173 | (defcustom php-lineup-cascaded-calls nil | ||
| 174 | "Indent chained method calls to the previous line" | ||
| 175 | :type 'boolean | ||
| 176 | :group 'php) | ||
| 177 | |||
| 178 | ;;;###autoload | ||
| 179 | (defcustom php-extra-constants '() | ||
| 180 | "A list of additional strings to treat as PHP constants." | ||
| 181 | :type 'list | ||
| 182 | :set 'php-mode-extra-constants-set | ||
| 183 | :group 'php) | ||
| 184 | |||
| 185 | (defun php-create-regexp-for-method (visibility) | ||
| 186 | "Make a regular expression for methods with the given VISIBILITY. | ||
| 187 | |||
| 188 | VISIBILITY must be a string that names the visibility for a PHP | ||
| 189 | method, e.g. 'public'. The parameter VISIBILITY can itself also | ||
| 190 | be a regular expression. | ||
| 191 | |||
| 192 | The regular expression this function returns will check for other | ||
| 193 | keywords that can appear in method signatures, e.g. 'final' and | ||
| 194 | 'static'. The regular expression will have one capture group | ||
| 195 | which will be the name of the method." | ||
| 196 | (concat | ||
| 197 | ;; Initial space with possible 'abstract' or 'final' keywords | ||
| 198 | "^\\s-*\\(?:\\(?:abstract\\|final\\)\\s-+\\)?" | ||
| 199 | ;; 'static' keyword may come either before or after visibility | ||
| 200 | "\\(?:" visibility "\\(?:\\s-+static\\)?\\|\\(?:static\\s-+\\)?" visibility "\\)\\s-+" | ||
| 201 | ;; Make sure 'function' comes next with some space after | ||
| 202 | "function\\s-+" | ||
| 203 | ;; Capture the name as the first group and the regexp and make sure | ||
| 204 | ;; by the end we see the opening parenthesis for the parameters. | ||
| 205 | "\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*(")) | ||
| 206 | |||
| 207 | (defun php-create-regexp-for-classlike (type) | ||
| 208 | "Accepts a `type' of a 'classlike' object as a string, such as | ||
| 209 | 'class' or 'interface', and returns a regexp as a string which | ||
| 210 | can be used to match against definitions for that classlike." | ||
| 211 | (concat | ||
| 212 | ;; First see if 'abstract' or 'final' appear, although really these | ||
| 213 | ;; are not valid for all values of `type' that the function | ||
| 214 | ;; accepts. | ||
| 215 | "^\\s-*\\(?:\\(?:abstract\\|final\\)\\s-+\\)?" | ||
| 216 | ;; The classlike type | ||
| 217 | type | ||
| 218 | ;; Its name, which is the first captured group in the regexp. We | ||
| 219 | ;; allow backslashes in the name to handle namespaces, but again | ||
| 220 | ;; this is not necessarily correct for all values of `type'. | ||
| 221 | "\\s-+\\(\\(?:\\sw\\|\\\\\\|\\s_\\)+\\)")) | ||
| 222 | |||
| 223 | (defvar php-imenu-generic-expression | ||
| 224 | `(("Namespaces" | ||
| 225 | ,(php-create-regexp-for-classlike "namespace") 1) | ||
| 226 | ("Classes" | ||
| 227 | ,(php-create-regexp-for-classlike "class") 1) | ||
| 228 | ("Interfaces" | ||
| 229 | ,(php-create-regexp-for-classlike "interface") 1) | ||
| 230 | ("Traits" | ||
| 231 | ,(php-create-regexp-for-classlike "trait") 1) | ||
| 232 | ("All Methods" | ||
| 233 | ,(php-create-regexp-for-method "\\(?:\\sw\\|\\s_\\)+") 1) | ||
| 234 | ("Private Methods" | ||
| 235 | ,(php-create-regexp-for-method "private") 1) | ||
| 236 | ("Protected Methods" | ||
| 237 | ,(php-create-regexp-for-method "protected") 1) | ||
| 238 | ("Public Methods" | ||
| 239 | ,(php-create-regexp-for-method "public") 1) | ||
| 240 | ("Anonymous Functions" | ||
| 241 | "\\<\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*=\\s-*function\\s-*(" 1) | ||
| 242 | ("Named Functions" | ||
| 243 | "^\\s-*function\\s-+\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*(" 1)) | ||
| 244 | "Imenu generic expression for PHP Mode. See `imenu-generic-expression'.") | ||
| 245 | |||
| 246 | (defcustom php-manual-url "http://www.php.net/manual/en/" | ||
| 247 | "URL at which to find PHP manual. | ||
| 248 | You can replace \"en\" with your ISO language code." | ||
| 249 | :type 'string | ||
| 250 | :group 'php) | ||
| 251 | |||
| 252 | (defcustom php-search-url "http://www.php.net/" | ||
| 253 | "URL at which to search for documentation on a word." | ||
| 254 | :type 'string | ||
| 255 | :group 'php) | ||
| 256 | |||
| 257 | (defcustom php-completion-file "" | ||
| 258 | "Path to the file which contains the function names known to PHP." | ||
| 259 | :type 'string | ||
| 260 | :group 'php) | ||
| 261 | |||
| 262 | (defcustom php-manual-path "" | ||
| 263 | "Path to the directory which contains the PHP manual." | ||
| 264 | :type 'string | ||
| 265 | :group 'php) | ||
| 266 | |||
| 267 | ;;;###autoload | ||
| 268 | (add-to-list 'interpreter-mode-alist (cons "php" 'php-mode)) | ||
| 269 | |||
| 270 | (defcustom php-mode-hook nil | ||
| 271 | "List of functions to be executed on entry to `php-mode'." | ||
| 272 | :type 'hook | ||
| 273 | :group 'php) | ||
| 274 | |||
| 275 | (defcustom php-mode-pear-hook nil | ||
| 276 | "Hook called when a PHP PEAR file is opened with `php-mode'." | ||
| 277 | :type 'hook | ||
| 278 | :group 'php) | ||
| 279 | |||
| 280 | (defcustom php-mode-drupal-hook nil | ||
| 281 | "Hook called when a Drupal file is opened with `php-mode'." | ||
| 282 | :type 'hook | ||
| 283 | :group 'php) | ||
| 284 | |||
| 285 | (defcustom php-mode-wordpress-hook nil | ||
| 286 | "Hook called when a WordPress file is opened with `php-mode'." | ||
| 287 | :type 'hook | ||
| 288 | :group 'php) | ||
| 289 | |||
| 290 | (defcustom php-mode-symfony2-hook nil | ||
| 291 | "Hook called when a Symfony2 file is opened with `php-mode'." | ||
| 292 | :type 'hook | ||
| 293 | :group 'php) | ||
| 294 | |||
| 295 | (defcustom php-mode-psr2-hook nil | ||
| 296 | "Hook called when a PSR-2 file is opened with `php-mode'." | ||
| 297 | :type 'hook | ||
| 298 | :group 'php) | ||
| 299 | |||
| 300 | (defcustom php-mode-force-pear nil | ||
| 301 | "Normally PEAR coding rules are enforced only when the filename contains \"PEAR.\" | ||
| 302 | Turning this on will force PEAR rules on all PHP files." | ||
| 303 | :type 'boolean | ||
| 304 | :group 'php) | ||
| 305 | |||
| 306 | (defcustom php-mode-warn-if-mumamo-off t | ||
| 307 | "Warn once per buffer if you try to indent a buffer without | ||
| 308 | mumamo-mode turned on. Detects if there are any HTML tags in the | ||
| 309 | buffer before warning, but this is is not very smart; e.g. if you | ||
| 310 | have any tags inside a PHP string, it will be fooled." | ||
| 311 | :type '(choice (const :tag "Warg" t) (const "Don't warn" nil)) | ||
| 312 | :group 'php) | ||
| 313 | |||
| 314 | (defcustom php-mode-coding-style 'pear | ||
| 315 | "Select default coding style to use with php-mode. | ||
| 316 | This variable can take one of the following symbol values: | ||
| 317 | |||
| 318 | `Default' - use a reasonable default style for PHP. | ||
| 319 | |||
| 320 | `PEAR' - use coding styles preferred for PEAR code and modules. | ||
| 321 | |||
| 322 | `Drupal' - use coding styles preferred for working with Drupal projects. | ||
| 323 | |||
| 324 | `WordPress' - use coding styles preferred for working with WordPress projects. | ||
| 325 | |||
| 326 | `Symfony2' - use coding styles preferred for working with Symfony2 projects. | ||
| 327 | |||
| 328 | `PSR-2' - use coding styles preferred for working with projects using PSR-2 standards." | ||
| 329 | :type '(choice (const :tag "Default" default) | ||
| 330 | (const :tag "PEAR" pear) | ||
| 331 | (const :tag "Drupal" drupal) | ||
| 332 | (const :tag "WordPress" wordpress) | ||
| 333 | (const :tag "Symfony2" symfony2) | ||
| 334 | (const :tag "PSR-2" psr2)) | ||
| 335 | :group 'php | ||
| 336 | :set 'php-mode-custom-coding-style-set | ||
| 337 | :initialize 'custom-initialize-default) | ||
| 338 | |||
| 339 | (defun php-mode-custom-coding-style-set (sym value) | ||
| 340 | (when (eq major-mode 'php-mode) | ||
| 341 | (set sym value) | ||
| 342 | (set-default sym value) | ||
| 343 | (cond ((eq value 'pear) | ||
| 344 | (php-enable-pear-coding-style)) | ||
| 345 | ((eq value 'default) | ||
| 346 | (php-enable-default-coding-style)) | ||
| 347 | ((eq value 'drupal) | ||
| 348 | (php-enable-drupal-coding-style)) | ||
| 349 | ((eq value 'wordpress) | ||
| 350 | (php-enable-wordpress-coding-style)) | ||
| 351 | ((eq value 'symfony2) | ||
| 352 | (php-enable-symfony2-coding-style)) | ||
| 353 | ((eq value 'psr2) | ||
| 354 | (php-enable-psr2-coding-style))))) | ||
| 355 | |||
| 356 | (defun php-mode-version () | ||
| 357 | "Display string describing the version of PHP mode." | ||
| 358 | (interactive) | ||
| 359 | (message "PHP mode %s of %s" | ||
| 360 | php-mode-version-number php-mode-modified)) | ||
| 361 | |||
| 362 | (defvar php-mode-map | ||
| 363 | (let ((map (make-sparse-keymap))) | ||
| 364 | ;; (define-key map [menu-bar php] | ||
| 365 | ;; (cons "PHP" (make-sparse-keymap "PHP"))) | ||
| 366 | |||
| 367 | ;; (define-key map [menu-bar php complete-function] | ||
| 368 | ;; '("Complete function name" . php-complete-function)) | ||
| 369 | ;; (define-key map [menu-bar php browse-manual] | ||
| 370 | ;; '("Browse manual" . php-browse-manual)) | ||
| 371 | ;; (define-key map [menu-bar php search-documentation] | ||
| 372 | ;; '("Search documentation" . php-search-documentation)) | ||
| 373 | |||
| 374 | ;; By default PHP mode binds C-M-h to c-mark-function, which it | ||
| 375 | ;; inherits from cc-mode. But there are situations where | ||
| 376 | ;; c-mark-function fails to properly mark a function. For | ||
| 377 | ;; example, if we use c-mark-function within a method definition | ||
| 378 | ;; then the region will expand beyond the method and into the | ||
| 379 | ;; class definition itself. | ||
| 380 | ;; | ||
| 381 | ;; Changing the default to mark-defun provides behavior that users | ||
| 382 | ;; are more likely to expect. | ||
| 383 | (define-key map (kbd "C-M-h") 'mark-defun) | ||
| 384 | |||
| 385 | ;; Many packages based on cc-mode provide the 'C-c C-w' binding | ||
| 386 | ;; to toggle Subword Mode. See the page | ||
| 387 | ;; | ||
| 388 | ;; https://www.gnu.org/software/emacs/manual/html_node/ccmode/Subword-Movement.html | ||
| 389 | ;; | ||
| 390 | ;; for more information about Submode Word. | ||
| 391 | (if (boundp 'subword-mode) | ||
| 392 | (if subword-mode | ||
| 393 | (subword-mode nil) | ||
| 394 | (subword-mode t))) | ||
| 395 | |||
| 396 | ;; We inherit c-beginning-of-defun and c-end-of-defun from CC Mode | ||
| 397 | ;; but we have two replacement functions specifically for PHP. We | ||
| 398 | ;; remap the commands themselves and not their default | ||
| 399 | ;; key-bindings so that our PHP-specific versions will work even | ||
| 400 | ;; if the user has reconfigured their keys, e.g. if they rebind | ||
| 401 | ;; c-end-of-defun to something other than C-M-e. | ||
| 402 | (define-key map [remap c-beginning-of-defun] 'php-beginning-of-defun) | ||
| 403 | (define-key map [remap c-end-of-defun] 'php-end-of-defun) | ||
| 404 | |||
| 405 | (define-key map [(control c) (control f)] 'php-search-documentation) | ||
| 406 | (define-key map [(meta tab)] 'php-complete-function) | ||
| 407 | (define-key map [(control c) (control m)] 'php-browse-manual) | ||
| 408 | (define-key map [(control .)] 'php-show-arglist) | ||
| 409 | (define-key map [(control c) (control r)] 'php-send-region) | ||
| 410 | ;; Use the Emacs standard indentation binding. This may upset c-mode | ||
| 411 | ;; which does not follow this at the moment, but I see no better | ||
| 412 | ;; choice. | ||
| 413 | (define-key map [tab] 'indent-for-tab-command) | ||
| 414 | map) | ||
| 415 | "Keymap for `php-mode'") | ||
| 416 | |||
| 417 | (c-lang-defconst c-mode-menu | ||
| 418 | php (append '(["Complete function name" php-complete-function t] | ||
| 419 | ["Browse manual" php-browse-manual t] | ||
| 420 | ["Search documentation" php-search-documentation t] | ||
| 421 | ["----" t]) | ||
| 422 | (c-lang-const c-mode-menu))) | ||
| 423 | |||
| 424 | (c-lang-defconst c-at-vsemi-p-fn | ||
| 425 | php 'php-c-at-vsemi-p) | ||
| 426 | |||
| 427 | (c-lang-defconst c-vsemi-status-unknown-p-fn | ||
| 428 | php 'php-c-vsemi-status-unknown-p) | ||
| 429 | |||
| 430 | ;; Make php-mode recognize opening tags as preprocessor macro's. | ||
| 431 | ;; | ||
| 432 | ;; This is a workaround, the tags must be recognized as something | ||
| 433 | ;; in order for the syntactic guesses of code below the tag | ||
| 434 | ;; to be correct and as a result not break indentation. | ||
| 435 | ;; | ||
| 436 | ;; Note that submatches or \\| here are not expected by cc-mode. | ||
| 437 | (c-lang-defconst c-opt-cpp-prefix | ||
| 438 | php "\\s-*<\\?") | ||
| 439 | |||
| 440 | (c-lang-defconst c-identifier-ops | ||
| 441 | php '( | ||
| 442 | (left-assoc "\\" "::" "->") | ||
| 443 | (prefix "\\" "::"))) | ||
| 444 | |||
| 445 | ;; Allow '\' when scanning from open brace back to defining | ||
| 446 | ;; construct like class | ||
| 447 | (c-lang-defconst c-block-prefix-disallowed-chars | ||
| 448 | php (cl-set-difference (c-lang-const c-block-prefix-disallowed-chars) | ||
| 449 | '(?\\))) | ||
| 450 | |||
| 451 | ;; Allow $ so variables are recognized in cc-mode and remove @. This | ||
| 452 | ;; makes cc-mode highlight variables and their type hints in arglists. | ||
| 453 | (c-lang-defconst c-symbol-start | ||
| 454 | php (concat "[" c-alpha "_$]")) | ||
| 455 | |||
| 456 | ;; All string literals can possibly span multiple lines | ||
| 457 | (c-lang-defconst c-multiline-string-start-char | ||
| 458 | php t) | ||
| 459 | |||
| 460 | (c-lang-defconst c-assignment-operators | ||
| 461 | ;; falls back to java, so no need to specify the language | ||
| 462 | php (append (remove ">>>=" (c-lang-const c-assignment-operators)) | ||
| 463 | '(".="))) | ||
| 464 | |||
| 465 | (c-lang-defconst beginning-of-defun-function | ||
| 466 | php 'php-beginning-of-defun) | ||
| 467 | |||
| 468 | (c-lang-defconst end-of-defun-function | ||
| 469 | php 'php-end-of-defun) | ||
| 470 | |||
| 471 | (c-lang-defconst c-primitive-type-kwds | ||
| 472 | php '("int" "integer" "bool" "boolean" "float" "double" "real" | ||
| 473 | "string" "object")) | ||
| 474 | |||
| 475 | (c-lang-defconst c-class-decl-kwds | ||
| 476 | "Keywords introducing declarations where the following block (if any) | ||
| 477 | contains another declaration level that should be considered a class." | ||
| 478 | php '("class" "trait" "interface")) | ||
| 479 | |||
| 480 | (c-lang-defconst c-brace-list-decl-kwds | ||
| 481 | "Keywords introducing declarations where the following block (if | ||
| 482 | any) is a brace list. | ||
| 483 | |||
| 484 | PHP does not have an \"enum\"-like keyword." | ||
| 485 | php nil) | ||
| 486 | |||
| 487 | (c-lang-defconst c-typeless-decl-kwds | ||
| 488 | php (append (c-lang-const c-class-decl-kwds) '("function"))) | ||
| 489 | |||
| 490 | (c-lang-defconst c-modifier-kwds | ||
| 491 | php '("abstract" "const" "final" "native" "static" "strictfp" | ||
| 492 | "synchronized" "transient" "volatile")) | ||
| 493 | |||
| 494 | (c-lang-defconst c-protection-kwds | ||
| 495 | "Access protection label keywords in classes." | ||
| 496 | php '("private" "protected" "public")) | ||
| 497 | |||
| 498 | (c-lang-defconst c-postfix-decl-spec-kwds | ||
| 499 | php '("implements" "extends")) | ||
| 500 | |||
| 501 | (c-lang-defconst c-type-list-kwds | ||
| 502 | php '("new" "use" "implements" "extends" "namespace" "instanceof" "insteadof")) | ||
| 503 | |||
| 504 | (c-lang-defconst c-ref-list-kwds | ||
| 505 | php nil) | ||
| 506 | |||
| 507 | (c-lang-defconst c-block-stmt-2-kwds | ||
| 508 | php (append '("elseif" "foreach" "declare") | ||
| 509 | (remove "synchronized" (c-lang-const c-block-stmt-2-kwds)))) | ||
| 510 | |||
| 511 | (c-lang-defconst c-simple-stmt-kwds | ||
| 512 | php (append '("include" "include_once" "require" "require_once" | ||
| 513 | "echo" "print" "die" "exit") | ||
| 514 | (c-lang-const c-simple-stmt-kwds))) | ||
| 515 | |||
| 516 | (c-lang-defconst c-constant-kwds | ||
| 517 | php '("true" | ||
| 518 | "false" | ||
| 519 | "null")) | ||
| 520 | |||
| 521 | (c-lang-defconst c-lambda-kwds | ||
| 522 | php '("function")) | ||
| 523 | |||
| 524 | (c-lang-defconst c-other-kwds | ||
| 525 | "Keywords not accounted for by any other `*-kwds' language constant." | ||
| 526 | php '( | ||
| 527 | "__halt_compiler" | ||
| 528 | "and" | ||
| 529 | "array" | ||
| 530 | "callable" | ||
| 531 | "as" | ||
| 532 | "break" | ||
| 533 | "catch all" | ||
| 534 | "catch" | ||
| 535 | "clone" | ||
| 536 | "default" | ||
| 537 | "empty" | ||
| 538 | "enddeclare" | ||
| 539 | "endfor" | ||
| 540 | "endforeach" | ||
| 541 | "endif" | ||
| 542 | "endswitch" | ||
| 543 | "endwhile" | ||
| 544 | "eval" | ||
| 545 | "global" | ||
| 546 | "isset" | ||
| 547 | "list" | ||
| 548 | "or" | ||
| 549 | "parent" | ||
| 550 | "static" | ||
| 551 | "unset" | ||
| 552 | "var" | ||
| 553 | "xor" | ||
| 554 | "yield" | ||
| 555 | |||
| 556 | ;; Below keywords are technically not reserved keywords, but | ||
| 557 | ;; threated no differently by php-mode from actual reserved | ||
| 558 | ;; keywords | ||
| 559 | ;; | ||
| 560 | ;;; declare directives: | ||
| 561 | "encoding" | ||
| 562 | "ticks" | ||
| 563 | |||
| 564 | ;;; self for static references: | ||
| 565 | "self" | ||
| 566 | )) | ||
| 567 | |||
| 568 | ;; PHP does not have <> templates/generics | ||
| 569 | (c-lang-defconst c-recognize-<>-arglists | ||
| 570 | php nil) | ||
| 571 | |||
| 572 | (c-lang-defconst c-enums-contain-decls | ||
| 573 | php nil) | ||
| 574 | |||
| 575 | (c-lang-defconst c-nonlabel-token-key | ||
| 576 | "Regexp matching things that can't occur in generic colon labels. | ||
| 577 | |||
| 578 | This overrides cc-mode `c-nonlabel-token-key' to support switching on | ||
| 579 | double quoted strings and true/false/null. | ||
| 580 | |||
| 581 | Note: this regexp is also applied to goto-labels, a future improvement | ||
| 582 | might be to handle switch and goto labels differently." | ||
| 583 | php (concat | ||
| 584 | ;; All keywords except `c-label-kwds' and `c-constant-kwds'. | ||
| 585 | (c-make-keywords-re t | ||
| 586 | (cl-set-difference (c-lang-const c-keywords) | ||
| 587 | (append (c-lang-const c-label-kwds) | ||
| 588 | (c-lang-const c-constant-kwds)) | ||
| 589 | :test 'string-equal)))) | ||
| 590 | |||
| 591 | (defun php-lineup-cascaded-calls (langelem) | ||
| 592 | "Line up chained methods using `c-lineup-cascaded-calls', | ||
| 593 | but only if the setting is enabled" | ||
| 594 | (if php-lineup-cascaded-calls | ||
| 595 | (c-lineup-cascaded-calls langelem))) | ||
| 596 | |||
| 597 | (c-add-style | ||
| 598 | "php" | ||
| 599 | '((c-basic-offset . 4) | ||
| 600 | (c-doc-comment-style . javadoc) | ||
| 601 | (c-offsets-alist . ((arglist-close . php-lineup-arglist-close) | ||
| 602 | (arglist-cont . (first php-lineup-cascaded-calls 0)) | ||
| 603 | (arglist-cont-nonempty . (first php-lineup-cascaded-calls c-lineup-arglist)) | ||
| 604 | (arglist-intro . php-lineup-arglist-intro) | ||
| 605 | (case-label . +) | ||
| 606 | (class-open . -) | ||
| 607 | (comment-intro . 0) | ||
| 608 | (inlambda . 0) | ||
| 609 | (inline-open . 0) | ||
| 610 | (label . +) | ||
| 611 | (statement-cont . (first php-lineup-cascaded-calls php-lineup-string-cont +)) | ||
| 612 | (substatement-open . 0) | ||
| 613 | (topmost-intro-cont . (first php-lineup-cascaded-calls +)))))) | ||
| 614 | |||
| 615 | (defun php-enable-default-coding-style () | ||
| 616 | "Set PHP Mode to use reasonable default formatting." | ||
| 617 | (interactive) | ||
| 618 | (c-set-style "php")) | ||
| 619 | |||
| 620 | (c-add-style | ||
| 621 | "pear" | ||
| 622 | '("php" | ||
| 623 | (c-basic-offset . 4) | ||
| 624 | (c-offsets-alist . ((case-label . 0))))) | ||
| 625 | |||
| 626 | (defun php-enable-pear-coding-style () | ||
| 627 | "Sets up php-mode to use the coding styles preferred for PEAR | ||
| 628 | code and modules." | ||
| 629 | (interactive) | ||
| 630 | (setq tab-width 4 | ||
| 631 | indent-tabs-mode nil) | ||
| 632 | (c-set-style "pear") | ||
| 633 | |||
| 634 | ;; Undo drupal/PSR-2 coding style whitespace effects | ||
| 635 | (set (make-local-variable 'show-trailing-whitespace) | ||
| 636 | (default-value 'show-trailing-whitespace))) | ||
| 637 | |||
| 638 | (c-add-style | ||
| 639 | "drupal" | ||
| 640 | '("php" | ||
| 641 | (c-basic-offset . 2))) | ||
| 642 | |||
| 643 | (defun php-enable-drupal-coding-style () | ||
| 644 | "Makes php-mode use coding styles that are preferable for | ||
| 645 | working with Drupal." | ||
| 646 | (interactive) | ||
| 647 | (setq tab-width 2 | ||
| 648 | indent-tabs-mode nil | ||
| 649 | fill-column 78) | ||
| 650 | (set (make-local-variable 'show-trailing-whitespace) t) | ||
| 651 | (add-hook 'before-save-hook 'delete-trailing-whitespace nil t) | ||
| 652 | (c-set-style "drupal")) | ||
| 653 | |||
| 654 | (c-add-style | ||
| 655 | "wordpress" | ||
| 656 | '("php" | ||
| 657 | (c-basic-offset . 4))) | ||
| 658 | |||
| 659 | (defun php-enable-wordpress-coding-style () | ||
| 660 | "Makes php-mode use coding styles that are preferable for | ||
| 661 | working with Wordpress." | ||
| 662 | (interactive) | ||
| 663 | (setq indent-tabs-mode t | ||
| 664 | fill-column 78 | ||
| 665 | tab-width 4 | ||
| 666 | c-indent-comments-syntactically-p t) | ||
| 667 | (c-set-style "wordpress") | ||
| 668 | |||
| 669 | ;; Undo drupal/PSR-2 coding style whitespace effects | ||
| 670 | (set (make-local-variable 'show-trailing-whitespace) | ||
| 671 | (default-value 'show-trailing-whitespace))) | ||
| 672 | |||
| 673 | (c-add-style | ||
| 674 | "symfony2" | ||
| 675 | '("php" | ||
| 676 | (c-offsets-alist . ((statement-cont . php-lineup-hanging-semicolon))))) | ||
| 677 | |||
| 678 | (defun php-enable-symfony2-coding-style () | ||
| 679 | "Makes php-mode use coding styles that are preferable for | ||
| 680 | working with Symfony2." | ||
| 681 | (interactive) | ||
| 682 | (setq indent-tabs-mode nil | ||
| 683 | fill-column 78 | ||
| 684 | c-indent-comments-syntactically-p t | ||
| 685 | require-final-newline t) | ||
| 686 | (c-set-style "symfony2") | ||
| 687 | |||
| 688 | ;; Undo drupal/PSR-2 coding style whitespace effects | ||
| 689 | (set (make-local-variable 'show-trailing-whitespace) | ||
| 690 | (default-value 'show-trailing-whitespace))) | ||
| 691 | |||
| 692 | (c-add-style | ||
| 693 | "psr2" | ||
| 694 | '("php")) | ||
| 695 | |||
| 696 | (defun php-enable-psr2-coding-style () | ||
| 697 | "Makes php-mode comply to the PSR-2 coding style" | ||
| 698 | (interactive) | ||
| 699 | (setq indent-tabs-mode nil | ||
| 700 | fill-column 78 | ||
| 701 | c-indent-comments-syntactically-p t | ||
| 702 | require-final-newline t) | ||
| 703 | (c-set-style "psr2") | ||
| 704 | |||
| 705 | ;; Apply drupal-like coding style whitespace effects | ||
| 706 | (set (make-local-variable 'require-final-newline) t) | ||
| 707 | (set (make-local-variable 'show-trailing-whitespace) t) | ||
| 708 | (add-hook 'before-save-hook 'delete-trailing-whitespace nil t)) | ||
| 709 | |||
| 710 | (defconst php-beginning-of-defun-regexp | ||
| 711 | "^\\s-*\\(?:\\(?:abstract\\|final\\|private\\|protected\\|public\\|static\\)\\s-+\\)*function\\s-+&?\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*(" | ||
| 712 | "Regular expression for a PHP function.") | ||
| 713 | |||
| 714 | (defun php-beginning-of-defun (&optional arg) | ||
| 715 | "Move to the beginning of the ARGth PHP function from point. | ||
| 716 | Implements PHP version of `beginning-of-defun-function'." | ||
| 717 | (interactive "p") | ||
| 718 | (let ((arg (or arg 1))) | ||
| 719 | (while (> arg 0) | ||
| 720 | (re-search-backward php-beginning-of-defun-regexp | ||
| 721 | nil 'noerror) | ||
| 722 | (setq arg (1- arg))) | ||
| 723 | (while (< arg 0) | ||
| 724 | (end-of-line 1) | ||
| 725 | (let ((opoint (point))) | ||
| 726 | (beginning-of-defun 1) | ||
| 727 | (forward-list 2) | ||
| 728 | (forward-line 1) | ||
| 729 | (if (eq opoint (point)) | ||
| 730 | (re-search-forward php-beginning-of-defun-regexp | ||
| 731 | nil 'noerror)) | ||
| 732 | (setq arg (1+ arg)))))) | ||
| 733 | |||
| 734 | (defun php-end-of-defun (&optional arg) | ||
| 735 | "Move the end of the ARGth PHP function from point. | ||
| 736 | Implements PHP befsion of `end-of-defun-function' | ||
| 737 | |||
| 738 | See `php-beginning-of-defun'." | ||
| 739 | (interactive "p") | ||
| 740 | (php-beginning-of-defun (- (or arg 1)))) | ||
| 741 | |||
| 742 | |||
| 743 | (defvar php-warned-bad-indent nil) | ||
| 744 | |||
| 745 | ;; Do it but tell it is not good if html tags in buffer. | ||
| 746 | (defun php-check-html-for-indentation () | ||
| 747 | (let ((html-tag-re "^\\s-*</?\\sw+.*?>") | ||
| 748 | (here (point))) | ||
| 749 | (goto-char (line-beginning-position)) | ||
| 750 | (if (or (when (boundp 'mumamo-multi-major-mode) mumamo-multi-major-mode) | ||
| 751 | ;; Fix-me: no idea how to check for mmm or multi-mode | ||
| 752 | (save-match-data | ||
| 753 | (not (or (re-search-forward html-tag-re (line-end-position) t) | ||
| 754 | (re-search-backward html-tag-re (line-beginning-position) t))))) | ||
| 755 | (progn | ||
| 756 | (goto-char here) | ||
| 757 | t) | ||
| 758 | (goto-char here) | ||
| 759 | (setq php-warned-bad-indent t) | ||
| 760 | (let* ((known-multi-libs '(("mumamo" mumamo (lambda () (nxhtml-mumamo))) | ||
| 761 | ("mmm-mode" mmm-mode (lambda () (mmm-mode 1))) | ||
| 762 | ("multi-mode" multi-mode (lambda () (multi-mode 1))) | ||
| 763 | ("web-mode" web-mode (lambda () (web-mode))))) | ||
| 764 | (known-names (mapcar (lambda (lib) (car lib)) known-multi-libs)) | ||
| 765 | (available-multi-libs (delq nil | ||
| 766 | (mapcar | ||
| 767 | (lambda (lib) | ||
| 768 | (when (locate-library (car lib)) lib)) | ||
| 769 | known-multi-libs))) | ||
| 770 | (available-names (mapcar (lambda (lib) (car lib)) available-multi-libs)) | ||
| 771 | (base-msg | ||
| 772 | (concat | ||
| 773 | "Indentation fails badly with mixed HTML/PHP in the HTML part in | ||
| 774 | plain `php-mode'. To get indentation to work you must use an | ||
| 775 | Emacs library that supports 'multiple major modes' in a buffer. | ||
| 776 | Parts of the buffer will then be in `php-mode' and parts in for | ||
| 777 | example `html-mode'. Known such libraries are:\n\t" | ||
| 778 | (mapconcat 'identity known-names ", ") | ||
| 779 | "\n" | ||
| 780 | (if available-multi-libs | ||
| 781 | (concat | ||
| 782 | "You have these available in your `load-path':\n\t" | ||
| 783 | (mapconcat 'identity available-names ", ") | ||
| 784 | "\n\n" | ||
| 785 | "Do you want to turn any of those on? ") | ||
| 786 | "You do not have any of those in your `load-path'."))) | ||
| 787 | (is-using-multi | ||
| 788 | (catch 'is-using | ||
| 789 | (dolist (lib available-multi-libs) | ||
| 790 | (when (and (boundp (cadr lib)) | ||
| 791 | (symbol-value (cadr lib))) | ||
| 792 | (throw 'is-using t)))))) | ||
| 793 | (unless is-using-multi | ||
| 794 | (if available-multi-libs | ||
| 795 | (if (not (y-or-n-p base-msg)) | ||
| 796 | (message "Did not do indentation, but you can try again now if you want") | ||
| 797 | (let* ((name | ||
| 798 | (if (= 1 (length available-multi-libs)) | ||
| 799 | (car available-names) | ||
| 800 | ;; Minibuffer window is more than one line, fix that first: | ||
| 801 | (message "") | ||
| 802 | (completing-read "Choose multiple major mode support library: " | ||
| 803 | available-names nil t | ||
| 804 | (car available-names) | ||
| 805 | '(available-names . 1) | ||
| 806 | ))) | ||
| 807 | (mode (when name | ||
| 808 | (caddr (assoc name available-multi-libs))))) | ||
| 809 | (when mode | ||
| 810 | ;; Minibuffer window is more than one line, fix that first: | ||
| 811 | (message "") | ||
| 812 | (load name) | ||
| 813 | (funcall mode)))) | ||
| 814 | (lwarn 'php-indent :warning base-msg))) | ||
| 815 | nil)))) | ||
| 816 | |||
| 817 | (defun php-cautious-indent-region (start end &optional quiet) | ||
| 818 | (if (or (not php-mode-warn-if-mumamo-off) | ||
| 819 | php-warned-bad-indent | ||
| 820 | (php-check-html-for-indentation)) | ||
| 821 | (funcall 'c-indent-region start end quiet))) | ||
| 822 | |||
| 823 | (defun php-cautious-indent-line () | ||
| 824 | (if (or (not php-mode-warn-if-mumamo-off) | ||
| 825 | php-warned-bad-indent | ||
| 826 | (php-check-html-for-indentation)) | ||
| 827 | (let ((here (point)) | ||
| 828 | doit) | ||
| 829 | (move-beginning-of-line nil) | ||
| 830 | ;; Don't indent heredoc end mark | ||
| 831 | (save-match-data | ||
| 832 | (unless (looking-at "[a-zA-Z0-9_]+;\n") | ||
| 833 | (setq doit t))) | ||
| 834 | (goto-char here) | ||
| 835 | (when doit | ||
| 836 | (funcall 'c-indent-line))))) | ||
| 837 | |||
| 838 | (defun php-c-at-vsemi-p (&optional pos) | ||
| 839 | "Return t on html lines (including php region border), otherwise nil. | ||
| 840 | POS is a position on the line in question. | ||
| 841 | |||
| 842 | This is was done due to the problem reported here: | ||
| 843 | |||
| 844 | URL `https://answers.launchpad.net/nxhtml/+question/43320'" | ||
| 845 | (if (not php-template-compatibility) | ||
| 846 | nil | ||
| 847 | (setq pos (or pos (point))) | ||
| 848 | (let ((here (point)) | ||
| 849 | ret) | ||
| 850 | (save-match-data | ||
| 851 | (goto-char pos) | ||
| 852 | (beginning-of-line) | ||
| 853 | (setq ret (looking-at | ||
| 854 | (rx | ||
| 855 | (or (seq | ||
| 856 | bol | ||
| 857 | (0+ space) | ||
| 858 | "<" | ||
| 859 | (in "a-z\\?")) | ||
| 860 | (seq | ||
| 861 | (0+ not-newline) | ||
| 862 | (in "a-z\\?") | ||
| 863 | ">" | ||
| 864 | (0+ space) | ||
| 865 | eol)))))) | ||
| 866 | (goto-char here) | ||
| 867 | ret))) | ||
| 868 | |||
| 869 | (defun php-c-vsemi-status-unknown-p () | ||
| 870 | "See `php-c-at-vsemi-p'." | ||
| 871 | ) | ||
| 872 | |||
| 873 | (defun php-lineup-string-cont (langelem) | ||
| 874 | "Line up string toward equal sign or dot | ||
| 875 | e.g. | ||
| 876 | $str = 'some' | ||
| 877 | . 'string'; | ||
| 878 | this ^ lineup" | ||
| 879 | (save-excursion | ||
| 880 | (goto-char (cdr langelem)) | ||
| 881 | (when (or (search-forward "=" (line-end-position) t) | ||
| 882 | (search-forward "." (line-end-position) t)) | ||
| 883 | (vector (1- (current-column)))))) | ||
| 884 | |||
| 885 | (defun php-lineup-arglist-intro (langelem) | ||
| 886 | (save-excursion | ||
| 887 | (goto-char (cdr langelem)) | ||
| 888 | (vector (+ (current-column) c-basic-offset)))) | ||
| 889 | |||
| 890 | (defun php-lineup-arglist-close (langelem) | ||
| 891 | (save-excursion | ||
| 892 | (goto-char (cdr langelem)) | ||
| 893 | (vector (current-column)))) | ||
| 894 | |||
| 895 | (defun php-lineup-arglist (langelem) | ||
| 896 | (save-excursion | ||
| 897 | (beginning-of-line) | ||
| 898 | (if (looking-at-p "\\s-*->") '+ 0))) | ||
| 899 | |||
| 900 | (defun php-lineup-hanging-semicolon (langelem) | ||
| 901 | (save-excursion | ||
| 902 | (beginning-of-line) | ||
| 903 | (if (looking-at-p "\\s-*;\\s-*$") 0 '+))) | ||
| 904 | |||
| 905 | (defconst php-heredoc-start-re | ||
| 906 | "<<<\\(?:\\w+\\|'\\w+'\\)$" | ||
| 907 | "Regular expression for the start of a PHP heredoc.") | ||
| 908 | |||
| 909 | (defun php-heredoc-end-re (heredoc-start) | ||
| 910 | "Build a regular expression for the end of a heredoc started by | ||
| 911 | the string HEREDOC-START." | ||
| 912 | ;; Extract just the identifier without <<< and quotes. | ||
| 913 | (string-match "\\w+" heredoc-start) | ||
| 914 | (concat "^\\(" (match-string 0 heredoc-start) "\\)\\W")) | ||
| 915 | |||
| 916 | (defsubst php-in-string-p () | ||
| 917 | (nth 3 (syntax-ppss))) | ||
| 918 | |||
| 919 | (defsubst php-in-comment-p () | ||
| 920 | (nth 4 (syntax-ppss))) | ||
| 921 | |||
| 922 | (defun php-syntax-propertize-function (start end) | ||
| 923 | "Apply propertize rules from START to END." | ||
| 924 | ;; (defconst php-syntax-propertize-function | ||
| 925 | ;; (syntax-propertize-rules | ||
| 926 | ;; (php-heredoc-start-re (0 (ignore (php-heredoc-syntax)))))) | ||
| 927 | (goto-char start) | ||
| 928 | (while (and (< (point) end) | ||
| 929 | (re-search-forward php-heredoc-start-re end t)) | ||
| 930 | (php-heredoc-syntax)) | ||
| 931 | (goto-char start) | ||
| 932 | (while (re-search-forward "['\"]" end t) | ||
| 933 | (when (php-in-comment-p) | ||
| 934 | (c-put-char-property (match-beginning 0) | ||
| 935 | 'syntax-table (string-to-syntax "_"))))) | ||
| 936 | |||
| 937 | (defun php-heredoc-syntax () | ||
| 938 | "Mark the boundaries of searched heredoc." | ||
| 939 | (goto-char (match-beginning 0)) | ||
| 940 | (c-put-char-property (point) 'syntax-table (string-to-syntax "|")) | ||
| 941 | (if (re-search-forward (php-heredoc-end-re (match-string 0)) nil t) | ||
| 942 | (goto-char (match-end 1)) | ||
| 943 | ;; Did not find the delimiter so go to the end of the buffer. | ||
| 944 | (goto-char (point-max))) | ||
| 945 | (c-put-char-property (1- (point)) 'syntax-table (string-to-syntax "|"))) | ||
| 946 | |||
| 947 | (defun php-syntax-propertize-extend-region (start end) | ||
| 948 | "Extend the propertize region if START or END falls inside a | ||
| 949 | PHP heredoc." | ||
| 950 | (let ((new-start) | ||
| 951 | (new-end)) | ||
| 952 | (goto-char start) | ||
| 953 | (when (re-search-backward php-heredoc-start-re nil t) | ||
| 954 | (let ((maybe (point))) | ||
| 955 | (when (and (re-search-forward | ||
| 956 | (php-heredoc-end-re (match-string 0)) nil t) | ||
| 957 | (> (point) start)) | ||
| 958 | (setq new-start maybe)))) | ||
| 959 | (goto-char end) | ||
| 960 | (when (re-search-backward php-heredoc-start-re nil t) | ||
| 961 | (if (re-search-forward | ||
| 962 | (php-heredoc-end-re (match-string 0)) nil t) | ||
| 963 | (when (> (point) end) | ||
| 964 | (setq new-end (point))) | ||
| 965 | (setq new-end (point-max)))) | ||
| 966 | (when (or new-start new-end) | ||
| 967 | (cons (or new-start start) (or new-end end))))) | ||
| 968 | |||
| 969 | (easy-menu-define php-mode-menu php-mode-map "PHP Mode Commands" | ||
| 970 | (cons "PHP" (c-lang-const c-mode-menu php))) | ||
| 971 | |||
| 972 | ;;;###autoload | ||
| 973 | (define-derived-mode php-mode c-mode "PHP" | ||
| 974 | "Major mode for editing PHP code. | ||
| 975 | |||
| 976 | \\{php-mode-map}" | ||
| 977 | |||
| 978 | (c-initialize-cc-mode t) | ||
| 979 | (c-init-language-vars php-mode) | ||
| 980 | (c-common-init 'php-mode) | ||
| 981 | |||
| 982 | (modify-syntax-entry ?_ "_" php-mode-syntax-table) | ||
| 983 | (modify-syntax-entry ?` "\"" php-mode-syntax-table) | ||
| 984 | (modify-syntax-entry ?\" "\"" php-mode-syntax-table) | ||
| 985 | (modify-syntax-entry ?# "< b" php-mode-syntax-table) | ||
| 986 | (modify-syntax-entry ?\n "> b" php-mode-syntax-table) | ||
| 987 | |||
| 988 | (set (make-local-variable 'syntax-propertize-via-font-lock) | ||
| 989 | '(("\\(\"\\)\\(\\\\.\\|[^\"\n\\]\\)*\\(\"\\)" (1 "\"") (3 "\"")) | ||
| 990 | ("\\(\'\\)\\(\\\\.\\|[^\'\n\\]\\)*\\(\'\\)" (1 "\"") (3 "\"")))) | ||
| 991 | |||
| 992 | (when (boundp 'syntax-propertize-function) | ||
| 993 | (add-to-list (make-local-variable 'syntax-propertize-extend-region-functions) | ||
| 994 | #'php-syntax-propertize-extend-region) | ||
| 995 | (set (make-local-variable 'syntax-propertize-function) | ||
| 996 | #'php-syntax-propertize-function)) | ||
| 997 | |||
| 998 | (setq font-lock-maximum-decoration t | ||
| 999 | imenu-generic-expression php-imenu-generic-expression) | ||
| 1000 | |||
| 1001 | ;; PHP vars are case-sensitive | ||
| 1002 | (setq case-fold-search t) | ||
| 1003 | |||
| 1004 | ;; Do not force newline at end of file. Such newlines can cause | ||
| 1005 | ;; trouble if the PHP file is included in another file before calls | ||
| 1006 | ;; to header() or cookie(). | ||
| 1007 | (set (make-local-variable 'require-final-newline) nil) | ||
| 1008 | (set (make-local-variable 'next-line-add-newlines) nil) | ||
| 1009 | |||
| 1010 | ;; PEAR coding standards | ||
| 1011 | (add-hook 'php-mode-pear-hook 'php-enable-pear-coding-style | ||
| 1012 | nil t) | ||
| 1013 | |||
| 1014 | ;; ;; Drupal coding standards | ||
| 1015 | (add-hook 'php-mode-drupal-hook 'php-enable-drupal-coding-style | ||
| 1016 | nil t) | ||
| 1017 | |||
| 1018 | ;; ;; WordPress coding standards | ||
| 1019 | (add-hook 'php-mode-wordpress-hook 'php-enable-wordpress-coding-style | ||
| 1020 | nil t) | ||
| 1021 | |||
| 1022 | ;; ;; Symfony2 coding standards | ||
| 1023 | (add-hook 'php-mode-symfony2-hook 'php-enable-symfony2-coding-style | ||
| 1024 | nil t) | ||
| 1025 | |||
| 1026 | ;; ;; PSR-2 coding standards | ||
| 1027 | (add-hook 'php-mode-psr2-hook 'php-enable-psr2-coding-style | ||
| 1028 | nil t) | ||
| 1029 | |||
| 1030 | (cond ((eq php-mode-coding-style 'pear) | ||
| 1031 | (php-enable-pear-coding-style) | ||
| 1032 | (run-hooks 'php-mode-pear-hook)) | ||
| 1033 | ((eq php-mode-coding-style 'drupal) | ||
| 1034 | (php-enable-drupal-coding-style) | ||
| 1035 | (run-hooks 'php-mode-drupal-hook)) | ||
| 1036 | ((eq php-mode-coding-style 'wordpress) | ||
| 1037 | (php-enable-wordpress-coding-style) | ||
| 1038 | (run-hooks 'php-mode-wordpress-hook)) | ||
| 1039 | ((eq php-mode-coding-style 'symfony2) | ||
| 1040 | (php-enable-symfony2-coding-style) | ||
| 1041 | (run-hooks 'php-mode-symfony2-hook)) | ||
| 1042 | ((eq php-mode-coding-style 'psr2) | ||
| 1043 | (php-enable-psr2-coding-style) | ||
| 1044 | (run-hooks 'php-mode-psr2-hook))) | ||
| 1045 | |||
| 1046 | (if (or php-mode-force-pear | ||
| 1047 | (and (stringp buffer-file-name) | ||
| 1048 | (string-match "PEAR\\|pear" | ||
| 1049 | (buffer-file-name)) | ||
| 1050 | (string-match "\\.php$" (buffer-file-name)))) | ||
| 1051 | (run-hooks 'php-mode-pear-hook)) | ||
| 1052 | |||
| 1053 | (setq indent-line-function 'php-cautious-indent-line) | ||
| 1054 | (setq indent-region-function 'php-cautious-indent-region) | ||
| 1055 | (setq c-at-vsemi-p-fn 'php-c-at-vsemi-p) | ||
| 1056 | (setq c-vsemi-status-unknown-p 'php-c-vsemi-status-unknown-p) | ||
| 1057 | |||
| 1058 | (set (make-local-variable 'syntax-begin-function) | ||
| 1059 | 'c-beginning-of-syntax) | ||
| 1060 | |||
| 1061 | ;; We map the php-{beginning,end}-of-defun functions so that they | ||
| 1062 | ;; replace the similar commands that we inherit from CC Mode. | ||
| 1063 | ;; Because of our remapping we may not actually need to keep the | ||
| 1064 | ;; following two local variables, but we keep them for now until we | ||
| 1065 | ;; are completely sure their removal will not break any current | ||
| 1066 | ;; behavior or backwards compatibility. | ||
| 1067 | (set (make-local-variable 'beginning-of-defun-function) | ||
| 1068 | 'php-beginning-of-defun) | ||
| 1069 | (set (make-local-variable 'end-of-defun-function) | ||
| 1070 | 'php-end-of-defun) | ||
| 1071 | |||
| 1072 | (set (make-local-variable 'open-paren-in-column-0-is-defun-start) | ||
| 1073 | nil) | ||
| 1074 | (set (make-local-variable 'defun-prompt-regexp) | ||
| 1075 | "^\\s-*function\\s-+&?\\s-*\\(\\(\\sw\\|\\s_\\)+\\)\\s-*") | ||
| 1076 | (set (make-local-variable 'add-log-current-defun-header-regexp) | ||
| 1077 | php-beginning-of-defun-regexp)) | ||
| 1078 | |||
| 1079 | ;; Define function name completion function | ||
| 1080 | (defvar php-completion-table nil | ||
| 1081 | "Obarray of tag names defined in current tags table and functions known to PHP.") | ||
| 1082 | |||
| 1083 | (defun php-complete-function () | ||
| 1084 | "Perform function completion on the text around point. | ||
| 1085 | Completes to the set of names listed in the current tags table | ||
| 1086 | and the standard php functions. | ||
| 1087 | The string to complete is chosen in the same way as the default | ||
| 1088 | for \\[find-tag] (which see)." | ||
| 1089 | (interactive) | ||
| 1090 | (let ((pattern (php-get-pattern)) | ||
| 1091 | beg | ||
| 1092 | completion | ||
| 1093 | (php-functions (php-completion-table))) | ||
| 1094 | (if (not pattern) (message "Nothing to complete") | ||
| 1095 | (if (not (search-backward pattern nil t)) | ||
| 1096 | (message "Can't complete here") | ||
| 1097 | (setq beg (point)) | ||
| 1098 | (forward-char (length pattern)) | ||
| 1099 | (setq completion (try-completion pattern php-functions nil)) | ||
| 1100 | (cond ((eq completion t)) | ||
| 1101 | ((null completion) | ||
| 1102 | (message "Can't find completion for \"%s\"" pattern) | ||
| 1103 | (ding)) | ||
| 1104 | ((not (string= pattern completion)) | ||
| 1105 | (delete-region beg (point)) | ||
| 1106 | (insert completion)) | ||
| 1107 | (t | ||
| 1108 | (message "Making completion list...") | ||
| 1109 | (with-output-to-temp-buffer "*Completions*" | ||
| 1110 | (display-completion-list | ||
| 1111 | (all-completions pattern php-functions))) | ||
| 1112 | (message "Making completion list...%s" "done"))))))) | ||
| 1113 | |||
| 1114 | (defun php-completion-table () | ||
| 1115 | "Build variable `php-completion-table' on demand. | ||
| 1116 | The table includes the PHP functions and the tags from the | ||
| 1117 | current `tags-file-name'." | ||
| 1118 | (or (and tags-file-name | ||
| 1119 | (save-excursion (tags-verify-table tags-file-name)) | ||
| 1120 | php-completion-table) | ||
| 1121 | (let ((tags-table | ||
| 1122 | (when tags-file-name | ||
| 1123 | (with-current-buffer (get-file-buffer tags-file-name) | ||
| 1124 | (etags-tags-completion-table)))) | ||
| 1125 | (php-table | ||
| 1126 | (cond ((and (not (string= "" php-completion-file)) | ||
| 1127 | (file-readable-p php-completion-file)) | ||
| 1128 | (php-build-table-from-file php-completion-file)) | ||
| 1129 | (php-manual-path | ||
| 1130 | (php-build-table-from-path php-manual-path)) | ||
| 1131 | (t nil)))) | ||
| 1132 | (unless (or php-table tags-table) | ||
| 1133 | (error | ||
| 1134 | (concat "No TAGS file active nor are " | ||
| 1135 | "`php-completion-file' or `php-manual-path' set"))) | ||
| 1136 | (when tags-table | ||
| 1137 | ;; Combine the tables. | ||
| 1138 | (mapatoms (lambda (sym) (intern (symbol-name sym) php-table)) | ||
| 1139 | tags-table)) | ||
| 1140 | (setq php-completion-table php-table)))) | ||
| 1141 | |||
| 1142 | (defun php-build-table-from-file (filename) | ||
| 1143 | (let ((table (make-vector 1022 0)) | ||
| 1144 | (buf (find-file-noselect filename))) | ||
| 1145 | (with-current-buffer buf | ||
| 1146 | (goto-char (point-min)) | ||
| 1147 | (while (re-search-forward | ||
| 1148 | "^\\([-a-zA-Z0-9_.]+\\)\n" | ||
| 1149 | nil t) | ||
| 1150 | (intern (buffer-substring (match-beginning 1) (match-end 1)) | ||
| 1151 | table))) | ||
| 1152 | (kill-buffer buf) | ||
| 1153 | table)) | ||
| 1154 | |||
| 1155 | (defun php-build-table-from-path (path) | ||
| 1156 | (let ((table (make-vector 1022 0)) | ||
| 1157 | (files (directory-files | ||
| 1158 | path | ||
| 1159 | nil | ||
| 1160 | "^function\\..+\\.html$"))) | ||
| 1161 | (mapc (lambda (file) | ||
| 1162 | (string-match "\\.\\([-a-zA-Z_0-9]+\\)\\.html$" file) | ||
| 1163 | (intern | ||
| 1164 | (replace-regexp-in-string | ||
| 1165 | "-" "_" (substring file (match-beginning 1) (match-end 1)) t) | ||
| 1166 | table)) | ||
| 1167 | files) | ||
| 1168 | table)) | ||
| 1169 | |||
| 1170 | ;; Find the pattern we want to complete | ||
| 1171 | ;; find-tag-default from GNU Emacs etags.el | ||
| 1172 | (defun php-get-pattern () | ||
| 1173 | (save-excursion | ||
| 1174 | (while (looking-at "\\sw\\|\\s_") | ||
| 1175 | (forward-char 1)) | ||
| 1176 | (if (or (re-search-backward "\\sw\\|\\s_" | ||
| 1177 | (save-excursion (beginning-of-line) (point)) | ||
| 1178 | t) | ||
| 1179 | (re-search-forward "\\(\\sw\\|\\s_\\)+" | ||
| 1180 | (save-excursion (end-of-line) (point)) | ||
| 1181 | t)) | ||
| 1182 | (progn (goto-char (match-end 0)) | ||
| 1183 | (buffer-substring-no-properties | ||
| 1184 | (point) | ||
| 1185 | (progn (forward-sexp -1) | ||
| 1186 | (while (looking-at "\\s'") | ||
| 1187 | (forward-char 1)) | ||
| 1188 | (point)))) | ||
| 1189 | nil))) | ||
| 1190 | |||
| 1191 | (defun php-show-arglist () | ||
| 1192 | (interactive) | ||
| 1193 | (let* ((tagname (php-get-pattern)) | ||
| 1194 | (buf (find-tag-noselect tagname nil nil)) | ||
| 1195 | arglist) | ||
| 1196 | (with-current-buffer buf | ||
| 1197 | (goto-char (point-min)) | ||
| 1198 | (when (re-search-forward | ||
| 1199 | (format "function\\s-+%s\\s-*(\\([^{]*\\))" tagname) | ||
| 1200 | nil t) | ||
| 1201 | (setq arglist (buffer-substring-no-properties | ||
| 1202 | (match-beginning 1) (match-end 1))))) | ||
| 1203 | (if arglist | ||
| 1204 | (message "Arglist for %s: %s" tagname arglist) | ||
| 1205 | (message "Unknown function: %s" tagname)))) | ||
| 1206 | |||
| 1207 | (defcustom php-search-documentation-browser-function nil | ||
| 1208 | "Function to display PHP documentation in a WWW browser. | ||
| 1209 | |||
| 1210 | If non-nil, this shadows the value of `browse-url-browser-function' when | ||
| 1211 | calling `php-search-documentation' or `php-search-local-documentation'." | ||
| 1212 | :type '(choice (const :tag "default" nil) function) | ||
| 1213 | :link '(variable-link browse-url-browser-function) | ||
| 1214 | :group 'php) | ||
| 1215 | |||
| 1216 | (defun php-browse-documentation-url (url) | ||
| 1217 | "Browse a documentation URL using the configured browser function. | ||
| 1218 | |||
| 1219 | See `php-search-documentation-browser-function'." | ||
| 1220 | (let ((browse-url-browser-function | ||
| 1221 | (or php-search-documentation-browser-function | ||
| 1222 | browse-url-browser-function))) | ||
| 1223 | (browse-url url))) | ||
| 1224 | |||
| 1225 | (defvar php-search-local-documentation-types | ||
| 1226 | (list "function" "control-structures" "class" "book") | ||
| 1227 | ;; "intro" and "ref" also look interesting, but for all practical purposes | ||
| 1228 | ;; their terms are sub-sets of the "book" terms (with the few exceptions | ||
| 1229 | ;; being very unlikely search terms). | ||
| 1230 | "The set (and priority sequence) of documentation file prefixes | ||
| 1231 | under which to search for files in the local documentation directory.") | ||
| 1232 | |||
| 1233 | (defvar php-search-local-documentation-words-cache nil) | ||
| 1234 | |||
| 1235 | (defun php--search-documentation-read-arg () | ||
| 1236 | "Obtain interactive argument for searching documentation." | ||
| 1237 | ;; Cache the list of documentation words available for completion, | ||
| 1238 | ;; based on the defined types-of-interest. | ||
| 1239 | (let ((types-list php-search-local-documentation-types) | ||
| 1240 | (words-cache php-search-local-documentation-words-cache) | ||
| 1241 | (local-manual (and (stringp php-manual-path) | ||
| 1242 | (not (string= php-manual-path ""))))) | ||
| 1243 | (when (and local-manual | ||
| 1244 | (not (assq types-list words-cache))) | ||
| 1245 | ;; Generate the cache on the first run, or if the types changed. | ||
| 1246 | ;; We read the filenames matching our types list in the local | ||
| 1247 | ;; documention directory, and extract the 'middle' component | ||
| 1248 | ;; of each. e.g. "function.array-map.html" => "array_map". | ||
| 1249 | (let* ((types-opt (regexp-opt types-list)) | ||
| 1250 | (pattern (concat "\\`" types-opt "\\.\\(.+\\)\\.html\\'")) | ||
| 1251 | (collection | ||
| 1252 | (mapcar (lambda (filename) (subst-char-in-string | ||
| 1253 | ?- ?_ (replace-regexp-in-string | ||
| 1254 | pattern "\\1" filename))) | ||
| 1255 | (directory-files php-manual-path nil pattern)))) | ||
| 1256 | ;; Replace the entire cache. If the types changed, we don't need | ||
| 1257 | ;; to retain the collection for the previous value. | ||
| 1258 | (setq words-cache (list (cons types-list collection))) | ||
| 1259 | (setq php-search-local-documentation-words-cache words-cache))) | ||
| 1260 | ;; By default we search for (current-word) immediately, without prompting. | ||
| 1261 | ;; With a prefix argument, or if there is no (current-word), we perform a | ||
| 1262 | ;; completing read for a word from the cached collection. | ||
| 1263 | (let* ((default (current-word)) | ||
| 1264 | (prompt (if default | ||
| 1265 | (format "Search PHP docs (%s): " default) | ||
| 1266 | "Search PHP docs: ")) | ||
| 1267 | (collection (and local-manual | ||
| 1268 | (cdr (assq types-list words-cache)))) | ||
| 1269 | (word (if (or current-prefix-arg (not default)) | ||
| 1270 | (completing-read prompt collection nil nil nil nil default) | ||
| 1271 | default))) | ||
| 1272 | ;; Return interactive argument list. | ||
| 1273 | (list word)))) | ||
| 1274 | |||
| 1275 | (defun php-search-local-documentation (word) | ||
| 1276 | "Search the local PHP documentation (i.e. in `php-manual-path') for | ||
| 1277 | the word at point. The function returns t if the requested documentation | ||
| 1278 | exists, and nil otherwise. | ||
| 1279 | |||
| 1280 | With a prefix argument, prompt (with completion) for a word to search for." | ||
| 1281 | (interactive (php--search-documentation-read-arg)) | ||
| 1282 | (cl-flet ((php-file-for (type name) | ||
| 1283 | (expand-file-name | ||
| 1284 | (format "%s.%s.html" type | ||
| 1285 | (replace-regexp-in-string | ||
| 1286 | "_" "-" (downcase name))) | ||
| 1287 | php-manual-path)) | ||
| 1288 | (php-file-url (file) | ||
| 1289 | ;; Some browsers require the file:// prefix. | ||
| 1290 | ;; Others do not seem to care. But it should | ||
| 1291 | ;; never be incorrect to use the prefix. | ||
| 1292 | (if (string-prefix-p "file://" file) | ||
| 1293 | file | ||
| 1294 | (concat "file://" file)))) | ||
| 1295 | (let ((file (catch 'found | ||
| 1296 | (loop for type in php-search-local-documentation-types do | ||
| 1297 | (let ((file (php-file-for type word))) | ||
| 1298 | (when (file-exists-p file) | ||
| 1299 | (throw 'found file))))))) | ||
| 1300 | (when file | ||
| 1301 | (php-browse-documentation-url (php-file-url file)) | ||
| 1302 | t)))) | ||
| 1303 | |||
| 1304 | ;; Define function documentation function | ||
| 1305 | (defun php-search-documentation (word) | ||
| 1306 | "Search PHP documentation for the word at point. | ||
| 1307 | |||
| 1308 | If `php-manual-path' has a non-empty string value then the command | ||
| 1309 | will first try searching the local documentation. If the requested | ||
| 1310 | documentation does not exist it will fallback to searching the PHP | ||
| 1311 | website. | ||
| 1312 | |||
| 1313 | With a prefix argument, prompt for a documentation word to search | ||
| 1314 | for. If the local documentation is available, it is used to build | ||
| 1315 | a completion list." | ||
| 1316 | (interactive (php--search-documentation-read-arg)) | ||
| 1317 | (cl-flet ((php-search-web-documentation (name) | ||
| 1318 | (php-browse-documentation-url | ||
| 1319 | (concat php-search-url name)))) | ||
| 1320 | (if (and (stringp php-manual-path) | ||
| 1321 | (not (string= php-manual-path ""))) | ||
| 1322 | (or (php-search-local-documentation word) | ||
| 1323 | (php-search-web-documentation word)) | ||
| 1324 | (php-search-web-documentation word)))) | ||
| 1325 | |||
| 1326 | ;; Define function for browsing manual | ||
| 1327 | (defun php-browse-manual () | ||
| 1328 | "Bring up manual for PHP." | ||
| 1329 | (interactive) | ||
| 1330 | (browse-url php-manual-url)) | ||
| 1331 | |||
| 1332 | (defconst php-font-lock-keywords-1 (c-lang-const c-matchers-1 php) | ||
| 1333 | "Basic highlighting for PHP mode.") | ||
| 1334 | |||
| 1335 | (defconst php-font-lock-keywords-2 (c-lang-const c-matchers-2 php) | ||
| 1336 | "Medium level highlighting for PHP mode.") | ||
| 1337 | |||
| 1338 | (defconst php-font-lock-keywords-3 | ||
| 1339 | (append | ||
| 1340 | ;; php-mode patterns *before* cc-mode: | ||
| 1341 | ;; only add patterns here if you want to prevent cc-mode from applying | ||
| 1342 | ;; a different face. | ||
| 1343 | '( | ||
| 1344 | ;; Highlight variables, e.g. 'var' in '$var' and '$obj->var', but | ||
| 1345 | ;; not in $obj->var() | ||
| 1346 | ("->\\(\\sw+\\)\\s-*(" 1 'default) | ||
| 1347 | |||
| 1348 | ;; Highlight special variables | ||
| 1349 | ("\\$\\(this\\|that\\)" 1 font-lock-constant-face) | ||
| 1350 | ("\\(\\$\\|->\\)\\([a-zA-Z0-9_]+\\)" 2 font-lock-variable-name-face) | ||
| 1351 | |||
| 1352 | ;; Highlight function/method names | ||
| 1353 | ("\\<function\\s-+&?\\(\\sw+\\)\\s-*(" 1 font-lock-function-name-face) | ||
| 1354 | |||
| 1355 | ;; The dollar sign should not get a variable-name face, below | ||
| 1356 | ;; pattern resets the face to default in case cc-mode sets the | ||
| 1357 | ;; variable-name face (cc-mode does this for variables prefixed | ||
| 1358 | ;; with type, like in arglist) | ||
| 1359 | ("\\(\\$\\)\\(\\sw+\\)" 1 'default) | ||
| 1360 | |||
| 1361 | ;; Array is a keyword, except when used as cast, so that (int) | ||
| 1362 | ;; and (array) look the same | ||
| 1363 | ("(\\(array\\))" 1 font-lock-type-face) | ||
| 1364 | |||
| 1365 | ;; Support the ::class constant in PHP5.6 | ||
| 1366 | ("\\sw+::\\(class\\)" 1 font-lock-constant-face)) | ||
| 1367 | |||
| 1368 | ;; cc-mode patterns | ||
| 1369 | (c-lang-const c-matchers-3 php) | ||
| 1370 | |||
| 1371 | ;; php-mode patterns *after* cc-mode: | ||
| 1372 | ;; most patterns should go here, faces will only be applied if not | ||
| 1373 | ;; already fontified by another pattern. Note that using OVERRIDE | ||
| 1374 | ;; is usually overkill. | ||
| 1375 | `( | ||
| 1376 | ;; Highlight variables, e.g. 'var' in '$var' and '$obj->var', but | ||
| 1377 | ;; not in $obj->var() | ||
| 1378 | ("->\\(\\sw+\\)\\s-*(" 1 'default) | ||
| 1379 | |||
| 1380 | ("\\(\\$\\|->\\)\\([a-zA-Z0-9_]+\\)" 2 font-lock-variable-name-face) | ||
| 1381 | |||
| 1382 | ;; Highlight all upper-cased symbols as constant | ||
| 1383 | ("\\<\\([A-Z_][A-Z0-9_]+\\)\\>" 1 font-lock-constant-face) | ||
| 1384 | |||
| 1385 | ;; Highlight all statically accessed class names as constant, | ||
| 1386 | ;; another valid option would be using type-face, but using | ||
| 1387 | ;; constant-face because this is how it works in c++-mode. | ||
| 1388 | ("\\(\\sw+\\)::" 1 font-lock-constant-face) | ||
| 1389 | |||
| 1390 | ;; Highlight class name after "use .. as" | ||
| 1391 | ("\\<as\\s-+\\(\\sw+\\)" 1 font-lock-type-face) | ||
| 1392 | |||
| 1393 | ;; Class names are highlighted by cc-mode as defined in | ||
| 1394 | ;; c-class-decl-kwds, below regexp is a workaround for a bug | ||
| 1395 | ;; where the class names are not highlighted right after opening | ||
| 1396 | ;; a buffer (editing a file corrects it). | ||
| 1397 | ;; | ||
| 1398 | ;; This behaviour is caused by the preceding '<?php', which | ||
| 1399 | ;; cc-mode cannot handle easily. Registering it as a cpp | ||
| 1400 | ;; preprocessor works well (i.e. the next line is not a | ||
| 1401 | ;; statement-cont) but the highlighting glitch remains. | ||
| 1402 | (,(concat (regexp-opt (c-lang-const c-class-decl-kwds php)) | ||
| 1403 | " \\(\\sw+\\)") | ||
| 1404 | 1 font-lock-type-face) | ||
| 1405 | |||
| 1406 | ;; While c-opt-cpp-* highlights the <?php opening tags, it is not | ||
| 1407 | ;; possible to make it highlight short open tags and closing tags | ||
| 1408 | ;; as well. So we force the correct face on all cases that | ||
| 1409 | ;; c-opt-cpp-* lacks for this purpose. | ||
| 1410 | ;; | ||
| 1411 | ;; Note that starting a file with <% breaks indentation, a | ||
| 1412 | ;; limitation we can/should live with. | ||
| 1413 | (,(regexp-opt '("?>" "<?" "<%" "%>")) 0 font-lock-preprocessor-face))) | ||
| 1414 | "Detailed highlighting for PHP mode.") | ||
| 1415 | |||
| 1416 | (defvar php-font-lock-keywords php-font-lock-keywords-3 | ||
| 1417 | "Default expressions to highlight in PHP mode.") | ||
| 1418 | |||
| 1419 | ;;; Provide support for Flymake so that users can see warnings and | ||
| 1420 | ;;; errors in real-time as they write code. | ||
| 1421 | |||
| 1422 | (defun flymake-php-init () | ||
| 1423 | (let* ((temp-file (flymake-init-create-temp-buffer-copy | ||
| 1424 | 'flymake-create-temp-inplace)) | ||
| 1425 | (local-file (file-relative-name | ||
| 1426 | temp-file | ||
| 1427 | (file-name-directory buffer-file-name)))) | ||
| 1428 | (list php-executable (list "-f" local-file "-l")))) | ||
| 1429 | |||
| 1430 | (add-to-list 'flymake-allowed-file-name-masks | ||
| 1431 | '("\\.php[345s]?$" | ||
| 1432 | flymake-php-init | ||
| 1433 | flymake-simple-cleanup | ||
| 1434 | flymake-get-real-file-name)) | ||
| 1435 | |||
| 1436 | (add-to-list 'flymake-err-line-patterns | ||
| 1437 | '("\\(Parse\\|Fatal\\) error: \\(.*?\\) in \\(.*?\\) on line \\([0-9]+\\)" 3 4 nil 2)) | ||
| 1438 | |||
| 1439 | |||
| 1440 | (defun php-send-region (start end) | ||
| 1441 | "Send the region between `start' and `end' to PHP for execution. | ||
| 1442 | The output will appear in the buffer *PHP*." | ||
| 1443 | (interactive "r") | ||
| 1444 | (let ((php-buffer (get-buffer-create "*PHP*")) | ||
| 1445 | (code (buffer-substring start end))) | ||
| 1446 | ;; Calling 'php -r' will fail if we send it code that starts with | ||
| 1447 | ;; '<?php', which is likely. So we run the code through this | ||
| 1448 | ;; function to check for that prefix and remove it. | ||
| 1449 | (cl-flet ((clean-php-code (code) | ||
| 1450 | (if (string-prefix-p "<?php" code t) | ||
| 1451 | (substring code 5) | ||
| 1452 | code))) | ||
| 1453 | (call-process "php" nil php-buffer nil "-r" (clean-php-code code))))) | ||
| 1454 | |||
| 1455 | |||
| 1456 | (defface php-annotations-annotation-face '((t . (:inherit font-lock-constant-face))) | ||
| 1457 | "Face used to highlight annotations.") | ||
| 1458 | |||
| 1459 | (defconst php-annotations-re "\\(\\s-\\|{\\)\\(@[[:alpha:]]+\\)") | ||
| 1460 | |||
| 1461 | (defmacro php-annotations-inside-comment-p (pos) | ||
| 1462 | "Return non-nil if POS is inside a comment." | ||
| 1463 | `(or (eq (get-char-property ,pos 'face) 'font-lock-comment-face) | ||
| 1464 | (eq (get-char-property ,pos 'face) 'font-lock-comment-delimiter-face))) | ||
| 1465 | |||
| 1466 | (defun php-annotations-font-lock-find-annotation (limit) | ||
| 1467 | (let ((match | ||
| 1468 | (catch 'match | ||
| 1469 | (save-match-data | ||
| 1470 | (while (re-search-forward php-annotations-re limit t) | ||
| 1471 | (when (php-annotations-inside-comment-p (match-beginning 0)) | ||
| 1472 | (goto-char (match-end 0)) | ||
| 1473 | (throw 'match (match-data)))))))) | ||
| 1474 | (when match | ||
| 1475 | (set-match-data match) | ||
| 1476 | t))) | ||
| 1477 | |||
| 1478 | (defconst php-string-interpolated-variable-regexp | ||
| 1479 | "{\\$[^}\n\\\\]*\\(?:\\\\.[^}\n\\\\]*\\)*}\\|\\${\\sw+}\\|\\$\\sw+") | ||
| 1480 | |||
| 1481 | (defun php-string-intepolated-variable-font-lock-find (limit) | ||
| 1482 | (while (re-search-forward php-string-interpolated-variable-regexp limit t) | ||
| 1483 | (when (php-in-string-p) | ||
| 1484 | (put-text-property (match-beginning 0) (match-end 0) | ||
| 1485 | 'face 'font-lock-variable-name-face))) | ||
| 1486 | nil) | ||
| 1487 | |||
| 1488 | (eval-after-load 'php-mode | ||
| 1489 | '(progn | ||
| 1490 | (font-lock-add-keywords | ||
| 1491 | 'php-mode | ||
| 1492 | '((php-annotations-font-lock-find-annotation (2 'php-annotations-annotation-face t)))) | ||
| 1493 | (font-lock-add-keywords | ||
| 1494 | 'php-mode | ||
| 1495 | `((php-string-intepolated-variable-font-lock-find)) | ||
| 1496 | 'append))) | ||
| 1497 | |||
| 1498 | |||
| 1499 | |||
| 1500 | ;;; Correct the behavior of `delete-indentation' by modifying the | ||
| 1501 | ;;; logic of `fixup-whitespace'. | ||
| 1502 | (defadvice fixup-whitespace (after php-mode-fixup-whitespace) | ||
| 1503 | "Remove whitespace before certain characters in PHP mode." | ||
| 1504 | (let* ((no-behind-space ";\\|,\\|->\\|::") | ||
| 1505 | (no-front-space "->\\|::")) | ||
| 1506 | (when (and (eq major-mode 'php-mode) | ||
| 1507 | (or (looking-at-p (concat " \\(" no-behind-space "\\)")) | ||
| 1508 | (save-excursion | ||
| 1509 | (forward-char -2) | ||
| 1510 | (looking-at-p no-front-space)))) | ||
| 1511 | (delete-char 1)))) | ||
| 1512 | |||
| 1513 | (ad-activate 'fixup-whitespace) | ||
| 1514 | |||
| 1515 | ;; Advice `font-lock-fontify-keywords-region' to support namespace | ||
| 1516 | ;; separators in class names. Use word syntax for backslashes when | ||
| 1517 | ;; doing keyword fontification, but not when doing syntactic | ||
| 1518 | ;; fontification because that breaks \ as escape character in strings. | ||
| 1519 | ;; | ||
| 1520 | ;; Special care is taken to restore the original syntax, because we | ||
| 1521 | ;; want \ not to be word for functions like forward-word. | ||
| 1522 | (defadvice font-lock-fontify-keywords-region (around backslash-as-word activate) | ||
| 1523 | "Fontify keywords with backslash as word character" | ||
| 1524 | (let ((old-syntax (string (char-syntax ?\\)))) | ||
| 1525 | (modify-syntax-entry ?\\ "w") | ||
| 1526 | ad-do-it | ||
| 1527 | (modify-syntax-entry ?\\ old-syntax))) | ||
| 1528 | |||
| 1529 | |||
| 1530 | ;;;###autoload | ||
| 1531 | (dolist (pattern '("\\.php[s345t]?\\'" "\\.phtml\\'" "Amkfile" "\\.amk$")) | ||
| 1532 | (add-to-list 'auto-mode-alist `(,pattern . php-mode) t)) | ||
| 1533 | |||
| 1534 | (provide 'php-mode) | ||
| 1535 | |||
| 1536 | ;;; php-mode.el ends here | ||
