diff --git a/phpinspect-index.el b/phpinspect-index.el index 077091e..cfa642d 100644 --- a/phpinspect-index.el +++ b/phpinspect-index.el @@ -368,7 +368,16 @@ namespace if not provided" (previous nil :type phpinspect--queue-item :documentation - "The previous item in the queue")) + "The previous item in the queue") + (subscription nil + :type function + :read-only t + :documentation + "A function that should be called when items are + enqueued.")) + +(defsubst phpinspect--make-queue (&optional subscription) + (phpinspect--make-queue-item :subscription subscription)) (cl-defmethod phpinspect--queue-last ((item phpinspect--queue-item)) (if (phpinspect--queue-item-next item) @@ -381,27 +390,30 @@ namespace if not provided" item)) (cl-defmethod phpinspect--queue-enqueue ((item phpinspect--queue-item) thing) - (let ((last (phpinspect--queue-last item))) - (if (not (phpinspect--queue-item-thing last)) - (setf (phpinspect--queue-item-thing last) thing) - (setf (phpinspect--queue-item-next last) - (phpinspect--make-queue-item :previous last :thing thing))))) + (let ((last (phpinspect--queue-last item))) + (if (not (phpinspect--queue-item-thing last)) + (setf (phpinspect--queue-item-thing last) thing) + (setf (phpinspect--queue-item-next last) + (phpinspect--make-queue-item + :previous last + :thing thing + :subscription (phpinspect--queue-item-subscription item))))) + (funcall (phpinspect--queue-item-subscription item))) (cl-defmethod phpinspect--queue-dequeue ((item phpinspect--queue-item)) - (let* ((first (phpinspect--queue-first item)) - (thing (phpinspect--queue-item-thing first)) - (next (phpinspect--queue-item-next first))) - (when next (setf (phpinspect--queue-item-previous next) nil)) - (cond ((and (eq item first) (not next)) - (setf (phpinspect--queue-item-thing item) - nil)) - ((eq item first) - - (setf (phpinspect--queue-item-thing item) - (phpinspect--queue-item-thing next)) - (setf (phpinspect--queue-item-next item) - (phpinspect--queue-item-next next)))) - thing)) + (let* ((first (phpinspect--queue-first item)) + (thing (phpinspect--queue-item-thing first)) + (next (phpinspect--queue-item-next first))) + (when next (setf (phpinspect--queue-item-previous next) nil)) + (cond ((and (eq item first) (not next)) + (setf (phpinspect--queue-item-thing item) + nil)) + ((eq item first) + (setf (phpinspect--queue-item-thing item) + (phpinspect--queue-item-thing next)) + (setf (phpinspect--queue-item-next item) + (phpinspect--queue-item-next next)))) + thing)) (cl-defmethod phpinspect--queue-find ((item phpinspect--queue-item) thing comparison-func) @@ -423,7 +435,10 @@ namespace if not provided" (when (not (phpinspect--queue-find item thing comparison-func)) (phpinspect--queue-enqueue item thing))) -(defvar phpinspect--index-queue (phpinspect--make-queue-item) +(cl-defmethod phpinspect--queue-await-insert ((item phpinspect--queue-item)) + (condition-wait (phpinspect--queue-item-insert item))) + +(defvar phpinspect--index-queue (phpinspect--make-queue) "Queue with indexation tasks. Each task is a list, the car of which is a project directory path and the cadr of which is an instance of `phpinspect--type`.") @@ -436,33 +451,46 @@ namespace if not provided" (defun phpinspect--index-thread-function () (while phpinspect--index-thread-running - (let* ((task (phpinspect--queue-dequeue phpinspect--index-queue)) - (mx (make-mutex)) - (continue (make-condition-variable mx)) - (skip-pause)) - (when task - (phpinspect--log "Indexing class %s for project in %s from index thread" - (phpinspect--index-task-type task) - (phpinspect--index-task-project-root task)) - - (let ((project (phpinspect--cache-get-project-create - (phpinspect--get-or-create-global-cache) - (phpinspect--index-task-project-root task))) - (is-native-type (phpinspect--type-is-native - (phpinspect--index-task-type task)))) - (if is-native-type - (progn - (phpinspect--log "Skipping indexation of native type %s" - (phpinspect--index-task-type task)) - (setq skip-pause t)) - (let ((type-index (phpinspect--index-type - project - (phpinspect--index-task-type task)))) - (when type-index (phpinspect--project-add-class project type-index)))))) - - (unless skip-pause - (phpinspect--index-thread-pause 1 mx continue)) - (setq skip-pause nil))) + ;; This error is used to wake up the thread when new tasks are added to the + ;; queue. + (ignore-error 'phpinspect--wakeup-thread + (let* ((task (phpinspect--queue-dequeue phpinspect--index-queue)) + (mx (make-mutex)) + (continue (make-condition-variable mx)) + (skip-pause)) + (if task + (progn + (phpinspect--log "Indexing class %s for project in %s from index thread" + (phpinspect--index-task-type task) + (phpinspect--index-task-project-root task)) + + (let ((project (phpinspect--cache-get-project-create + (phpinspect--get-or-create-global-cache) + (phpinspect--index-task-project-root task))) + (is-native-type (phpinspect--type-is-native + (phpinspect--index-task-type task)))) + (if is-native-type + (progn + (phpinspect--log "Skipping indexation of native type %s" + (phpinspect--index-task-type task)) + + ;; We can skip pausing when a native type is encountered + ;; and skipped, as we haven't done any intensive work that + ;; may cause hangups. + (setq skip-pause t)) + (let ((type-index (phpinspect--index-type + project + (phpinspect--index-task-type task)))) + (when type-index (phpinspect--project-add-class project type-index)))))) + + ;; else: join with the main thread until wakeup is signaled + (thread-join main-thread)) + + ;; Pause for a second after indexing something, to allow user input to + ;; interrupt the thread. + (unless skip-pause + (phpinspect--index-thread-pause 1 mx continue)) + (setq skip-pause nil)))) (phpinspect--log "Index thread exiting") (message "phpinspect index thread exited")) @@ -475,10 +503,18 @@ namespace if not provided" (with-mutex mx (condition-wait continue)) (phpinspect--log "Index thread continuing")) +(define-error 'phpinspect--wakeup-thread + "This error is used to wakeup the index thread") + +(defun phpinspect--wakeup-index-thread () + (when (thread--blocker phpinspect--index-thread) + (thread-signal phpinspect--index-thread 'phpinspect--wakeup-thread nil))) + (defun phpinspect--ensure-index-thread () (interactive) (when (or (not phpinspect--index-thread) (not (thread-alive-p phpinspect--index-thread))) + (setq phpinspect--index-queue (phpinspect--make-queue #'phpinspect--wakeup-index-thread)) (setq phpinspect--index-thread-running t) (setq phpinspect--index-thread (make-thread #'phpinspect--index-thread-function "phpinspect-index-thread")))) diff --git a/phpinspect-project.el b/phpinspect-project.el index 4783794..313dc07 100644 --- a/phpinspect-project.el +++ b/phpinspect-project.el @@ -51,6 +51,29 @@ indexed classes in the project") (phpinspect--function-return-type method)) #'phpinspect--index-task=)))) +(cl-defmethod phpinspect--project-add-variable-types-to-index-queue + ((project phpinspect--project) variables) + (dolist (var variables) + (when (phpinspect--variable-type var) + (phpinspect--queue-enqueue-noduplicate phpinspect--index-queue + (phpinspect--make-index-task + (phpinspect--project-root project) + (phpinspect--variable-type var)) + #'phpinspect--index-task=)))) + +(cl-defmethod phpinspect--project-add-class-attribute-types-to-index-queue + ((project phpinspect--project) (class phpinspect--class)) + (phpinspect--project-add-return-types-to-index-queueue + project + (phpinspect--class-get-method-list class)) + (phpinspect--project-add-return-types-to-index-queueue + project + (phpinspect--class-get-static-method-list class)) + (phpinspect--project-add-variable-types-to-index-queue + project + (phpinspect--class-variables class))) + + (cl-defmethod phpinspect--project-add-class ((project phpinspect--project) (indexed-class (head phpinspect--indexed-class))) (let* ((class-name (phpinspect--type-name-symbol @@ -60,15 +83,15 @@ indexed classes in the project") (if existing-class (progn (phpinspect--class-set-index existing-class indexed-class) - (phpinspect--project-add-return-types-to-index-queueue + (phpinspect--project-add-class-attribute-types-to-index-queue project - (phpinspect--class-get-method-list existing-class))) + existing-class)) (let ((new-class (phpinspect--make-class-generated :project project))) (phpinspect--class-set-index new-class indexed-class) (puthash class-name new-class (phpinspect--project-class-index project)) - (phpinspect--project-add-return-types-to-index-queueue + (phpinspect--project-add-class-attribute-types-to-index-queue project - (phpinspect--class-get-method-list new-class)))))) + new-class))))) (cl-defgeneric phpinspect--project-get-class ((project phpinspect--project) (class-fqn phpinspect--type))