diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..88b3b49 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,15 @@ +language: emacs-lisp +before_install: + - curl -fsSkL https://gist.githubusercontent.com/rejeep/7736123/raw | sh + - export PATH="/home/travis/.cask/bin:$PATH" + - export PATH="/home/travis/.evm/bin:$PATH" + - evm install $EVM_EMACS --use + - cask +env: + - EVM_EMACS=emacs-24.1-bin + - EVM_EMACS=emacs-24.2-bin + - EVM_EMACS=emacs-24.4-bin + - EVM_EMACS=emacs-24.5-bin +script: + - emacs --version + - make test diff --git a/drupal-mode.el b/drupal-mode.el index f6c9476..0458356 100644 --- a/drupal-mode.el +++ b/drupal-mode.el @@ -1,11 +1,11 @@ ;;; drupal-mode.el --- Advanced minor mode for Drupal development -;; Copyright (C) 2012, 2013, 2014, 2015 Arne Jørgensen +;; Copyright (C) 2012, 2013, 2014, 2015, 2016 Arne Jørgensen ;; Author: Arne Jørgensen ;; URL: https://github.com/arnested/drupal-mode ;; Created: January 17, 2012 -;; Version: 0.6.1 +;; Version: 0.7.0 ;; Package-Requires: ((php-mode "1.5.0")) ;; Keywords: programming, php, drupal @@ -36,6 +36,8 @@ (require 'cl) (require 'php-mode) (require 'format-spec) +(require 'json) +(require 'sql) ;; Silence byte compiler. (defvar css-indent-level) @@ -239,7 +241,8 @@ get better filling in Doxygen comments." (?f . drupal-insert-function) (?m . drupal-module-name) (?e . drupal-drush-php-eval) - (?t . drupal-wrap-string-in-t-function)) + (?t . drupal-wrap-string-in-t-function) + (?s . drupal-drush-sql-cli)) "Map of mnemonic keys and functions for keyboard shortcuts. See `drupal-mode-map'.") @@ -428,6 +431,10 @@ of the project)." [menu-bar drupal cache-clear] '(menu-item "Clear all caches" drupal-drush-cache-clear :enable (and drupal-rootdir drupal-drush-program))) +(define-key drupal-mode-map + [menu-bar drupal sql-cli] + '(menu-item "Open SQL shell" drupal-drush-sql-cli + :enable (and drupal-rootdir drupal-drush-program))) (define-key drupal-mode-map [menu-bar drupal drupal-project drupal-project-bugs] @@ -519,6 +526,48 @@ buffer." (search-forward-regexp "\\(\"\\|'\\)") (insert ")"))))) +(defun drupal-drush-sql-cli () + "Run a SQL shell using \"drush sql-cli\" in a SQL-mode comint buffer." + (interactive) + (let* ((json-object-type 'plist) + (config + (json-read-from-string + (with-temp-buffer + (call-process drupal-drush-program nil t nil + "sql-conf" "--format=json") + (buffer-string))))) + (when (not config) + (error "No Drupal SQL configuration found.")) + (destructuring-bind (&key database driver &allow-other-keys) config + (let ((sql-interactive-product + (drupal--db-driver-to-sql-product driver)) + (start-buffer (current-buffer)) + (sqli-buffer + (make-comint (format "SQL (%s)" database) + drupal-drush-program nil "sql-cli"))) + (with-current-buffer sqli-buffer + (sql-interactive-mode) + (set (make-local-variable 'sql-buffer) + (buffer-name (current-buffer))) + + ;; Set `sql-buffer' in the start buffer + (with-current-buffer start-buffer + (when (derived-mode-p 'sql-mode) + (setq sql-buffer (buffer-name sqli-buffer)) + (run-hooks 'sql-set-sqli-hook))) + + ;; All done. + (run-hooks 'sql-login-hook) + (pop-to-buffer sqli-buffer)))))) + +(defun drupal--db-driver-to-sql-product (driver) + "Translate a Drupal DB driver name into a sql-mode symbol." + (let ((driver (intern driver))) + (cond + ((eq driver 'pgsql) 'postgres) + ((assq driver sql-product-alist) driver) + (t 'ansi)))) + (defvar drupal-form-id-history nil @@ -556,7 +605,8 @@ buffer." (user-error "%s already exists in file." (replace-regexp-in-string "^hook" (drupal-module-name) v2))) ;; User error if the hook is already inserted elsewhere. (when (and drupal-get-function-args - (funcall drupal-get-function-args (replace-regexp-in-string "^hook" (drupal-module-name) v2))) + (ignore-errors + (funcall drupal-get-function-args (replace-regexp-in-string "^hook" (drupal-module-name) v2)))) (user-error "%s already exists elsewhere." (replace-regexp-in-string "^hook" (drupal-module-name) v2))) (drupal-ensure-newline) "/**\n" @@ -872,6 +922,7 @@ mode-hook." (eval-after-load 'eldoc '(require 'drupal/eldoc)) (eval-after-load 'etags '(require 'drupal/etags)) (eval-after-load 'gtags '(require 'drupal/gtags)) +(eval-after-load 'helm-gtags '(require 'drupal/helm-gtags)) (eval-after-load 'ggtags '(require 'drupal/ggtags)) (eval-after-load 'ispell '(require 'drupal/ispell)) (eval-after-load 'flymake-phpcs '(require 'drupal/flymake-phpcs)) diff --git a/drupal/autoinsert.el b/drupal/autoinsert.el index 1aa29d8..3a32ada 100644 --- a/drupal/autoinsert.el +++ b/drupal/autoinsert.el @@ -1,6 +1,6 @@ ;;; drupal/autoinsert.el --- Drupal-mode support for `auto-insert-mode' -;; Copyright (C) 2012, 2013, 2014 Arne Jørgensen +;; Copyright (C) 2012, 2013, 2014, 2015, 2016 Arne Jørgensen ;; Author: Arne Jørgensen ;; Keywords: @@ -30,6 +30,8 @@ (define-auto-insert '("\\.module" . "Drupal module file") 'drupal/autoinsert-insert-module-skeleton) (define-auto-insert '("\\.install" . "Drupal install file") 'drupal/autoinsert-insert-install-skeleton) (define-auto-insert '("\\.test" . "Drupal test file") 'drupal/autoinsert-insert-test-skeleton) +(define-auto-insert '("\\.api.php" . "Drupal API file") 'drupal/autoinsert-insert-api-skeleton) +(define-auto-insert '("\\.variable.inc" . "Drupal variable module support file") 'drupal/autoinsert-insert-variable-module-skeleton) (define-skeleton drupal/autoinsert-insert-info-skeleton "Drupal info file skeleton." @@ -95,6 +97,73 @@ @ - "\n" "}\n") +(define-skeleton drupal/autoinsert-insert-api-skeleton + "Drupal api.php file skeleton." + nil + " 'string',\n" + " 'title' => t('Some variable title', array(), $options),\n" + " 'default' => 'uid',\n" + " 'description' => t('Some variable description', array(), $options),\n" + " 'group' => '" (drupal-module-name) "',\n" + " );\n" + "\n" + " return $variables;\n" + "}\n" + "\n" + "/**\n" + " * Implements hook_variable_group_info().\n" + " */\n" + "function " (drupal-module-name) "_variable_group_info() {\n" + " $groups['" (drupal-module-name) "'] = array(\n" + " 'title' => t('Some group title'),\n" + " 'description' => t('Some group description.'),\n" + " );\n" + "\n" + " return $groups;\n" + "}\n" + "\n" + "/**\n" + " * @} End of \"addtogroup variables\".\n" + " */\n") + (provide 'drupal/autoinsert) diff --git a/drupal/etags.el b/drupal/etags.el index 6c23a7e..d502b45 100644 --- a/drupal/etags.el +++ b/drupal/etags.el @@ -47,12 +47,13 @@ "Get function arguments from etags TAGS." (when (and (boundp 'drupal/etags-rootdir) (file-exists-p (concat drupal/etags-rootdir "TAGS"))) - (with-current-buffer (find-tag-noselect symbol nil nil) - (goto-char (point-min)) - (when (re-search-forward - (format "function\\s-+%s\\s-*(\\([^{]*\\))" symbol) - nil t) - (match-string-no-properties 1))))) + (save-excursion + (with-current-buffer (find-tag-noselect symbol nil nil) + (goto-char (point-min)) + (when (re-search-forward + (format "function\\s-+%s\\s-*(\\([^{]*\\))" symbol) + nil t) + (match-string-no-properties 1)))))) (add-hook 'drupal-mode-hook #'drupal/etags-enable) diff --git a/drupal/flycheck.el b/drupal/flycheck.el index 1f1df69..1eb3675 100644 --- a/drupal/flycheck.el +++ b/drupal/flycheck.el @@ -50,7 +50,7 @@ checker runs those. See URL `http://pear.php.net/package/PHP_CodeSniffer/'." :command ("phpcs" "--report=emacs" - (option "--standard=" flycheck-phpcs-standard concat) + (option "--standard=" drupal/phpcs-standard concat) source-inplace) ;; Though phpcs supports Checkstyle output which we could feed to ;; `flycheck-parse-checkstyle', we are still using error patterns here, @@ -64,17 +64,15 @@ See URL `http://pear.php.net/package/PHP_CodeSniffer/'." (warning line-start (file-name) ":" line ":" column ": warning - " (message) line-end)) - ;; We'd prefer to just check drupal-mode, but flycheck global mode - ;; finds the checker before we get a chance to set drupal-mode. :predicate (lambda () - (apply 'derived-mode-p (append drupal-css-modes drupal-js-modes drupal-info-modes)))) + (and drupal-mode drupal/phpcs-standard))) ;; Append our custom checker. (add-to-list 'flycheck-checkers 'drupal-phpcs t) ;; Add our checker as next-checker to checkers of all supported modes. (let ((modes (append drupal-css-modes drupal-js-modes drupal-info-modes))) (dolist (checker (flycheck-defined-checkers)) - (dolist (mode (flycheck-checker-modes checker)) + (dolist (mode (flycheck-checker-get checker 'modes)) (if (memq mode modes) (flycheck-add-next-checker checker 'drupal-phpcs))))) diff --git a/drupal/helm-gtags.el b/drupal/helm-gtags.el new file mode 100644 index 0000000..8f74bd0 --- /dev/null +++ b/drupal/helm-gtags.el @@ -0,0 +1,63 @@ +;;; drupal/helm-gtags.el --- Drupal-mode support for helm-gtags + +;; Copyright (C) 2012, 2013, 2014, 2015, 2016 Arne Jørgensen + +;; Author: Arne Jørgensen + +;; This file is part of Drupal mode. + +;; Drupal mode is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published +;; by the Free Software Foundation, either version 3 of the License, +;; or (at your option) any later version. + +;; Drupal mode is distributed in the hope that it will be useful, but +;; WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with Drupal mode. If not, see . + +;;; Commentary: + +;; Enable drupal-mode support for helm-gtags. + +;;; Code: + +(require 'helm-gtags) + +(defvar drupal/helm-gtags-global-command (executable-find "global") + "Name of the GNU GLOBAL `global' executable. +Include path to the executable if it is not in your $PATH.") + +(defun drupal/helm-gtags-enable () + "Setup rootdir for helm-gtags." + (let ((dir (locate-dominating-file (or buffer-file-name default-directory) "GTAGS"))) + (when dir + (set (make-local-variable 'helm-gtags--tag-location) dir) + + ;; Set `drupal-symbol-collection' to a call to + ;; `gtags-completing-gtags' so that inserting hooks will do + ;; completion based on gtags. + (setq drupal-symbol-collection #'(lambda() (helm-gtags--complete 'tag "" nil t))) + (setq drupal-get-function-args #'drupal/helm-gtags-get-function-args) + (helm-gtags-mode 1)))) + +(defun drupal/helm-gtags-get-function-args (symbol &optional version) + "Get function arguments from GNU GLOBAL." + (when (file-exists-p (concat helm-gtags--tag-location "GTAGS")) + (with-temp-buffer + (ignore-errors + (call-process drupal/helm-gtags-global-command nil t nil "-x" symbol) + (goto-char (point-min)) + (search-forward-regexp "[^(]*(\\(.*\\))[^)]*" nil t) + (match-string-no-properties 1))))) + +(add-hook 'drupal-mode-hook #'drupal/helm-gtags-enable) + + + +(provide 'drupal/helm-gtags) + +;;; drupal/helm-gtags.el ends here diff --git a/drupal/phpcs.el b/drupal/phpcs.el index 723f9fa..4dd4cbb 100644 --- a/drupal/phpcs.el +++ b/drupal/phpcs.el @@ -1,6 +1,6 @@ ;;; drupal/phpcs.el --- Drupal-mode common support for flymake-phpcs and flycheck -;; Copyright (C) 2012, 2013 Arne Jørgensen +;; Copyright (C) 2012, 2013, 2016 Arne Jørgensen ;; Author: Arne Jørgensen @@ -34,7 +34,7 @@ ;; command. Check for both. (call-process (or (and (boundp 'flymake-phpcs-command) (executable-find flymake-phpcs-command)) (executable-find "phpcs")) nil (list t nil) nil "-i"))))) (when (string-match - "\\(Drupal[^, + "\\(Drupal[^ , ]*\\)" standards) (match-string-no-properties 1 standards))))