diff --git a/Cask b/Cask index eb2df24e..ff497f3f 100644 --- a/Cask +++ b/Cask @@ -1,8 +1,10 @@ (package "php-mode" "1.21.2" "Major mode for editing PHP code") (source melpa) +(package-file "php.el") (package-file "php-mode.el") (package-file "php-project.el") +(package-file "php-mode-debug.el") (development (depends-on "pkg-info") diff --git a/Makefile b/Makefile index 906dc5bb..609d3560 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ EMACS ?= emacs -ELS = php-project.el php-mode.el php-mode-test.el +ELS = php.el php-project.el php-mode.el php-mode-debug.el php-mode-test.el AUTOLOADS = php-project-autoloads.el php-mode-autoloads.el ELCS = $(ELS:.el=.elc) @@ -10,7 +10,7 @@ all: autoloads $(ELCS) autoloads: $(AUTOLOADS) -$(AUTOLOADS): php-project.el php-mode.el +$(AUTOLOADS): php.el php-project.el php-mode-debug.el php-mode.el $(EMACS) -Q -batch -L . --eval \ "(progn \ (require 'package) \ @@ -24,7 +24,7 @@ clean: dev: cp etc/git/prepare-commit-msg .git/hooks/prepare-commit-msg chmod u+x .git/hooks/prepare-commit-msg - + # Runs all unit tests from php-mode-test.el and shows the results. The # script will exit with the status code zero if all tests pass. If any # test fails the script exits with a non-zero status and shows diff --git a/php-mode-debug.el b/php-mode-debug.el new file mode 100644 index 00000000..d6f3cf65 --- /dev/null +++ b/php-mode-debug.el @@ -0,0 +1,99 @@ +;;; php-mode-debug.el --- Debug functions for PHP Mode -*- lexical-binding: t; -*- + +;; Copyright (C) 2018-2019 Friends of Emacs-PHP development + +;; Author: USAMI Kenta +;; URL: https://github.com/emacs-php/php-mode +;; Keywords: maint +;; Version: 1.21.2 +;; Package-Requires: ((emacs "24.3") (cl-lib "0.5")) +;; License: GPL-3.0-or-later + +;; This program 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. + +;; This program 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 this program. If not, see . + +;;; Commentary: + +;; Provides functions to debugging php-mode work. + +;;; Code: +(require 'cc-mode) +(require 'cus-edit) +(require 'php-mode) +(require 'package) +(require 'pkg-info nil t) + +(declare-function pkg-info-version-info "pkg-info" (library &optional package show)) + +(defun php-mode-debug--buffer (&optional command &rest args) + "Return buffer for php-mode-debug, and execute `COMMAND' with `ARGS'." + (with-current-buffer (get-buffer-create "*PHP Mode DEBUG*") + (cl-case command + (init (erase-buffer) + (goto-address-mode)) + (top (goto-char (point-min))) + (insert (goto-char (point-max)) + (apply #'insert args))) + (current-buffer))) + +(defun php-mode-debug--message (format-string &rest args) + "Write message `FORMAT-STRING' and `ARGS' to debug buffer, like `message'." + (declare (indent 1)) + (php-mode-debug--buffer 'insert (apply #'format format-string args) "\n")) + +(defun php-mode-debug () + "Display informations useful for debugging PHP Mode." + (interactive) + (php-mode-debug--buffer 'init) + (php-mode-debug--message "Feel free to report on GitHub what you noticed!") + (php-mode-debug--message "https://github.com/emacs-php/php-mode/issues/new") + (php-mode-debug--message "") + (php-mode-debug--message "Pasting the following information on the issue will help us to investigate the cause.") + (php-mode-debug--message "```") + (php-mode-debug--message "--- PHP-MODE DEBUG BEGIN ---") + (php-mode-debug--message "versions: %s; %s" (emacs-version) (php-mode-version)) + (php-mode-debug--message "package-version: %s" + (if (fboundp 'pkg-info) + (pkg-info-version-info 'php-mode) + (let ((pkg (and (boundp 'package-alist) + (cadr (assq 'php-mode package-alist))))) + (when (and pkg (member (package-desc-status pkg) '("unsigned" "dependency"))) + (package-version-join (package-desc-version pkg)))))) + + (php-mode-debug--message "major-mode: %s" major-mode) + (php-mode-debug--message "minor-modes: %s" + (cl-loop for s in minor-mode-list + unless (string-match-p "global" (symbol-name s)) + if (and (boundp s) (symbol-value s)) + collect s)) + (php-mode-debug--message "variables: %s" + (cl-loop for v in '(indent-tabs-mode tab-width) + collect (list v (symbol-value v)))) + (php-mode-debug--message "custom variables: %s" + (cl-loop for (v type) in (custom-group-members 'php nil) + if (eq type 'custom-variable) + collect (list v (symbol-value v)))) + (php-mode-debug--message "c-indentation-style: %s" c-indentation-style) + (php-mode-debug--message "c-style-variables: %s" + (cl-loop for v in c-style-variables + unless (memq v '(c-doc-comment-style c-offsets-alist)) + collect (list v (symbol-value v)))) + (php-mode-debug--message "c-doc-comment-style: %s" c-doc-comment-style) + (php-mode-debug--message "c-offsets-alist: %s" c-offsets-alist) + (php-mode-debug--message "--- PHP-MODE DEBUG END ---") + (php-mode-debug--message "```\n") + (php-mode-debug--message "Thank you!") + (pop-to-buffer (php-mode-debug--buffer 'top))) + +(provide 'php-mode-debug) +;;; php-mode-debug.el ends here diff --git a/php-mode-test.el b/php-mode-test.el index e54fdd01..b0f0114b 100644 --- a/php-mode-test.el +++ b/php-mode-test.el @@ -30,8 +30,9 @@ ;; with Emacs >= 24.1. ;;; Code: - +(require 'php) (require 'php-mode) +(require 'php-mode-debug) (require 'php-project) (require 'ert) (require 'cl-lib) diff --git a/php-mode.el b/php-mode.el index de0aa3c2..cf9e44cd 100644 --- a/php-mode.el +++ b/php-mode.el @@ -63,6 +63,7 @@ ;;; Code: +(require 'php) (require 'cc-mode) (require 'cc-langs) @@ -83,7 +84,6 @@ (require 'speedbar) (require 'imenu) (require 'nadvice nil t) -(require 'package) (require 'cl-lib) (require 'mode-local) @@ -91,7 +91,6 @@ (eval-when-compile (require 'regexp-opt) - (autoload 'pkg-info-version-info "pkg-info") (defvar c-vsemi-status-unknown-p) (defvar syntax-propertize-via-font-lock)) @@ -118,16 +117,10 @@ ;; need it in php-mode, just return nil. nil))) +(autoload 'php-mode-debug "php-mode-debug" + "Display informations useful for debugging PHP Mode." t) ;; Local variables -;;;###autoload -(defgroup php nil - "Language support for PHP." - :tag "PHP" - :group 'languages - :group 'php - :link '(url-link :tag "Official Site" "https://github.com/emacs-php/php-mode") - :link '(url-link :tag "PHP Mode Wiki" "https://github.com/emacs-php/php-mode/wiki")) ;;;###autoload (defgroup php-mode nil @@ -139,11 +132,6 @@ :link '(url-link :tag "Official Site" "https://github.com/emacs-php/php-mode") :link '(url-link :tag "PHP Mode Wiki" "https://github.com/emacs-php/php-mode/wiki")) -(defcustom php-executable (or (executable-find "php") - "/usr/bin/php") - "The location of the PHP executable." - :type 'string) - (define-obsolete-variable-alias 'php-default-face 'php-mode-default-face "1.20.0") (defcustom php-mode-default-face 'default "Default face in `php-mode' buffers." @@ -178,15 +166,6 @@ Turning this on will open it whenever `php-mode' is loaded." :group 'php-mode :type 'boolean) -(defsubst php-in-string-p () - (nth 3 (syntax-ppss))) - -(defsubst php-in-comment-p () - (nth 4 (syntax-ppss))) - -(defsubst php-in-string-or-comment-p () - (nth 8 (syntax-ppss))) - (defun php-mode-extra-constants-create-regexp (kwds) "Create regexp for the list of extra constant keywords KWDS." (concat "[^_$]?\\<\\(" @@ -225,67 +204,6 @@ of constants when set." :type '(repeat string) :set 'php-mode-extra-constants-set) -(defun php-create-regexp-for-method (visibility) - "Make a regular expression for methods with the given VISIBILITY. - -VISIBILITY must be a string that names the visibility for a PHP -method, e.g. 'public'. The parameter VISIBILITY can itself also -be a regular expression. - -The regular expression this function returns will check for other -keywords that can appear in method signatures, e.g. 'final' and -'static'. The regular expression will have one capture group -which will be the name of the method." - (concat - ;; Initial space with possible 'abstract' or 'final' keywords - "^\\s-*\\(?:\\(?:abstract\\|final\\)\\s-+\\)?" - ;; 'static' keyword may come either before or after visibility - "\\(?:" visibility "\\(?:\\s-+static\\)?\\|\\(?:static\\s-+\\)?" visibility "\\)\\s-+" - ;; Make sure 'function' comes next with some space after - "function\\s-+" - ;; Capture the name as the first group and the regexp and make sure - ;; by the end we see the opening parenthesis for the parameters. - "\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*(")) - -(defun php-create-regexp-for-classlike (type) - "Accepts a `TYPE' of a 'classlike' object as a string, such as -'class' or 'interface', and returns a regexp as a string which -can be used to match against definitions for that classlike." - (concat - ;; First see if 'abstract' or 'final' appear, although really these - ;; are not valid for all values of `type' that the function - ;; accepts. - "^\\s-*\\(?:\\(?:abstract\\|final\\)\\s-+\\)?" - ;; The classlike type - type - ;; Its name, which is the first captured group in the regexp. We - ;; allow backslashes in the name to handle namespaces, but again - ;; this is not necessarily correct for all values of `type'. - "\\s-+\\(\\(?:\\sw\\|\\\\\\|\\s_\\)+\\)")) - -(defvar php-imenu-generic-expression - `(("Namespaces" - ,(php-create-regexp-for-classlike "namespace") 1) - ("Classes" - ,(php-create-regexp-for-classlike "class") 1) - ("Interfaces" - ,(php-create-regexp-for-classlike "interface") 1) - ("Traits" - ,(php-create-regexp-for-classlike "trait") 1) - ("All Methods" - ,(php-create-regexp-for-method "\\(?:\\sw\\|\\s_\\)+") 1) - ("Private Methods" - ,(php-create-regexp-for-method "private") 1) - ("Protected Methods" - ,(php-create-regexp-for-method "protected") 1) - ("Public Methods" - ,(php-create-regexp-for-method "public") 1) - ("Anonymous Functions" - "\\<\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*=\\s-*function\\s-*(" 1) - ("Named Functions" - "^\\s-*function\\s-+\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*(" 1)) - "Imenu generic expression for PHP Mode. See `imenu-generic-expression'.") - (define-obsolete-variable-alias 'php-do-not-use-semantic-imenu 'php-mode-do-not-use-semantic-imenu "1.20.0") (defcustom php-mode-do-not-use-semantic-imenu t "Customize `imenu-create-index-function' for `php-mode'. @@ -297,32 +215,6 @@ parent. Set this variable to t if you want to use enabled." :type 'boolean) -(defcustom php-site-url "https://php.net/" - "Default PHP.net site URL. - -The URL to use open PHP manual and search word." - :type 'string) - -(defcustom php-manual-url 'en - "URL at which to find PHP manual. -You can replace \"en\" with your ISO language code." - :type '(choice (const :tag "English" 'en) - (const :tag "Brazilian Portuguese" 'pt_BR) - (const :tag "Chinese (Simplified)" 'zh) - (const :tag "French" 'fr) - (const :tag "German" 'de) - (const :tag "Japanese" 'ja) - (const :tag "Romanian" 'ro) - (const :tag "Russian" 'ru) - (const :tag "Spanish" 'es) - (const :tag "Turkish" 'tr) - (string :tag "PHP manual URL"))) - -(defcustom php-search-url nil - "URL at which to search for documentation on a word." - :type '(choice (string :tag "URL to search PHP documentation") - (const :tag "Use `php-site-url' variable" nil))) - (defcustom php-completion-file "" "Path to the file which contains the function names known to PHP." :type 'string) @@ -1192,70 +1084,6 @@ After setting the stylevars run hooks according to STYLENAME (prog1 (php-set-style (symbol-name coding-style)) (remove-hook 'hack-local-variables-hook #'php-mode-set-style-delay))))) -(defun php-mode-debug--buffer (&optional command &rest args) - "Return buffer for php-mode-debug, and execute `COMMAND' with `ARGS'." - (with-current-buffer (get-buffer-create "*PHP Mode DEBUG*") - (cl-case command - (init (erase-buffer) - (goto-address-mode)) - (top (goto-char (point-min))) - (insert (goto-char (point-max)) - (apply #'insert args))) - (current-buffer))) - -(defun php-mode-debug--message (format-string &rest args) - "Write message `FORMAT-STRING' and `ARGS' to debug buffer, like `message'." - (declare (indent 1)) - (php-mode-debug--buffer 'insert (apply #'format format-string args) "\n")) - -(declare-function custom-group-members "cus-edit" (symbol groups-only)) - -(defun php-mode-debug () - "Display informations useful for debugging PHP Mode." - (interactive) - (require 'cus-edit) - (require 'pkg-info nil t) - (php-mode-debug--buffer 'init) - (php-mode-debug--message "Feel free to report on GitHub what you noticed!") - (php-mode-debug--message "https://github.com/emacs-php/php-mode/issues/new") - (php-mode-debug--message "") - (php-mode-debug--message "Pasting the following information on the issue will help us to investigate the cause.") - (php-mode-debug--message "```") - (php-mode-debug--message "--- PHP-MODE DEBUG BEGIN ---") - (php-mode-debug--message "versions: %s; %s" (emacs-version) (php-mode-version)) - (php-mode-debug--message "package-version: %s" - (if (fboundp 'pkg-info) - (pkg-info-version-info 'php-mode) - (let ((pkg (and (boundp 'package-alist) - (cadr (assq 'php-mode package-alist))))) - (when (and pkg (member (package-desc-status pkg) '("unsigned" "dependency"))) - (package-version-join (package-desc-version pkg)))))) - - (php-mode-debug--message "major-mode: %s" major-mode) - (php-mode-debug--message "minor-modes: %s" - (cl-loop for s in minor-mode-list - unless (string-match-p "global" (symbol-name s)) - if (and (boundp s) (symbol-value s)) - collect s)) - (php-mode-debug--message "variables: %s" - (cl-loop for v in '(indent-tabs-mode tab-width) - collect (list v (symbol-value v)))) - (php-mode-debug--message "custom variables: %s" - (cl-loop for (v type) in (custom-group-members 'php nil) - if (eq type 'custom-variable) - collect (list v (symbol-value v)))) - (php-mode-debug--message "c-indentation-style: %s" c-indentation-style) - (php-mode-debug--message "c-style-variables: %s" - (cl-loop for v in c-style-variables - unless (memq v '(c-doc-comment-style c-offsets-alist)) - collect (list v (symbol-value v)))) - (php-mode-debug--message "c-doc-comment-style: %s" c-doc-comment-style) - (php-mode-debug--message "c-offsets-alist: %s" c-offsets-alist) - (php-mode-debug--message "--- PHP-MODE DEBUG END ---") - (php-mode-debug--message "```\n") - (php-mode-debug--message "Thank you!") - (pop-to-buffer (php-mode-debug--buffer 'top))) - ;;;###autoload (define-derived-mode php-mode c-mode "PHP" "Major mode for editing PHP code. @@ -1827,46 +1655,6 @@ The output will appear in the buffer *PHP*." (ad-activate 'fixup-whitespace) - -(defcustom php-class-suffix-when-insert "::" - "Suffix for inserted class." - :group 'php - :type 'string) - -(defcustom php-namespace-suffix-when-insert "\\" - "Suffix for inserted namespace." - :group 'php - :type 'string) - -(defvar php--re-namespace-pattern - (php-create-regexp-for-classlike "namespace")) - -(defvar php--re-classlike-pattern - (php-create-regexp-for-classlike (regexp-opt '("class" "interface" "trait")))) - -(defun php-get-current-element (re-pattern) - "Return backward matched element by RE-PATTERN." - (save-excursion - (when (re-search-backward re-pattern nil t) - (match-string-no-properties 1)))) - -;;;###autoload -(defun php-current-class () - "Insert current class name if cursor in class context." - (interactive) - (let ((matched (php-get-current-element php--re-classlike-pattern))) - (when matched - (insert (concat matched php-class-suffix-when-insert))))) - -;;;###autoload -(defun php-current-namespace () - "Insert current namespace if cursor in namespace context." - (interactive) - (let ((matched (php-get-current-element php--re-namespace-pattern))) - (when matched - (insert (concat matched php-namespace-suffix-when-insert))))) - - ;;;###autoload (add-to-list 'auto-mode-alist (cons diff --git a/php.el b/php.el new file mode 100644 index 00000000..13ce5c19 --- /dev/null +++ b/php.el @@ -0,0 +1,185 @@ +;;; php.el --- PHP support for friends -*- lexical-binding: t; -*- + +;; Copyright (C) 2019 Friends of Emacs-PHP development + +;; Author: USAMI Kenta +;; Created: 5 Dec 2018 +;; Version: 1.21.2 +;; Keywords: languages, php +;; Homepage: https://github.com/emacs-php/php-mode +;; Package-Requires: ((emacs "24.3") (cl-lib "0.5")) +;; License: GPL-3.0-or-later + +;; This program 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. + +;; This program 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 this program. If not, see . + +;;; Commentary: + +;; This file provides common variable and functions for PHP packages. + +;;; Code: + +;;;###autoload +(defgroup php nil + "Language support for PHP." + :tag "PHP" + :group 'languages + :link '(url-link :tag "Official Site" "https://github.com/emacs-php/php-mode") + :link '(url-link :tag "PHP Mode Wiki" "https://github.com/emacs-php/php-mode/wiki")) + +(defcustom php-executable (or (executable-find "php") "/usr/bin/php") + "The location of the PHP executable." + :type 'string) + +(defcustom php-site-url "https://php.net/" + "Default PHP.net site URL. + +The URL to use open PHP manual and search word." + :type 'string) + +(defcustom php-manual-url 'en + "URL at which to find PHP manual. +You can replace \"en\" with your ISO language code." + :type '(choice (const :tag "English" 'en) + (const :tag "Brazilian Portuguese" 'pt_BR) + (const :tag "Chinese (Simplified)" 'zh) + (const :tag "French" 'fr) + (const :tag "German" 'de) + (const :tag "Japanese" 'ja) + (const :tag "Romanian" 'ro) + (const :tag "Russian" 'ru) + (const :tag "Spanish" 'es) + (const :tag "Turkish" 'tr) + (string :tag "PHP manual URL"))) + +(defcustom php-search-url nil + "URL at which to search for documentation on a word." + :group 'php + :type '(choice (string :tag "URL to search PHP documentation") + (const :tag "Use `php-site-url' variable" nil))) + +(defcustom php-class-suffix-when-insert "::" + "Suffix for inserted class." + :group 'php + :type 'string) + +(defcustom php-namespace-suffix-when-insert "\\" + "Suffix for inserted namespace." + :group 'php + :type 'string) + +;;; Utillity for locate language construction +(defsubst php-in-string-p () + "Return non-nil if inside a string. +it is the character that will terminate the string, or t if the string should be terminated by a generic string delimiter." + (nth 3 (syntax-ppss))) + +(defsubst php-in-comment-p () + "Return nil if outside a comment, t if inside a non-nestable comment, else an integer (the current comment nesting)." + (nth 4 (syntax-ppss))) + +(defsubst php-in-string-or-comment-p () + "Return character address of start of comment or string; nil if not in one." + (nth 8 (syntax-ppss))) + +(defun php-create-regexp-for-method (visibility) + "Make a regular expression for methods with the given VISIBILITY. + +VISIBILITY must be a string that names the visibility for a PHP +method, e.g. 'public'. The parameter VISIBILITY can itself also +be a regular expression. + +The regular expression this function returns will check for other +keywords that can appear in method signatures, e.g. 'final' and +'static'. The regular expression will have one capture group +which will be the name of the method." + (concat + ;; Initial space with possible 'abstract' or 'final' keywords + "^\\s-*\\(?:\\(?:abstract\\|final\\)\\s-+\\)?" + ;; 'static' keyword may come either before or after visibility + "\\(?:" visibility "\\(?:\\s-+static\\)?\\|\\(?:static\\s-+\\)?" visibility "\\)\\s-+" + ;; Make sure 'function' comes next with some space after + "function\\s-+" + ;; Capture the name as the first group and the regexp and make sure + ;; by the end we see the opening parenthesis for the parameters. + "\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*(")) + +(defun php-create-regexp-for-classlike (type) + "Accepts a `TYPE' of a 'classlike' object as a string, such as +'class' or 'interface', and returns a regexp as a string which +can be used to match against definitions for that classlike." + (concat + ;; First see if 'abstract' or 'final' appear, although really these + ;; are not valid for all values of `type' that the function + ;; accepts. + "^\\s-*\\(?:\\(?:abstract\\|final\\)\\s-+\\)?" + ;; The classlike type + type + ;; Its name, which is the first captured group in the regexp. We + ;; allow backslashes in the name to handle namespaces, but again + ;; this is not necessarily correct for all values of `type'. + "\\s-+\\(\\(?:\\sw\\|\\\\\\|\\s_\\)+\\)")) + +(defvar php-imenu-generic-expression + `(("Namespaces" + ,(php-create-regexp-for-classlike "namespace") 1) + ("Classes" + ,(php-create-regexp-for-classlike "class") 1) + ("Interfaces" + ,(php-create-regexp-for-classlike "interface") 1) + ("Traits" + ,(php-create-regexp-for-classlike "trait") 1) + ("All Methods" + ,(php-create-regexp-for-method "\\(?:\\sw\\|\\s_\\)+") 1) + ("Private Methods" + ,(php-create-regexp-for-method "private") 1) + ("Protected Methods" + ,(php-create-regexp-for-method "protected") 1) + ("Public Methods" + ,(php-create-regexp-for-method "public") 1) + ("Anonymous Functions" + "\\<\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*=\\s-*function\\s-*(" 1) + ("Named Functions" + "^\\s-*function\\s-+\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*(" 1)) + "Imenu generic expression for PHP Mode. See `imenu-generic-expression'.") + +(defvar php--re-namespace-pattern + (php-create-regexp-for-classlike "namespace")) + +(defvar php--re-classlike-pattern + (php-create-regexp-for-classlike (regexp-opt '("class" "interface" "trait")))) + +(defun php-get-current-element (re-pattern) + "Return backward matched element by RE-PATTERN." + (save-excursion + (when (re-search-backward re-pattern nil t) + (match-string-no-properties 1)))) + +;;;###autoload +(defun php-current-class () + "Insert current class name if cursor in class context." + (interactive) + (let ((matched (php-get-current-element php--re-classlike-pattern))) + (when matched + (insert (concat matched php-class-suffix-when-insert))))) + +;;;###autoload +(defun php-current-namespace () + "Insert current namespace if cursor in namespace context." + (interactive) + (let ((matched (php-get-current-element php--re-namespace-pattern))) + (when matched + (insert (concat matched php-namespace-suffix-when-insert))))) + +(provide 'php) +;;; php.el ends here