diff --git a/company-phpactor.el b/company-phpactor.el index b1cb66e..b079c13 100644 --- a/company-phpactor.el +++ b/company-phpactor.el @@ -32,6 +32,17 @@ (require 'company) (require 'phpactor) +(defgroup company-phpactor nil + "Company backend for Phpactor." + :prefix "company-phpactor-" + :group 'company + :group 'phpactor) + +(defcustom company-phpactor-request-async t + "When non-NIL, asynchronous recuest to Phpactor." + :type 'boolean + :group 'company-phpactor) + (defun company-phpactor--grab-symbol () "If point is at the end of a symbol, return it. Otherwise, if point is not inside a symbol, return an empty string. @@ -51,9 +62,9 @@ Here we create a temporary syntax table in order to add $ to symbols." (let ((response (phpactor--rpc "complete" (phpactor--command-argments :source :offset)))) (plist-get (plist-get (plist-get response :parameters) :value) :suggestions))) -(defun company-phpactor--get-candidates () - "Build a list of candidates with text-properties extracted from phpactor's output." - (let ((suggestions (company-phpactor--get-suggestions)) candidate) +(defun company-phpactor--get-candidates (suggestions) + "Build a list of candidates with text-properties extracted from phpactor's output `SUGGESTIONS'." + (let (candidate) (mapcar (lambda (suggestion) (setq candidate (plist-get suggestion :name)) @@ -75,6 +86,17 @@ Here we create a temporary syntax table in order to add $ to symbols." "Show additional info (ARG) from phpactor as lateral annotation." (message (concat " " (get-text-property 0 'annotation arg)))) +(defun company-phpactor--get-candidates-async (callback) + "Get completion candidates asynchronously calling `CALLBACK' by Phpactor." + (if (not company-phpactor-request-async) + (funcall callback (company-phpactor--get-candidates (company-phpactor--get-suggestions))) + (phpactor--rpc-async "complete" (phpactor--command-argments :source :offset) + (lambda (proc) + (let* ((response (phpactor--parse-json (process-buffer proc))) + (suggestions + (plist-get (plist-get (plist-get response :parameters) :value) :suggestions))) + (funcall callback (company-phpactor--get-candidates suggestions))))))) + ;;;###autoload (defun company-phpactor (command &optional arg &rest ignored) "`company-mode' completion backend for Phpactor." @@ -87,7 +109,7 @@ Here we create a temporary syntax table in order to add $ to symbols." (`annotation (company-phpactor--annotation arg)) (`interactive (company-begin-backend 'company-phpactor)) (`prefix (company-phpactor--grab-symbol)) - (`candidates (company-phpactor--get-candidates)))))) + (`candidates (cons :async #'company-phpactor--get-candidates-async)))))) (provide 'company-phpactor) ;;; company-phpactor.el ends here diff --git a/phpactor.el b/phpactor.el index fadf597..e608137 100644 --- a/phpactor.el +++ b/phpactor.el @@ -7,7 +7,7 @@ ;; Created: 8 Apr 2018 ;; Version: 0.1.0 ;; Keywords: tools, php -;; Package-Requires: ((emacs "24.4") (cl-lib "0.5") (f "0.17") (php-runtime "0.2") (composer "0.1")) +;; Package-Requires: ((emacs "24.4") (cl-lib "0.5") (f "0.17") (php-runtime "0.2") (composer "0.1") (async "1.9.3")) ;; URL: https://github.com/emacs-php/phpactor.el ;; License: GPL-3.0-or-later @@ -52,6 +52,7 @@ (require 'ring) (require 'subr-x) (require 'composer) +(require 'async) ;; Custom variables ;;;###autoload @@ -223,6 +224,21 @@ have to ensure a compatible version of phpactor is used." (call-process-region (point-min) (point-max) phpactor-executable nil output nil "rpc" (format "--working-dir=%s" default-directory)) (phpactor--parse-json output)))) +(defun phpactor--rpc-async (action arguments callback) + "Async execute Phpactor `ACTION' subcommand with `ARGUMENTS' and calling `CALLBACK' after process." + (declare (indent 2)) + (phpactor--add-history 'phpactor--rpc-async (list action arguments)) + (let* ((json (phpactor--serialize-json (list :action action + :parameters arguments))) + (coding-system-for-write 'utf-8) + (default-directory (phpactor-get-working-dir)) + (executable phpactor-executable) + (proc (async-start-process + "phpactor-async" executable callback + "rpc" (format "--working-dir=%s" default-directory)))) + (process-send-string proc json) + (process-send-eof proc))) + (defun phpactor--parse-json (buffer) "Read JSON string from BUFFER." (with-current-buffer buffer