Skip to content

Commit

Permalink
Merge pull request #532 from emacs-php/php-mode-maybe
Browse files Browse the repository at this point in the history
Add php-mode-maybe and php-project-php-file-as-template
  • Loading branch information
zonuexe authored May 26, 2019
2 parents 5b0fe1b + 43d0a80 commit d75517c
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 55 deletions.
3 changes: 2 additions & 1 deletion php-mode-test.el
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,8 @@ an error."
style from Drupal."
(dolist (mode '(pear wordpress symfony2))
;; the file written to has no significance, only the buffer
(let ((tmp-filename (concat (make-temp-name temporary-file-directory) ".php")))
(let ((tmp-filename (concat (make-temp-name temporary-file-directory) ".php"))
(auto-mode-alist '(("\\.php\\'" . php-mode))))
(with-php-mode-test ("issue-53.php")
(search-forward "return $this->bar;")
(should (equal (list "before-write-file" mode nil)
Expand Down
20 changes: 3 additions & 17 deletions php-mode.el
Original file line number Diff line number Diff line change
Expand Up @@ -1600,23 +1600,9 @@ The output will appear in the buffer *PHP*."
(ad-activate 'fixup-whitespace)

;;;###autoload
(add-to-list 'auto-mode-alist
(cons
(eval-when-compile
(rx (or
;; File name extensions (ex. "*.php", "*.phtml")
(: "."
(or (: "php" (? (in "s345t")))
"amk"
"phtml"))
;; Full file names (ex. "/Makefile", "/Amkfile")
(: "/"
(or "Amkfile"
".php_cs"
".php_cs.dist")))
string-end))
'php-mode)
t)
(progn
(add-to-list 'auto-mode-alist '("/\\.php_cs\\(?:\\.dist\\)?\\'" . php-mode))
(add-to-list 'auto-mode-alist '("\\.\\(?:php[s345]?\\|phtml\\)\\'" . php-mode-maybe)))

(provide 'php-mode)
;;; php-mode.el ends here
90 changes: 53 additions & 37 deletions php-project.el
Original file line number Diff line number Diff line change
Expand Up @@ -102,85 +102,90 @@ STRING
If the string is an actual directory path, it is set as the absolute path
of the root directory, not the marker.")
(put 'php-project-root 'safe-local-variable
#'(lambda (v) (or (stringp v) (assq v php-project-available-root-files)))))
#'(lambda (v) (or (stringp v) (assq v php-project-available-root-files))))

;;;###autoload
(progn
(defvar-local php-project-bootstrap-scripts nil
"List of path to bootstrap php script file.
The ideal bootstrap file is silent, it only includes dependent files,
defines constants, and sets the class loaders.")
(put 'php-project-bootstrap-scripts 'safe-local-variable #'php-project--eval-bootstrap-scripts))
(put 'php-project-bootstrap-scripts 'safe-local-variable #'php-project--eval-bootstrap-scripts)

;;;###autoload
(progn
(defvar-local php-project-php-executable nil
"Path to php executable file.")
(put 'php-project-php-executable 'safe-local-variable
#'(lambda (v) (and (stringp v) (file-executable-p v)))))
#'(lambda (v) (and (stringp v) (file-executable-p v))))

;;;###autoload
(progn
(defvar-local php-project-phan-executable nil
"Path to phan executable file.")
(put 'php-project-phan-executable 'safe-local-variable #'php-project--eval-bootstrap-scripts))
(put 'php-project-phan-executable 'safe-local-variable #'php-project--eval-bootstrap-scripts)

;;;###autoload
(progn
(defvar-local php-project-coding-style nil
"Symbol value of the coding style of the project that PHP major mode refers to.
Typically it is `pear', `drupal', `wordpress', `symfony2' and `psr2'.")
(put 'php-project-coding-style 'safe-local-variable #'symbolp))
(put 'php-project-coding-style 'safe-local-variable #'symbolp)

;;;###autoload
(progn
(defvar php-project-repl nil
(defvar-local php-project-php-file-as-template 'auto
"
`auto' (default)
Automatically switch to mode for template when HTML tag detected in file.
`t'
Switch all PHP files in that directory to mode for HTML template.
`nil'
Any .php in that directory is just a PHP script.
\(\(PATTERN . SYMBOL))
Alist of file name pattern regular expressions and the above symbol pairs.
PATTERN is regexp pattern.
")
(put 'php-project-php-file-as-template 'safe-local-variable #'php-project--validate-php-file-as-template)

(defvar-local php-project-repl nil
"Function name or path to REPL (interactive shell) script.")
(make-variable-buffer-local 'php-project-repl)
(put 'php-project-repl 'safe-local-variable
#'(lambda (v) (or (functionp v)
(php-project--eval-bootstrap-scripts v)))))
(php-project--eval-bootstrap-scripts v))))

;;;###autoload
(progn
(defvar php-project-unit-test nil
(defvar-local php-project-unit-test nil
"Function name or path to unit test script.")
(make-variable-buffer-local 'php-project-unit-test)
(put 'php-project-unit-test 'safe-local-variable
#'(lambda (v) (or (functionp v)
(php-project--eval-bootstrap-scripts v)))))
(php-project--eval-bootstrap-scripts v))))

;;;###autoload
(progn
(defvar php-project-deploy nil
(defvar-local php-project-deploy nil
"Function name or path to deploy script.")
(make-variable-buffer-local 'php-project-deploy)
(put 'php-project-deploy 'safe-local-variable
#'(lambda (v) (or (functionp v)
(php-project--eval-bootstrap-scripts v)))))
(php-project--eval-bootstrap-scripts v))))

;;;###autoload
(progn
(defvar php-project-build nil
(defvar-local php-project-build nil
"Function name or path to build script.")
(make-variable-buffer-local 'php-project-build)
(put 'php-project-build 'safe-local-variable
#'(lambda (v) (or (functionp v)
(php-project--eval-bootstrap-scripts v)))))
(php-project--eval-bootstrap-scripts v))))

;;;###autoload
(progn
(defvar php-project-server-start nil
(defvar-local php-project-server-start nil
"Function name or path to server-start script.")
(make-variable-buffer-local 'php-project-server-start)
(put 'php-project-server-start 'safe-local-variable
#'(lambda (v) (or (functionp v)
(php-project--eval-bootstrap-scripts v)))))


;; Functions
(defun php-project--validate-php-file-as-template (val)
"Return T when `VAL' is valid list of safe ."
(cond
((null val) t)
((memq val '(t auto)) t)
((listp val)
(cl-loop for v in val
always (and (consp v)
(stringp (car v))
(php-project--validate-php-file-as-template (cdr v)))))
(t nil)))

(defun php-project--eval-bootstrap-scripts (val)
"Return T when `VAL' is valid list of safe bootstrap php script."
Expand Down Expand Up @@ -213,6 +218,17 @@ Typically it is `pear', `drupal', `wordpress', `symfony2' and `psr2'.")
(cons 'root "vendor/bin/phan"))))
(executable-find "phan")))

(defun php-project-get-file-html-template-type (filename)
"Return symbol T, NIL or `auto' by `FILENAME'."
(cond
((not php-project-php-file-as-template) nil)
((eq t php-project-php-file-as-template) t)
((eq 'auto php-project-php-file-as-template) 'auto)
((listp php-project-php-file-as-template)
(assoc-default filename php-project-php-file-as-template #'string-match-p))
(t (prog1 nil
(warn "php-project-php-file-as-template is unexpected format")))))

;;;###autoload
(defun php-project-get-bootstrap-scripts ()
"Return list of bootstrap script."
Expand Down
84 changes: 84 additions & 0 deletions php.el
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

;;; Code:
(require 'flymake)
(require 'php-project)

;;;###autoload
(defgroup php nil
Expand Down Expand Up @@ -85,6 +86,41 @@ You can replace \"en\" with your ISO language code."
"Suffix for inserted namespace."
:group 'php
:type 'string)

(defcustom php-default-major-mode 'php-mode
"Major mode for editing PHP script."
:group 'php
:tag "PHP Default Major Mode"
:type 'function)

(defcustom php-html-template-major-mode 'web-mode
"Major mode for editing PHP-HTML template."
:group 'php
:tag "PHP-HTML Template Major Mode"
:type 'function)

(defcustom php-blade-template-major-mode 'web-mode
"Major mode for editing Blade template."
:group 'php
:tag "PHP Blade Template Major Mode"
:type 'function)

(defcustom php-template-mode-alist
`(("\\.blade" . ,php-blade-template-major-mode)
("\\.phpt\\'" . ,(if (fboundp 'phpt-mode) 'phpt-mode php-html-template-major-mode))
("\\.phtml\\'" . ,php-html-template-major-mode))
"Automatically use another MAJOR-MODE when open template file."
:group 'php
:tag "PHP Template Mode Alist"
:type '(alist :key-type regexp :value-type function)
:link '(url-link :tag "web-mode" "http://web-mode.org/")
:link '(url-link :tag "phpt-mode" "https://github.com/emacs-php/phpt-mode"))

(defcustom php-mode-maybe-hook nil
"List of functions to be executed on entry to `php-mode-maybe'."
:group 'php
:tag "PHP Mode Maybe Hook"
:type 'hook)

;;; PHP Keywords
(defconst php-magical-constants
Expand Down Expand Up @@ -199,6 +235,54 @@ Look at the `php-executable' variable instead of the constant \"php\" command."
'flymake-php-init)))))
(list php-executable (cdr init))))

(defconst php-re-detect-html-tag
(eval-when-compile
(rx (or (: string-start (* (in space))
"<!"
(or "DOCTYPE" "doctype")
(+ (in space))
(or "HTML" "html"))
(: (or line-start
(: "<" (? "/")
(* (in space)) (+ (in alpha "-")) (* (in space)) ">"))
(: "<" (* (in space)) (+ (in alpha "-")) (* (in space)) ">"))))))

(defun php-buffer-has-html-tag ()
"Return position of HTML tag or NIL in current buffer."
(save-excursion
(save-restriction
(widen)
(goto-char (point-min))
(re-search-forward php-re-detect-html-tag nil t))))

(defun php-derivation-major-mode ()
"Return major mode for PHP file by file-name and its content."
(let ((mode (assoc-default buffer-file-name
php-template-mode-alist
#'string-match-p))
type)
(when (and (null mode) buffer-file-name
php-project-php-file-as-template)
(setq type (php-project-get-file-html-template-type buffer-file-name))
(cond
((eq t type) (setq mode php-html-template-major-mode))
((eq 'auto type)
(when (php-buffer-has-html-tag)
(setq mode php-html-template-major-mode)))))
(when (and mode (not (fboundp mode)))
(if (string-match-p "\\.blade\\." buffer-file-name)
(warn "php-mode is NOT support blade template. %s"
"Please install `web-mode' package")
(setq mode nil)))
(or mode php-default-major-mode)))

;;;###autoload
(defun php-mode-maybe ()
"Select PHP mode or other major mode."
(interactive)
(run-hooks php-mode-maybe-hook)
(funcall (php-derivation-major-mode)))

;;;###autoload
(defun php-current-class ()
"Insert current class name if cursor in class context."
Expand Down

0 comments on commit d75517c

Please sign in to comment.