11; ;; drupal-mode.el --- Advanced minor mode for Drupal development
22
3- ; ; Copyright (C) 2012, 2013 Arne Jørgensen
3+ ; ; Copyright (C) 2012, 2013, 2014 Arne Jørgensen
44
55; ; Author: Arne Jørgensen <[email protected] >66; ; URL: https://github.com/arnested/drupal-mode
77; ; Created: January 17, 2012
8- ; ; Version: 0.3 .1
8+ ; ; Version: 0.4 .1
99; ; Package-Requires: ((php-mode "1.5.0"))
1010; ; Keywords: programming, php, drupal
1111
3636(require 'php-mode )
3737(require 'format-spec )
3838
39- ( eval-when-compile
40- ( require ' css-mode ) )
39+ ; ; Silence byte compiler.
40+ ( defvar css-indent-level )
4141
4242
4343
@@ -62,7 +62,7 @@ If `Ask' ask the user whether to convert line endings.
6262
6363Drupal coding standards states that all text files should end in
6464a single newline (\\ n)."
65- :type `(choice
65+ :type `(choice
6666 :tag " we offer to change line endings if needed?"
6767 (const :tag " Always" t )
6868 (const :tag " Never" nil )
@@ -83,7 +83,7 @@ If `Default' do what the global setting is.
8383
8484Drupal coding standards states that lines should have no trailing
8585whitespace at the end."
86- :type `(choice
86+ :type `(choice
8787 :tag " Whether to delete all the trailing whitespace."
8888 (const :tag " Always" always)
8989 (const :tag " Default" default )
@@ -98,6 +98,7 @@ whitespace at the end."
9898%s is the search term."
9999 :type '(choice (const :tag " Api.drupal.org" " http://api.drupal.org/api/search/%v/%s" )
100100 (const :tag " Api.drupalcontrib.org" " http://api.drupalcontrib.org/api/search/%v/%s" )
101+ (const :tag " Api.drupalize.me" " http://api.drupalize.me/api/search/%v/%s" )
101102 (string :tag " Other" " http://example.com/api/search/%v/%s" ))
102103 :link '(url-link :tag " api.drupalcontrib.org" " http://api.drupalcontrib.org" )
103104 :link '(url-link :tag " api.drupal.org" " http://api.drupal.org" )
@@ -162,6 +163,36 @@ Include path to the executable if it is not in your $PATH."
162163 :type '(repeat symbol)
163164 :group 'drupal )
164165
166+ (defcustom drupal-enable-auto-fill-mode t
167+ " Whether to use `auto-fill-mode' Drupal PHP buffers.
168+ Drupal mode will only do auto fill in comments (auto filling code
169+ is not nice).
170+
171+ If `Yes' enable `auto-fill-mode' in Drupal PHP mode buffers.
172+ If `No' don't enable `auto-fill-mode' in Drupal PHP mode buffers (`auto-fill-mode' can still be enabled by other settings)."
173+ :type `(choice
174+ :tag " Enable `auto-fill-mode' ."
175+ (const :tag " Yes" t )
176+ (const :tag " No" nil ))
177+ :link '(variable-link comment-auto-fill-only-comments)
178+ :group 'drupal )
179+
180+ (defcustom drupal-paragraph-separate " ^[ \t ]*\\ (\\ (/[/\\ *]+\\ )\\ |\\ (\\ *+/\\ )\\ |\\ (\\ *?\\ )\\ |\\ (\\ *?[ \t ]*@[[:alpha:]]+\\ ([ \t ]+.*\\ )?\\ )\\ )[ \t ]*$"
181+ " Regexp for beginning of a line that separates paragraphs.
182+ In Drupal mode we extend the regular `paragraph-separate' so we
183+ will get better filling in Doxygen comments."
184+ :type 'regexp
185+ :link '(variable-link paragraph-separate)
186+ :group 'drupal )
187+
188+ (defcustom drupal-paragraph-start (default-value 'drupal-paragraph-separate )
189+ " Regexp for beginning of a line that starts OR separates paragraphs.
190+ In Drupal mode we extend the regular `paragraph-start' so we will
191+ get better filling in Doxygen comments."
192+ :type 'regexp
193+ :link '(variable-link paragraph-start)
194+ :group 'drupal )
195+
165196
166197
167198(defvar drupal-version nil " Drupal version as auto detected." )
@@ -188,14 +219,23 @@ Include path to the executable if it is not in your $PATH."
188219(make-variable-buffer-local 'drupal-project )
189220(put 'drupal-project 'safe-local-variable 'string-or-null-p )
190221
222+ (defvar drupal-mode-map-alist
223+ '((?d . drupal-search-documentation)
224+ (?c . drupal-drush-cache-clear)
225+ (?h . drupal-insert-hook)
226+ (?f . drupal-insert-function)
227+ (?m . drupal-module-name)
228+ (?t . drupal-wrap-string-in-t-function))
229+ " Map of mnemonic keys and functions for keyboard shortcuts.
230+ See `drupal-mode-map' ." )
231+
191232(defvar drupal-mode-map
192233 (let ((map (make-sparse-keymap )))
193- (define-key map [(control c) (control v) (control d)] #'drupal-search-documentation )
194- (define-key map [(control c) (control v) (control c)] #'drupal-drush-cache-clear )
195- (define-key map [(control c) (control v) (control h)] #'drupal-insert-hook )
196- (define-key map [(control c) (control v) (control f)] #'drupal-insert-function )
197- (define-key map [(control c) (control v) (control m)] #'drupal-module-name )
198- (define-key map [(control c) (control v) (control t )] #'drupal-wrap-string-in-t-function )
234+ ; ; Iterate `drupal-mode-map-alist' and assign the functions to the
235+ ; ; mode map on C-c C-v C-`mnemonic-key' .
236+ (dolist (elem drupal-mode-map-alist)
237+ (define-key map `[(control c) (control v) (control ,(car elem))] (cdr elem)))
238+
199239 (define-key map [(control a)] #'drupal-mode-beginning-of-line )
200240 map)
201241 " Keymap for `drupal-mode' " )
@@ -228,9 +268,6 @@ function arguments.")
228268 :lighter " Drupal"
229269 :keymap drupal-mode-map
230270
231- ; ; Detect drupal version, drupal root, etc.
232- (drupal-detect-drupal-version)
233-
234271 ; ; Delete trailing white space.
235272 (when (eq drupal-delete-trailing-whitespace 'always )
236273 (add-hook 'before-save-hook #'delete-trailing-whitespace nil t ))
@@ -263,7 +300,16 @@ function arguments.")
263300 ; ; Setup cc-mode style stuff.
264301 (when (derived-mode-p 'c-mode )
265302 (c-add-language 'drupal-mode 'c-mode )
266- (c-set-style " drupal" ))))
303+ (c-set-style " drupal" ))
304+
305+ ; ; Use `auto-fill' only in comments.
306+ (when drupal-enable-auto-fill-mode
307+ (set (make-local-variable 'comment-auto-fill-only-comments ) t )
308+ (auto-fill-mode 1 ))
309+
310+ ; ; Improve filling in Doxygen comments.
311+ (set (make-local-variable 'paragraph-separate ) drupal-paragraph-separate)
312+ (set (make-local-variable 'paragraph-start ) drupal-paragraph-start)))
267313
268314
269315
@@ -497,7 +543,7 @@ It is really slow to download `drupal-search-url'. You should
497543probably not use this. Have a look at using GNU GLOBAL / Gtags
498544instead."
499545 (unless version
500- (setq version ( drupal-detect-drupal- version) ))
546+ (setq version drupal-version))
501547 (with-temp-buffer
502548 (ignore-errors
503549 (url-insert-file-contents (format-spec drupal-search-url `((?v . , version )
@@ -538,79 +584,95 @@ Heavily based on `message-beginning-of-line' from Gnus."
538584 (set zrs t )))
539585 (if (derived-mode-p 'conf-mode )
540586 (let* ((here (point ))
541- (bol (progn (beginning-of-line n) (point )))
542- (eol (point-at-eol ))
543- (eoh (re-search-forward " = *" eol t )))
544- (goto-char
545- (if (and eoh (or (< eoh here) (= bol here)))
546- eoh bol)))
587+ (bol (progn (beginning-of-line n) (point )))
588+ (eol (point-at-eol ))
589+ (eoh (re-search-forward " = *" eol t )))
590+ (goto-char
591+ (if (and eoh (or (< eoh here) (= bol here)))
592+ eoh bol)))
547593 (beginning-of-line n)))
548594
549595
550596
597+ (defvar drupal-local-variables (make-hash-table :test 'equal )
598+ " Drupal local variables hash table." )
599+
551600; ; Detect Drupal and Drupal version
552601(defun drupal-detect-drupal-version ()
553602 " Detect if the buffer is part of a Drupal project.
554603If part of a Drupal project also detect the version of Drupal and
555604the location of DRUPAL_ROOT."
556605 (interactive )
557- (hack-local-variables )
606+ (drupal- hack-local-variables)
558607 (when (or (not drupal-version)
559608 (not drupal-rootdir))
560609 (dolist (file '(" modules/system/system.module" " includes/bootstrap.inc" " core/lib/Drupal.php" ))
561610 (let ((here (or buffer-file-name default-directory)))
562611 (when here
563612 (let ((dir (locate-dominating-file here file)))
564613 (when dir
565- (with-current-buffer (find-file-noselect (concat dir file) t )
566- (save-excursion
567- (widen )
568- (goto-char (point-min ))
569- (when (re-search-forward " \\ (define('VERSION',\\ |const VERSION =\\ ) +'\\ (.+\\ )'" nil t )
570- (dir-locals-set-class-variables 'drupal-site `((nil . ((drupal-version . ,(match-string-no-properties 2 ))
571- (drupal-rootdir . , dir )))))
572- (dir-locals-set-directory-class dir 'drupal-site )))
573- (setq drupal-version (match-string-no-properties 2 ))))))))
574- (hack-local-variables ))
614+ (with-temp-buffer
615+ (insert-file-contents-literally (concat dir file))
616+ (goto-char (point-min ))
617+ (when (re-search-forward " \\ (define('VERSION',\\ |const VERSION =\\ ) +'\\ (.+\\ )'" nil t )
618+ (setq drupal-version (match-string-no-properties 2 ))
619+ (puthash (expand-file-name dir) `((drupal-version . , drupal-version )
620+ (drupal-rootdir . , dir ))
621+ drupal-local-variables)))))))))
622+ (drupal-hack-local-variables)
575623 (let ((module (drupal-locate-dominating-module (or buffer-file-name default-directory) t ))
576624 (version drupal-version)
577625 (module-name nil )
578626 (module-version nil )
579627 (project nil ))
580628 (when module
581- (with-current-buffer (find-file-noselect module t )
582- (save-excursion
583- (widen )
584- (goto-char (point-min ))
585- (when (and (not drupal-version)
586- (re-search-forward " ^core *=" nil t ))
587- (re-search-forward " *\" ?\\ ([^\" ]+\\ )\" ?" (point-at-eol ) t )
588- (setq version (match-string-no-properties 1 )))
589- (goto-char (point-min ))
590- (when (re-search-forward " ^name *=" nil t )
591- (re-search-forward " *\" ?\\ ([^\" ]+\\ )\" ?" (point-at-eol ) t )
592- (setq module-name (match-string-no-properties 1 )))
593- (goto-char (point-min ))
594- (when (re-search-forward " ^version *=" nil t )
595- (re-search-forward " *\" ?\\ ([^\" ]+\\ )\" ?" (point-at-eol ) t )
596- (setq module-version (match-string-no-properties 1 )))
597- (goto-char (point-min ))
598- (when (re-search-forward " ^project *=" nil t )
599- (re-search-forward " *\" ?\\ ([^\" ]+\\ )\" ?" (point-at-eol ) t )
600- (setq project (match-string-no-properties 1 )))
601- (when (and (string= project " drupal" )
602- (string= module-version " VERSION" ))
603- (setq module-version version))))
604- (dir-locals-set-class-variables 'drupal-module `((nil . ((drupal-module . ,(file-name-nondirectory
605- (file-name-sans-extension module)))
606- (drupal-version . , version )
607- (drupal-module-name . , module-name )
608- (drupal-module-version . , module-version )
609- (drupal-project . , project )))))
610- (dir-locals-set-directory-class (file-name-directory module) 'drupal-module )))
611- (hack-local-variables )
629+ (with-temp-buffer
630+ (insert-file-contents-literally module)
631+ (goto-char (point-min ))
632+ (when (and (not drupal-version)
633+ (re-search-forward " ^core *=" nil t ))
634+ (re-search-forward " *\" ?\\ ([^\" ]+\\ )\" ?" (point-at-eol ) t )
635+ (setq version (match-string-no-properties 1 )))
636+ (goto-char (point-min ))
637+ (when (re-search-forward " ^name *=" nil t )
638+ (re-search-forward " *\" ?\\ ([^\" ]+\\ )\" ?" (point-at-eol ) t )
639+ (setq module-name (match-string-no-properties 1 )))
640+ (goto-char (point-min ))
641+ (when (re-search-forward " ^version *=" nil t )
642+ (re-search-forward " *\" ?\\ ([^\" ]+\\ )\" ?" (point-at-eol ) t )
643+ (setq module-version (match-string-no-properties 1 )))
644+ (goto-char (point-min ))
645+ (when (re-search-forward " ^project *=" nil t )
646+ (re-search-forward " *\" ?\\ ([^\" ]+\\ )\" ?" (point-at-eol ) t )
647+ (setq project (match-string-no-properties 1 )))
648+ (when (and (string= project " drupal" )
649+ (string= module-version " VERSION" ))
650+ (setq module-version version))
651+ (puthash (expand-file-name (file-name-directory module)) `((drupal-module . ,(file-name-nondirectory
652+ (file-name-sans-extension module)))
653+ (drupal-version . , version )
654+ (drupal-module-name . , module-name )
655+ (drupal-module-version . , module-version )
656+ (drupal-project . , project ))
657+ drupal-local-variables))))
658+ (drupal-hack-local-variables)
612659 drupal-version)
613660
661+ (defun drupal-hack-local-variables ()
662+ " Drupal hack `drupal-local-variables' as buffer local variables."
663+ (interactive )
664+ (let ((dir (expand-file-name (or (file-name-directory buffer-file-name) default-directory)))
665+ matches)
666+ (maphash (lambda (key value )
667+ (when (string-match (concat " ^" (regexp-quote key)) dir)
668+ (add-to-list 'matches key)))
669+ drupal-local-variables)
670+ (sort matches #' (lambda (a b ) (> (string-width a) (string-width b))))
671+ (dolist (elem matches)
672+ (let ((vars (gethash elem drupal-local-variables)))
673+ (dolist (var vars)
674+ (set (make-local-variable (car var)) (cdr-safe var)))))))
675+
614676(defun drupal-locate-dominating-module (file &optional info-file-location )
615677 " Look up the directory hierarchy from FILE for a Drupal module root.
616678Stop at the first parent where a matching module is found and
@@ -666,7 +728,7 @@ Used in `drupal-insert-hook' and `drupal-insert-function'."
666728 drupal-module
667729 ; ; Otherwise fall back to a very naive
668730 ; ; way of guessing the module name.
669- (file-name-nondirectory (file-name-sans-extension (buffer-file-name )))))))
731+ (file-name-nondirectory (file-name-sans-extension (or buffer-file-name ( buffer-name ) )))))))
670732 (if (called-interactively-p 'any )
671733 (insert name)
672734 name)))
@@ -675,7 +737,7 @@ Used in `drupal-insert-hook' and `drupal-insert-function'."
675737 " Return major version number of version string.
676738If major version number is 4 - return both major and minor."
677739 (unless version
678- (setq version ( drupal-detect-drupal- version) ))
740+ (setq version drupal-version))
679741 (when version
680742 (let ((version-list (split-string version " \\ ." )))
681743 (if (= (string-to-number (car version-list)) 4 )
0 commit comments