diff --git a/Makefile b/Makefile index b9f8121e..2d630dca 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ EMACS ?= emacs -ELS = lisp/php.el lisp/php-align.el lisp/php-face.el lisp/php-project.el lisp/php-mode.el lisp/php-mode-debug.el +ELS = lisp/php.el lisp/php-align.el lisp/php-face.el lisp/php-project.el lisp/php-local-manual.el lisp/php-mode.el lisp/php-mode-debug.el AUTOLOADS = php-mode-autoloads.el ELCS = $(ELS:.el=.elc) diff --git a/lisp/php-local-manual.el b/lisp/php-local-manual.el index 6601ed65..e61d2bfb 100644 --- a/lisp/php-local-manual.el +++ b/lisp/php-local-manual.el @@ -2,9 +2,9 @@ ;; Copyright (C) 2020 Friends of Emacs-PHP development -;; Author: Eric James Michael Ritz +;; Author: phil-s ;; Maintainer: USAMI Kenta -;; URL: https://github.com/emacs-php/php-mode +;; URL: https://github.com/emacs-php/php-mode/wiki/Local-PHP-Manual ;; Keywords: docs, php ;; Version: 2.0.0 ;; License: GPL-3.0-or-later @@ -26,14 +26,104 @@ ;; This package helps you search the locally installed PHP Manual. ;; If you're only developing online, this feature is probably unnecessary. +;; +;; ## Notice +;; +;; This file is marked as an unmaintained feature. +;; https://github.com/emacs-php/php-mode/wiki/Unmaintained-Features +;; +;; ## How to use +;; +;; see https://github.com/emacs-php/php-mode/wiki/Local-PHP-Manual +;; +;; ### php-local-manual-search +;; +;; Put follows code into your .emacs (~/.emacs.d/init.el) file: +;; +;; (custom-set-variables +;; '(php-manual-path (expand-file-name "~/local/share/php-manual")) +;; '(php-search-documentation-function #'php-local-manual-search)) +;; ;;; Code: -(require 'php-mode) +(require 'php) -(defalias 'php-local-manual-search #'php-search-local-documentation) +(defconst php-local-manual-documentation-types + '("function" "control-structures" "class" "book") + ;; "intro" and "ref" also look interesting, but for all practical purposes + ;; their terms are sub-sets of the "book" terms (with the few exceptions + ;; being very unlikely search terms). + "The set (and priority sequence) of documentation file prefixes +under which to search for files in the local documentation directory.") -;; TODO: move implementation -;; (define-obsolete-function-alias 'php-search-local-documentation #'php-local-manual-search) +(defvar php-local-manual--words-cache nil) + +(defun php-local-manual--read-arg () + "Obtain interactive argument for searching documentation." + ;; Cache the list of documentation words available for completion, + ;; based on the defined types-of-interest. + (let ((types-list php-local-manual-documentation-types) + (words-cache php-local-manual--words-cache) + (local-manual (and (stringp php-manual-path) + (not (string= php-manual-path ""))))) + (when (and local-manual + (not (assq types-list words-cache))) + ;; Generate the cache on the first run, or if the types changed. + ;; We read the filenames matching our types list in the local + ;; documentation directory, and extract the 'middle' component + ;; of each. e.g. "function.array-map.html" => "array_map". + (let* ((types-opt (regexp-opt types-list)) + (pattern (concat "\\`" types-opt "\\.\\(.+\\)\\.html\\'")) + (collection + (mapcar (lambda (filename) + (subst-char-in-string ?- ?_ (replace-regexp-in-string + pattern "\\1" filename))) + (directory-files php-manual-path nil pattern)))) + ;; Replace the entire cache. If the types changed, we don't need + ;; to retain the collection for the previous value. + (setq words-cache (list (cons types-list collection))) + (setq php-local-manual--words-cache words-cache))) + ;; By default we search for (current-word) immediately, without prompting. + ;; With a prefix argument, or if there is no (current-word), we perform a + ;; completing read for a word from the cached collection. + (let* ((default (current-word)) + (prompt (if default + (format "Search PHP docs (%s): " default) + "Search PHP docs: ")) + (collection (and local-manual + (cdr (assq types-list words-cache)))) + (word (if (or current-prefix-arg (not default)) + (completing-read prompt collection nil nil nil nil default) + default))) + ;; Return interactive argument list. + (list word)))) + +;;;###autoload +(defun php-local-manual-search (word) + "Search the local PHP documentation (i.e. in `php-manual-path') for +the word at point. The function returns t if the requested documentation +exists, and nil otherwise. + +With a prefix argument, prompt (with completion) for a word to search for." + (interactive (php-local-manual--read-arg)) + (let ((file (catch 'found + (cl-loop for type in php-local-manual-documentation-types do + (let* ((doc-html (format "%s.%s.html" + type + (replace-regexp-in-string + "_" "-" (downcase word)))) + (file (expand-file-name doc-html php-manual-path))) + (when (file-exists-p file) + (throw 'found file))))))) + (when file + (let ((file-url (if (string-prefix-p "file://" file) + file + (concat "file://" file)))) + (php-browse-documentation-url file-url)) + t))) + +;;;###autoload +(define-obsolete-function-alias 'php-search-local-documentation #'php-local-manual-search "2.0.0") (provide 'php-local-manual) ;;; php-local-manual.el ends here diff --git a/lisp/php-mode.el b/lisp/php-mode.el index 917a28c7..e35b688f 100644 --- a/lisp/php-mode.el +++ b/lisp/php-mode.el @@ -72,6 +72,7 @@ (require 'etags) (require 'speedbar) (require 'imenu) +(require 'package) (require 'nadvice nil t) (require 'cl-lib) @@ -191,14 +192,6 @@ enabled." :tag "PHP Mode Do Not Use Semantic Imenu" :type 'boolean) -(defcustom php-completion-file "" - "Path to the file which contains the function names known to PHP." - :type 'string) - -(defcustom php-manual-path "" - "Path to the directory which contains the PHP manual." - :type 'string) - ;;;###autoload (if (version< emacs-version "24.4") (dolist (i '("php" "php5" "php7")) @@ -1399,130 +1392,6 @@ current `tags-file-name'." (message "Arglist for %s: %s" tagname arglist) (message "Unknown function: %s" tagname)))) -(defcustom php-search-documentation-browser-function nil - "Function to display PHP documentation in a WWW browser. - -If non-nil, this shadows the value of `browse-url-browser-function' when -calling `php-search-documentation' or `php-search-local-documentation'." - :group 'php - :tag "PHP Search Documentation Browser Function" - :type '(choice (const :tag "default" nil) function) - :link '(variable-link browse-url-browser-function)) - -(defun php-browse-documentation-url (url) - "Browse a documentation URL using the configured browser function. - -See `php-search-documentation-browser-function'." - (let ((browse-url-browser-function - (or php-search-documentation-browser-function - browse-url-browser-function))) - (browse-url url))) - -(defvar php-search-local-documentation-types - (list "function" "control-structures" "class" "book") - ;; "intro" and "ref" also look interesting, but for all practical purposes - ;; their terms are sub-sets of the "book" terms (with the few exceptions - ;; being very unlikely search terms). - "The set (and priority sequence) of documentation file prefixes -under which to search for files in the local documentation directory.") - -(defvar php-search-local-documentation-words-cache nil) - -(defun php--search-documentation-read-arg () - "Obtain interactive argument for searching documentation." - ;; Cache the list of documentation words available for completion, - ;; based on the defined types-of-interest. - (let ((types-list php-search-local-documentation-types) - (words-cache php-search-local-documentation-words-cache) - (local-manual (and (stringp php-manual-path) - (not (string= php-manual-path ""))))) - (when (and local-manual - (not (assq types-list words-cache))) - ;; Generate the cache on the first run, or if the types changed. - ;; We read the filenames matching our types list in the local - ;; documentation directory, and extract the 'middle' component - ;; of each. e.g. "function.array-map.html" => "array_map". - (let* ((types-opt (regexp-opt types-list)) - (pattern (concat "\\`" types-opt "\\.\\(.+\\)\\.html\\'")) - (collection - (mapcar (lambda (filename) (subst-char-in-string - ?- ?_ (replace-regexp-in-string - pattern "\\1" filename))) - (directory-files php-manual-path nil pattern)))) - ;; Replace the entire cache. If the types changed, we don't need - ;; to retain the collection for the previous value. - (setq words-cache (list (cons types-list collection))) - (setq php-search-local-documentation-words-cache words-cache))) - ;; By default we search for (current-word) immediately, without prompting. - ;; With a prefix argument, or if there is no (current-word), we perform a - ;; completing read for a word from the cached collection. - (let* ((default (current-word)) - (prompt (if default - (format "Search PHP docs (%s): " default) - "Search PHP docs: ")) - (collection (and local-manual - (cdr (assq types-list words-cache)))) - (word (if (or current-prefix-arg (not default)) - (completing-read prompt collection nil nil nil nil default) - default))) - ;; Return interactive argument list. - (list word)))) - -(defun php-search-local-documentation (word) - "Search the local PHP documentation (i.e. in `php-manual-path') for -the word at point. The function returns t if the requested documentation -exists, and nil otherwise. - -With a prefix argument, prompt (with completion) for a word to search for." - (interactive (php--search-documentation-read-arg)) - (let ((file (catch 'found - (cl-loop for type in php-search-local-documentation-types do - (let* ((doc-html (format "%s.%s.html" - type - (replace-regexp-in-string - "_" "-" (downcase word)))) - (file (expand-file-name doc-html php-manual-path))) - (when (file-exists-p file) - (throw 'found file))))))) - (when file - (let ((file-url (if (string-prefix-p "file://" file) - file - (concat "file://" file)))) - (php-browse-documentation-url file-url)) - t))) - -(defsubst php-search-web-documentation (word) - "Return URL to search PHP manual search by `WORD'." - (php-browse-documentation-url (concat (or php-search-url php-site-url) word))) - -;; Define function documentation function -(defun php-search-documentation (word) - "Search PHP documentation for the `WORD' at point. - -If `php-manual-path' has a non-empty string value then the command -will first try searching the local documentation. If the requested -documentation does not exist it will fallback to searching the PHP -website. - -With a prefix argument, prompt for a documentation word to search -for. If the local documentation is available, it is used to build -a completion list." - (interactive (php--search-documentation-read-arg)) - (if (and (stringp php-manual-path) - (not (string= php-manual-path ""))) - (or (php-search-local-documentation word) - (php-search-web-documentation word)) - (php-search-web-documentation word))) - -;; Define function for browsing manual -(defun php-browse-manual () - "Bring up manual for PHP." - (interactive) - (browse-url (if (stringp php-manual-url) - php-manual-url - (format "%smanual/%s/" php-site-url php-manual-url)))) - - ;; Font Lock (defconst php-phpdoc-type-keywords (list "string" "integer" "int" "boolean" "bool" "float" diff --git a/lisp/php.el b/lisp/php.el index 4844eec7..3cc23cfe 100644 --- a/lisp/php.el +++ b/lisp/php.el @@ -78,6 +78,70 @@ You can replace \"en\" with your ISO language code." :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) + +(defcustom php-manual-path "" + "Path to the directory which contains the PHP manual." + :type 'string) + +(defcustom php-search-documentation-function #'php-search-web-documentation + "Function to search PHP Manual at cursor position." + :group 'php + :tag "PHP Search Documentation Function" + :type '(choice (const :tag "Use online documentation" #'php-search-web-documentation) + (const :tag "Use local documentation" #'php-local-manual-search) + (function :tag "Use other function"))) + +(defcustom php-search-documentation-browser-function nil + "Function to display PHP documentation in a WWW browser. + +If non-nil, this shadows the value of `browse-url-browser-function' when +calling `php-search-documentation' or `php-search-local-documentation'." + :group 'php + :tag "PHP Search Documentation Browser Function" + :type '(choice (const :tag "default" nil) function) + :link '(variable-link browse-url-browser-function)) + +;; Define function for browsing manual +(defun php-browse-documentation-url (url) + "Browse a documentation URL using the configured browser function. + +See `php-search-documentation-browser-function'." + (let ((browse-url-browser-function + (or php-search-documentation-browser-function + browse-url-browser-function))) + (browse-url url))) + +(defun php-browse-manual () + "Bring up manual for PHP." + (interactive) + (browse-url (if (stringp php-manual-url) + php-manual-url + (format "%smanual/%s/" php-site-url php-manual-url)))) + +(defun php-search-web-documentation (word) + "Return URL to search PHP manual search by `WORD'." + (interactive (list (current-word))) + (php-browse-documentation-url (concat (or php-search-url php-site-url) word))) + +(defun php-search-documentation (&optional word) + "Search PHP documentation for the `WORD' at point. + +If `php-manual-path' has a non-empty string value then the command +will first try searching the local documentation. If the requested +documentation does not exist it will fallback to searching the PHP +website. + +With a prefix argument, prompt for a documentation word to search +for. If the local documentation is available, it is used to build +a completion list." + (interactive) + (if (called-interactively-p 'interactive) + (call-interactively php-search-documentation-function) + (funcall php-search-documentation-function word))) + (defcustom php-class-suffix-when-insert "::" "Suffix for inserted class." :group 'php