Skip to content

Commit d75517c

Browse files
authored
Merge pull request #532 from emacs-php/php-mode-maybe
Add php-mode-maybe and php-project-php-file-as-template
2 parents 5b0fe1b + 43d0a80 commit d75517c

File tree

4 files changed

+142
-55
lines changed

4 files changed

+142
-55
lines changed

Diff for: php-mode-test.el

+2-1
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,8 @@ an error."
271271
style from Drupal."
272272
(dolist (mode '(pear wordpress symfony2))
273273
;; the file written to has no significance, only the buffer
274-
(let ((tmp-filename (concat (make-temp-name temporary-file-directory) ".php")))
274+
(let ((tmp-filename (concat (make-temp-name temporary-file-directory) ".php"))
275+
(auto-mode-alist '(("\\.php\\'" . php-mode))))
275276
(with-php-mode-test ("issue-53.php")
276277
(search-forward "return $this->bar;")
277278
(should (equal (list "before-write-file" mode nil)

Diff for: php-mode.el

+3-17
Original file line numberDiff line numberDiff line change
@@ -1600,23 +1600,9 @@ The output will appear in the buffer *PHP*."
16001600
(ad-activate 'fixup-whitespace)
16011601

16021602
;;;###autoload
1603-
(add-to-list 'auto-mode-alist
1604-
(cons
1605-
(eval-when-compile
1606-
(rx (or
1607-
;; File name extensions (ex. "*.php", "*.phtml")
1608-
(: "."
1609-
(or (: "php" (? (in "s345t")))
1610-
"amk"
1611-
"phtml"))
1612-
;; Full file names (ex. "/Makefile", "/Amkfile")
1613-
(: "/"
1614-
(or "Amkfile"
1615-
".php_cs"
1616-
".php_cs.dist")))
1617-
string-end))
1618-
'php-mode)
1619-
t)
1603+
(progn
1604+
(add-to-list 'auto-mode-alist '("/\\.php_cs\\(?:\\.dist\\)?\\'" . php-mode))
1605+
(add-to-list 'auto-mode-alist '("\\.\\(?:php[s345]?\\|phtml\\)\\'" . php-mode-maybe)))
16201606

16211607
(provide 'php-mode)
16221608
;;; php-mode.el ends here

Diff for: php-project.el

+53-37
Original file line numberDiff line numberDiff line change
@@ -102,85 +102,90 @@ STRING
102102
If the string is an actual directory path, it is set as the absolute path
103103
of the root directory, not the marker.")
104104
(put 'php-project-root 'safe-local-variable
105-
#'(lambda (v) (or (stringp v) (assq v php-project-available-root-files)))))
105+
#'(lambda (v) (or (stringp v) (assq v php-project-available-root-files))))
106106

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

116-
;;;###autoload
117-
(progn
118114
(defvar-local php-project-php-executable nil
119115
"Path to php executable file.")
120116
(put 'php-project-php-executable 'safe-local-variable
121-
#'(lambda (v) (and (stringp v) (file-executable-p v)))))
117+
#'(lambda (v) (and (stringp v) (file-executable-p v))))
122118

123-
;;;###autoload
124-
(progn
125119
(defvar-local php-project-phan-executable nil
126120
"Path to phan executable file.")
127-
(put 'php-project-phan-executable 'safe-local-variable #'php-project--eval-bootstrap-scripts))
121+
(put 'php-project-phan-executable 'safe-local-variable #'php-project--eval-bootstrap-scripts)
128122

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

137-
;;;###autoload
138-
(progn
139-
(defvar php-project-repl nil
129+
(defvar-local php-project-php-file-as-template 'auto
130+
"
131+
`auto' (default)
132+
Automatically switch to mode for template when HTML tag detected in file.
133+
134+
`t'
135+
Switch all PHP files in that directory to mode for HTML template.
136+
137+
`nil'
138+
Any .php in that directory is just a PHP script.
139+
140+
\(\(PATTERN . SYMBOL))
141+
Alist of file name pattern regular expressions and the above symbol pairs.
142+
PATTERN is regexp pattern.
143+
")
144+
(put 'php-project-php-file-as-template 'safe-local-variable #'php-project--validate-php-file-as-template)
145+
146+
(defvar-local php-project-repl nil
140147
"Function name or path to REPL (interactive shell) script.")
141-
(make-variable-buffer-local 'php-project-repl)
142148
(put 'php-project-repl 'safe-local-variable
143149
#'(lambda (v) (or (functionp v)
144-
(php-project--eval-bootstrap-scripts v)))))
150+
(php-project--eval-bootstrap-scripts v))))
145151

146-
;;;###autoload
147-
(progn
148-
(defvar php-project-unit-test nil
152+
(defvar-local php-project-unit-test nil
149153
"Function name or path to unit test script.")
150-
(make-variable-buffer-local 'php-project-unit-test)
151154
(put 'php-project-unit-test 'safe-local-variable
152155
#'(lambda (v) (or (functionp v)
153-
(php-project--eval-bootstrap-scripts v)))))
156+
(php-project--eval-bootstrap-scripts v))))
154157

155-
;;;###autoload
156-
(progn
157-
(defvar php-project-deploy nil
158+
(defvar-local php-project-deploy nil
158159
"Function name or path to deploy script.")
159-
(make-variable-buffer-local 'php-project-deploy)
160160
(put 'php-project-deploy 'safe-local-variable
161161
#'(lambda (v) (or (functionp v)
162-
(php-project--eval-bootstrap-scripts v)))))
162+
(php-project--eval-bootstrap-scripts v))))
163163

164-
;;;###autoload
165-
(progn
166-
(defvar php-project-build nil
164+
(defvar-local php-project-build nil
167165
"Function name or path to build script.")
168-
(make-variable-buffer-local 'php-project-build)
169166
(put 'php-project-build 'safe-local-variable
170167
#'(lambda (v) (or (functionp v)
171-
(php-project--eval-bootstrap-scripts v)))))
168+
(php-project--eval-bootstrap-scripts v))))
172169

173-
;;;###autoload
174-
(progn
175-
(defvar php-project-server-start nil
170+
(defvar-local php-project-server-start nil
176171
"Function name or path to server-start script.")
177-
(make-variable-buffer-local 'php-project-server-start)
178172
(put 'php-project-server-start 'safe-local-variable
179173
#'(lambda (v) (or (functionp v)
180174
(php-project--eval-bootstrap-scripts v)))))
181175

182176

183177
;; Functions
178+
(defun php-project--validate-php-file-as-template (val)
179+
"Return T when `VAL' is valid list of safe ."
180+
(cond
181+
((null val) t)
182+
((memq val '(t auto)) t)
183+
((listp val)
184+
(cl-loop for v in val
185+
always (and (consp v)
186+
(stringp (car v))
187+
(php-project--validate-php-file-as-template (cdr v)))))
188+
(t nil)))
184189

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

221+
(defun php-project-get-file-html-template-type (filename)
222+
"Return symbol T, NIL or `auto' by `FILENAME'."
223+
(cond
224+
((not php-project-php-file-as-template) nil)
225+
((eq t php-project-php-file-as-template) t)
226+
((eq 'auto php-project-php-file-as-template) 'auto)
227+
((listp php-project-php-file-as-template)
228+
(assoc-default filename php-project-php-file-as-template #'string-match-p))
229+
(t (prog1 nil
230+
(warn "php-project-php-file-as-template is unexpected format")))))
231+
216232
;;;###autoload
217233
(defun php-project-get-bootstrap-scripts ()
218234
"Return list of bootstrap script."

Diff for: php.el

+84
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
;;; Code:
3131
(require 'flymake)
32+
(require 'php-project)
3233

3334
;;;###autoload
3435
(defgroup php nil
@@ -85,6 +86,41 @@ You can replace \"en\" with your ISO language code."
8586
"Suffix for inserted namespace."
8687
:group 'php
8788
:type 'string)
89+
90+
(defcustom php-default-major-mode 'php-mode
91+
"Major mode for editing PHP script."
92+
:group 'php
93+
:tag "PHP Default Major Mode"
94+
:type 'function)
95+
96+
(defcustom php-html-template-major-mode 'web-mode
97+
"Major mode for editing PHP-HTML template."
98+
:group 'php
99+
:tag "PHP-HTML Template Major Mode"
100+
:type 'function)
101+
102+
(defcustom php-blade-template-major-mode 'web-mode
103+
"Major mode for editing Blade template."
104+
:group 'php
105+
:tag "PHP Blade Template Major Mode"
106+
:type 'function)
107+
108+
(defcustom php-template-mode-alist
109+
`(("\\.blade" . ,php-blade-template-major-mode)
110+
("\\.phpt\\'" . ,(if (fboundp 'phpt-mode) 'phpt-mode php-html-template-major-mode))
111+
("\\.phtml\\'" . ,php-html-template-major-mode))
112+
"Automatically use another MAJOR-MODE when open template file."
113+
:group 'php
114+
:tag "PHP Template Mode Alist"
115+
:type '(alist :key-type regexp :value-type function)
116+
:link '(url-link :tag "web-mode" "http://web-mode.org/")
117+
:link '(url-link :tag "phpt-mode" "https://github.com/emacs-php/phpt-mode"))
118+
119+
(defcustom php-mode-maybe-hook nil
120+
"List of functions to be executed on entry to `php-mode-maybe'."
121+
:group 'php
122+
:tag "PHP Mode Maybe Hook"
123+
:type 'hook)
88124

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

238+
(defconst php-re-detect-html-tag
239+
(eval-when-compile
240+
(rx (or (: string-start (* (in space))
241+
"<!"
242+
(or "DOCTYPE" "doctype")
243+
(+ (in space))
244+
(or "HTML" "html"))
245+
(: (or line-start
246+
(: "<" (? "/")
247+
(* (in space)) (+ (in alpha "-")) (* (in space)) ">"))
248+
(: "<" (* (in space)) (+ (in alpha "-")) (* (in space)) ">"))))))
249+
250+
(defun php-buffer-has-html-tag ()
251+
"Return position of HTML tag or NIL in current buffer."
252+
(save-excursion
253+
(save-restriction
254+
(widen)
255+
(goto-char (point-min))
256+
(re-search-forward php-re-detect-html-tag nil t))))
257+
258+
(defun php-derivation-major-mode ()
259+
"Return major mode for PHP file by file-name and its content."
260+
(let ((mode (assoc-default buffer-file-name
261+
php-template-mode-alist
262+
#'string-match-p))
263+
type)
264+
(when (and (null mode) buffer-file-name
265+
php-project-php-file-as-template)
266+
(setq type (php-project-get-file-html-template-type buffer-file-name))
267+
(cond
268+
((eq t type) (setq mode php-html-template-major-mode))
269+
((eq 'auto type)
270+
(when (php-buffer-has-html-tag)
271+
(setq mode php-html-template-major-mode)))))
272+
(when (and mode (not (fboundp mode)))
273+
(if (string-match-p "\\.blade\\." buffer-file-name)
274+
(warn "php-mode is NOT support blade template. %s"
275+
"Please install `web-mode' package")
276+
(setq mode nil)))
277+
(or mode php-default-major-mode)))
278+
279+
;;;###autoload
280+
(defun php-mode-maybe ()
281+
"Select PHP mode or other major mode."
282+
(interactive)
283+
(run-hooks php-mode-maybe-hook)
284+
(funcall (php-derivation-major-mode)))
285+
202286
;;;###autoload
203287
(defun php-current-class ()
204288
"Insert current class name if cursor in class context."

0 commit comments

Comments
 (0)