From cdd23d34b0849940e55022f524f148565f7fe8b8 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Thu, 11 Mar 2021 13:31:12 +0900 Subject: [PATCH 1/6] Impl PHP-UI --- lisp/php-ui-phpactor.el | 63 +++++++++++++++ lisp/php-ui.el | 174 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 237 insertions(+) create mode 100644 lisp/php-ui-phpactor.el create mode 100644 lisp/php-ui.el diff --git a/lisp/php-ui-phpactor.el b/lisp/php-ui-phpactor.el new file mode 100644 index 00000000..e5e5c8eb --- /dev/null +++ b/lisp/php-ui-phpactor.el @@ -0,0 +1,63 @@ +;;; php-ui-phpactor.el --- UI support for PHP developing -*- lexical-binding: t; -*- + +;; Copyright (C) 2022 Friends of Emacs-PHP development + +;; Author: USAMI Kenta +;; Keywords: tools, files +;; URL: https://github.com/emacs-php/php-mode +;; Version: 1.24.0 +;; 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: + +;; PHP-UI implementation to integrate Phpactor (phpactor.el). + +;;; Code: +(require 'phpactor nil t) +(require 'popup nil t) + +(defvar-local php-ui-phpactor-buffer nil + ".") + +(defvar-local php-ui-phpactor-last-hover-pos nil + ".") + +(defvar php-ui-phpactor-timer nil + ".") + +(defun php-ui-phpactor-hover () + "" + (interactive) + (when (and php-ui-phpactor-buffer (not (eq (point) php-ui-phpactor-last-hover-pos))) + (setq php-ui-phpactor-last-hover-pos (point)) + (popup-tip (phpactor-hover)))) + +;;;###autoload +(defun php-ui-phpactor-activate () + "" + (interactive) + (unless php-ui-phpactor-timer + (setq php-ui-phpactor-timer (run-with-timer 1.0 5 #'php-ui-phpactor-hover))) + (setq php-ui-phpactor-buffer t)) + +;;;###autoload +(defun php-ui-phpactor-deactivate () + "" + (interactive) + (setq php-ui-phpactor-buffer nil)) + +(provide 'php-ui-phpactor) +;;; php-ui-phpactor.el ends here diff --git a/lisp/php-ui.el b/lisp/php-ui.el new file mode 100644 index 00000000..3c916eaf --- /dev/null +++ b/lisp/php-ui.el @@ -0,0 +1,174 @@ +;;; php-ui.el --- UI support for PHP development -*- lexical-binding: t; -*- + +;; Copyright (C) 2022 Friends of Emacs-PHP development + +;; Author: USAMI Kenta +;; Keywords: tools, files +;; URL: https://github.com/emacs-php/php-mode +;; Version: 1.24.0 +;; 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: + +;; PHP Mode integrates LSP Mode (lsp-mode), Phpactor (phpactor.el) and IDE-like tools. +;; +;; **Note**: +;; This feature is under development and experimental. +;; All of these functions, modes and terms are subject to change without notice. +;; +;; ## Motivations +;; +;; There are some IDE-like features / packages for PHP development. +;; PHP-UI bridges projects and their IDE-like features. +;; +;; ## IDE Features +;; +;; We don't recommend features, but bundle some feature bridges. +;; They are sorted alphabetically except "none." +;; +;; - none +;; Does not launch any IDE features. +;; - lsp-mode +;; https://emacs-lsp.github.io/lsp-mode/ +;; https://github.com/emacs-lsp/lsp-mode +;; - phpactor +;; https://phpactor.readthedocs.io/ +;; https://github.com/phpactor/phpactor +;; https://github.com/emacs-php/phpactor.el +;; +;; ## Configuration +;; +;; Put follows code into your .emacs (~/.emacs.d/init.el) file: +;; +;; (defun my-php-mode-setup () +;; (add-hook 'hack-local-variables-hook #'php-ui-mode t t)) +;; +;; (with-eval-after-load 'php-ui +;; (custom-set-variables +;; '(php-ui-feature 'eglot) ;; or 'none, 'phpactor, 'lsp-mode +;; '(php-ui-eglot-executable '("psalm-language-server")) ;; or "intelephense", '("php" "vendor/bin/path/to/server") +;; ;; If you want to hide php-ui-mode from the mode line, set an empty string +;; '(php-ui-mode-lighter "")) +;; +;; ;; Only Eglot users +;; (add-to-list 'php-ui-eglot-executable '(php-mode . php-ui-eglot-server-program)) +;; +;; (add-hook 'php-mode #'my-php-mode-setup)) +;; +;; If you don't enable IDE support by default, set '(php-ui-feature 'none) +;; +;; ### For per project configuration +;; +;; Put follows code into .dir-locals.el in project directory: +;; +;; ((nil (php-project-root . git) +;; (php-ui-eglot-executable . ("psalm-language-server")) +;; ;; or (php-ui-eglot-executable . ("php" "vendor/bin/path/to/server")) +;; (php-ui-feature . lsp-mode))) +;; +;; If you can't put .dir-locals.el in your project directory, consider the sidecar-locals package. +;; https://melpa.org/#/sidecar-locals +;; https://gitlab.com/ideasman42/emacs-sidecar-locals +;; + +;;; Code: +(eval-when-compile + (require 'php-ui-phpactor)) + +(defvar php-ui-feature-alist + '((none :test (lambda () t) + :activate (lambda () t) + :deactivate (lambda () t)) + (phpactor :test (lambda () (and (require 'phpactor nil t) (featurep 'phpactor))) + :activate php-ui-phpactor-activate + :deactivate php-ui-phpactor-activate) + (lsp-mode :test (lambda () (and (require 'lsp nil t) (featurep 'lsp))) + :activate lsp + :deactivate lsp-workspace-shutdown))) + +(defgroup php-ui nil + "UI support for PHP developing." + :tag "PHP-UI" + :prefix "php-ui-" + :group 'php) + +(defcustom php-ui-feature nil + "A symbol of PHP-UI feature" + :tag "PHP-UI Feature" + :group 'php-ui + :type 'symbol + :safe #'symbolp) + +(defcustom php-ui-mode-lighter " PHP-UI" + "A symbol of PHP-UI feature" + :tag "PHP-UI Mode Lighter" + :group 'php-ui + :type 'string + :safe #'stringp) + +;;;###autoload +(define-minor-mode php-ui-mode + "Minor mode for integrate IDE-like tools." + :lighter php-ui-mode-lighter + (let ((ui-plist (cdr-safe (assq php-ui-feature php-ui-feature-alist)))) + (if (null ui-plist) + (message "Please set `php-ui-feature' variable in .dir-locals.el or custom variable") + (if php-ui-mode + (php-ui--activate-buffer ui-plist) + (php-ui--deactivate-buffer ui-plist))))) + +;;;###autoload +(defun php-ui (feature) + "Select a PHP-UI feature and execute `php-ui-mode'." + (interactive (list (php-ui--select-feature))) + (unless feature + (user-error "No PHP-UI feature is installed. Install the lsp-mode, eglot or phpactor package")) + (unless (assq feature php-ui-feature-alist) + (user-error "`%s' does not include in available PHP-UI features. (%s)" + feature + (mapconcat #'symbol-name (php-ui--avilable-features) ", "))) + (when (and php-ui-mode feature php-ui-feature + (not (eq php-ui-feature php-ui-feature))) + (php-ui-mode -1)) + (let ((php-ui-feature feature)) + (php-ui-mode +1))) + +(defun php-ui--activate-buffer (ui-plist) + "Activate php-ui implementation by UI-PLIST." + (funcall (plist-get ui-plist :activate))) + +(defun php-ui--deactivate-buffer (ui-plist) + "Deactivate php-ui implementation by UI-PLIST." + (funcall (plist-get ui-plist :deactivate))) + +(defun php-ui--avilable-features () + "Return list of available PHP-UI features." + (cl-loop for (ui . plist) in php-ui-feature-alist + if (funcall (plist-get plist :test)) + collect ui)) + +(defun php-ui--select-feature () + "Choose PHP-UI feature" + (let* ((features (php-ui--avilable-features)) + (count (length features))) + (cond + ((eq count 0) nil) + ((eq count 1) (car features)) + (t + (intern (completing-read "Select PHP-UI feature: " features nil t)))))) + +(provide 'php-ui) +;;; php-ui.el ends here From a5d24aa20c770dc815cda6061036e9f6444149b8 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Thu, 11 Mar 2021 22:27:28 +0900 Subject: [PATCH 2/6] Impl php-ui-phpactor-hover --- lisp/php-ui-phpactor.el | 42 +++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/lisp/php-ui-phpactor.el b/lisp/php-ui-phpactor.el index e5e5c8eb..fd2f6bb4 100644 --- a/lisp/php-ui-phpactor.el +++ b/lisp/php-ui-phpactor.el @@ -29,34 +29,52 @@ (require 'phpactor nil t) (require 'popup nil t) -(defvar-local php-ui-phpactor-buffer nil - ".") +(defvar-local php-ui-phpactor-buffer nil) +(defvar-local php-ui-phpactor-hover-last-pos nil) +(defvar-local php-ui-phpactor-hover-last-msg nil) -(defvar-local php-ui-phpactor-last-hover-pos nil - ".") +(declare-function phpactor--command-argments (&rest arg-keys)) +(declare-function phpactor--parse-json (buffer)) +(declare-function phpactor--rpc-async "phpactor" (action arguments callback)) +(declare-function phpactor-goto-definition "phpactor" ()) +(declare-function popup-tip "popup" (string)) (defvar php-ui-phpactor-timer nil - ".") + "Timer object for execute Phpactor and display hover message.") (defun php-ui-phpactor-hover () - "" + "Show brief information about the symbol underneath the cursor." (interactive) - (when (and php-ui-phpactor-buffer (not (eq (point) php-ui-phpactor-last-hover-pos))) - (setq php-ui-phpactor-last-hover-pos (point)) - (popup-tip (phpactor-hover)))) + (when php-ui-phpactor-buffer + (if (eq (point) php-ui-phpactor-hover-last-pos) + (when php-ui-phpactor-hover-last-msg + (let ((msg php-ui-phpactor-hover-last-msg)) + (setq php-ui-phpactor-hover-last-msg nil) + (popup-tip msg))) + (setq php-ui-phpactor-hover-last-pos (point)) + (let ((main-buffer (current-buffer))) + (phpactor--rpc-async "hover" (phpactor--command-argments :source :offset) + (lambda (proc) + (let* ((response (phpactor--parse-json (process-buffer proc))) + (msg (plist-get (plist-get response :parameters) :message))) + (with-current-buffer main-buffer + (setq php-ui-phpactor-hover-last-msg msg))))))))) ;;;###autoload (defun php-ui-phpactor-activate () - "" + "Activate PHP-UI using phpactor.el." (interactive) (unless php-ui-phpactor-timer - (setq php-ui-phpactor-timer (run-with-timer 1.0 5 #'php-ui-phpactor-hover))) + (setq php-ui-phpactor-timer (run-with-timer 1.0 1 #'php-ui-phpactor-hover))) (setq php-ui-phpactor-buffer t)) ;;;###autoload (defun php-ui-phpactor-deactivate () - "" + "Dectivate PHP-UI using phpactor.el." (interactive) + (when php-ui-phpactor-timer + (cancel-timer php-ui-phpactor-timer) + (setq php-ui-phpactor-timer nil)) (setq php-ui-phpactor-buffer nil)) (provide 'php-ui-phpactor) From 2c77d5905dbe959d280629cb464a214b3dca6770 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Thu, 11 Mar 2021 23:06:38 +0900 Subject: [PATCH 3/6] Impl code jump using smart-jump using PHP-UI Phpactor --- lisp/php-ui-phpactor.el | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lisp/php-ui-phpactor.el b/lisp/php-ui-phpactor.el index fd2f6bb4..ea501d09 100644 --- a/lisp/php-ui-phpactor.el +++ b/lisp/php-ui-phpactor.el @@ -28,6 +28,7 @@ ;;; Code: (require 'phpactor nil t) (require 'popup nil t) +(require 'smart-jump nil t) (defvar-local php-ui-phpactor-buffer nil) (defvar-local php-ui-phpactor-hover-last-pos nil) @@ -64,6 +65,11 @@ (defun php-ui-phpactor-activate () "Activate PHP-UI using phpactor.el." (interactive) + (if (not (fboundp 'smart-jump-go)) + (local-set-key [remap xref-find-definitions] #'phpactor-goto-definition) + (local-set-key [remap xref-find-definitions] #'smart-jump-go) + (local-set-key [remap xref-pop-marker-stack] #'smart-jump-back) + (local-set-key [remap xref-find-references] #'smart-jump-references)) (unless php-ui-phpactor-timer (setq php-ui-phpactor-timer (run-with-timer 1.0 1 #'php-ui-phpactor-hover))) (setq php-ui-phpactor-buffer t)) @@ -72,6 +78,10 @@ (defun php-ui-phpactor-deactivate () "Dectivate PHP-UI using phpactor.el." (interactive) + (local-unset-key [remap xref-find-definitions]) + (local-unset-key [remap xref-pop-marker-stack]) + (local-unset-key [remap xref-find-references]) + (when php-ui-phpactor-timer (cancel-timer php-ui-phpactor-timer) (setq php-ui-phpactor-timer nil)) From fff7ed90abaed789ea6de689959a107652505822 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Mon, 19 Apr 2021 08:27:12 +0900 Subject: [PATCH 4/6] Load cask when compile --- Cask | 4 ++++ Makefile | 8 ++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Cask b/Cask index d992fad3..76702c32 100644 --- a/Cask +++ b/Cask @@ -8,9 +8,13 @@ "lisp/php-face.el" "lisp/php-project.el" "lisp/php-local-manual.el" + "lisp/php-ui-phpactor.el" + "lisp/php-ui.el" "lisp/php-mode-debug.el") (development + ;;(depends-on "lsp-mode") + (depends-on "phpactor") (depends-on "pkg-info") (depends-on "projectile") (depends-on "smart-jump") diff --git a/Makefile b/Makefile index 2bad67e0..650eb44f 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,15 @@ EMACS ?= emacs CASK ?= cask -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 +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-ui.el lisp/php-ui-phpactor.el lisp/php-mode-debug.el AUTOLOADS = php-mode-autoloads.el ELCS = $(ELS:.el=.elc) %.elc: %.el - $(EMACS) -Q -batch -L lisp/ -f batch-byte-compile $< + $(EMACS) -Q -batch -L lisp/ --eval \ + "(let ((default-directory (expand-file-name \".cask\" default-directory))) \ + (require 'package) \ + (normal-top-level-add-subdirs-to-load-path))" \ + -f package-initialize -f batch-byte-compile $< all: autoloads $(ELCS) authors From 40c3a92f8a935508691b627dc608d47ee3860325 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Mon, 19 Apr 2021 08:28:13 +0900 Subject: [PATCH 5/6] Use run-with-idle-timer instead of run-with-timer --- lisp/php-ui-phpactor.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/php-ui-phpactor.el b/lisp/php-ui-phpactor.el index ea501d09..944daa6a 100644 --- a/lisp/php-ui-phpactor.el +++ b/lisp/php-ui-phpactor.el @@ -71,7 +71,7 @@ (local-set-key [remap xref-pop-marker-stack] #'smart-jump-back) (local-set-key [remap xref-find-references] #'smart-jump-references)) (unless php-ui-phpactor-timer - (setq php-ui-phpactor-timer (run-with-timer 1.0 1 #'php-ui-phpactor-hover))) + (setq php-ui-phpactor-timer (run-with-idle-timer 1.0 1 #'php-ui-phpactor-hover))) (setq php-ui-phpactor-buffer t)) ;;;###autoload From 1184e0ec05a647b8cb24a4ff033e6e62f3cbe99c Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Fri, 30 Apr 2021 16:37:59 +0900 Subject: [PATCH 6/6] Add Eglot activation to php-ui.el --- lisp/php-ui.el | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/lisp/php-ui.el b/lisp/php-ui.el index 3c916eaf..530931db 100644 --- a/lisp/php-ui.el +++ b/lisp/php-ui.el @@ -41,6 +41,8 @@ ;; ;; - none ;; Does not launch any IDE features. +;; - eglot +;; https://github.com/joaotavora/eglot ;; - lsp-mode ;; https://emacs-lsp.github.io/lsp-mode/ ;; https://github.com/emacs-lsp/lsp-mode @@ -95,6 +97,9 @@ (phpactor :test (lambda () (and (require 'phpactor nil t) (featurep 'phpactor))) :activate php-ui-phpactor-activate :deactivate php-ui-phpactor-activate) + (eglot :test (lambda () (and (require 'eglot nil t) (featurep 'eglot))) + :activate eglot-ensure + :deactivate eglot--managed-mode-off) (lsp-mode :test (lambda () (and (require 'lsp nil t) (featurep 'lsp))) :activate lsp :deactivate lsp-workspace-shutdown))) @@ -105,6 +110,13 @@ :prefix "php-ui-" :group 'php) +(defcustom php-ui-eglot-executable nil + "A symbol of PHP-UI feature" + :tag "PHP-UI Eglot Executable" + :group 'php-ui + :type '(repeat string) + :safe (lambda (v) (or (stringp v) (listp v)))) + (defcustom php-ui-feature nil "A symbol of PHP-UI feature" :tag "PHP-UI Feature" @@ -146,6 +158,16 @@ (let ((php-ui-feature feature)) (php-ui-mode +1))) +;;;###autoload +(defun php-ui-eglot-server-program () + "Return a list of command to execute LSP Server." + (if (stringp php-ui-eglot-executable) + (list php-ui-eglot-executable) + php-ui-eglot-executable)) + +(defun php-ui--eglot-current-server () + (php-project-get-root-dir)) + (defun php-ui--activate-buffer (ui-plist) "Activate php-ui implementation by UI-PLIST." (funcall (plist-get ui-plist :activate)))