branch: externals/javaimp commit 43013717e824b662cf14e76102439cd71c3fdd58 Author: Filipp Gunbin <fgun...@fastmail.fm> Commit: Filipp Gunbin <fgun...@fastmail.fm>
Introduce javaimp-source-file-cache and use it --- javaimp-util.el | 46 +++++++++++++++++++++++++++++++++-------- javaimp.el | 64 ++++++++++++++++++++++++++++++--------------------------- 2 files changed, 72 insertions(+), 38 deletions(-) diff --git a/javaimp-util.el b/javaimp-util.el index a4569b9..639474a 100644 --- a/javaimp-util.el +++ b/javaimp-util.el @@ -80,7 +80,7 @@ build tool output. Can be let-bound to nil to suppress copying.") (cl-defstruct javaimp-id group artifact version) -(cl-defstruct javaimp-cached-jar ;jar or jmod +(cl-defstruct javaimp-cached-file file read-ts classes) (cl-defstruct javaimp-scope @@ -90,6 +90,11 @@ build tool output. Can be let-bound to nil to suppress copying.") open-brace parent) +(defsubst javaimp-print-id (id) + (format "%s:%s:%s" + (javaimp-id-artifact id) + (javaimp-id-group id) + (javaimp-id-version id))) ;; Xml @@ -246,17 +251,42 @@ additionally tested by PRED." -;; Other - -(defsubst javaimp-print-id (id) - (format "%s:%s:%s" - (javaimp-id-artifact id) - (javaimp-id-group id) - (javaimp-id-version id))) +;; Files & caches (defsubst javaimp--get-file-ts (file) (nth 5 (file-attributes file))) +(defun javaimp--get-file-classes-cached (file cache-sym class-reader) + "Return list of classes for FILE. Use CACHE-SYM as a cache, it +should be an alist with elements of the form (FILE +. CACHED-FILE). If not found in cache, or the cache is outdated, +then classes are read using CLASS-READER, which should be a +function of one argument, a FILE. If that function throws an +error, the cache for FILE is cleared." + (condition-case err + (let ((cached-file + (alist-get file (symbol-value cache-sym) nil nil #'string=))) + (when (or (not cached-file) + ;; If the file doesn't exist this will be current + ;; time, and thus condition always true + (> (float-time (javaimp--get-file-ts file)) + (float-time (javaimp-cached-file-read-ts cached-file)))) + (setq cached-file (make-javaimp-cached-file + :file file + :read-ts (javaimp--get-file-ts file) + :classes (funcall class-reader file)))) + (setf (alist-get file (symbol-value cache-sym) nil 'remove #'string=) + cached-file) + (javaimp-cached-file-classes cached-file)) + (t + ;; Clear on any error + (setf (alist-get file (symbol-value cache-sym) nil 'remove #'string=) nil) + (signal (car err) (cdr err))))) + + + +;; System + ;; TODO use functions `cygwin-convert-file-name-from-windows' and ;; `cygwin-convert-file-name-to-windows' when they are available ;; instead of calling `cygpath'. See diff --git a/javaimp.el b/javaimp.el index e2a1e37..cbd1283 100644 --- a/javaimp.el +++ b/javaimp.el @@ -75,6 +75,7 @@ (require 'javaimp-maven) (require 'javaimp-gradle) (require 'javaimp-parse) +(require 'javaimp-util) (require 'cc-mode) ;for java-mode-syntax-table (require 'imenu) @@ -184,9 +185,15 @@ A handler function takes one argument, a FILE.") (defvar javaimp-project-forest nil "Visited projects") -(defvar javaimp-jar-cache nil - "Jar cache, an alist of (FILE . JAR), where FILE is expanded -file name and JAR is javaimp-cached-jar struct.") +(defvar javaimp-jar-file-cache nil + "Jar file cache, an alist of (FILE . CACHED-FILE), where FILE is +expanded file name and CACHED-FILE is javaimp-cached-file +struct.") + +(defvar javaimp-source-file-cache nil + "Source file cache, an alist of (FILE . CACHED-FILE), where FILE +is expanded file name and CACHED-FILE is javaimp-cached-file +struct.") (defvar javaimp-syntax-table (make-syntax-table java-mode-syntax-table) ;TODO don't depend @@ -267,14 +274,14 @@ any module's source file." (message "Loaded project from %s" file)))) -;; Dependency jars +;; Dependencies (defun javaimp--update-module-maybe (node) (let ((module (javaimp-node-contents node)) need-update ids) ;; check if deps are initialized (unless (javaimp-module-dep-jars module) - (message "Loading dependencies for module: %s" (javaimp-module-id module)) + (message "Will load dependencies for %s" (javaimp-module-id module)) (setq need-update t)) ;; check if this or any parent build file has changed since we ;; loaded the module @@ -303,22 +310,10 @@ any module's source file." (current-time))))) (defun javaimp--get-jar-classes (file) - (condition-case err - (let ((jar (alist-get file javaimp-jar-cache nil nil #'equal))) - (when (or (not jar) - ;; If the file doesn't exist this will be current - ;; time, and thus condition always true - (> (float-time (javaimp--get-file-ts file)) - (float-time (javaimp-cached-jar-read-ts jar)))) - (setq jar (make-javaimp-cached-jar - :file file - :read-ts (javaimp--get-file-ts file) - :classes (javaimp--read-jar-classes file)))) - (setf (alist-get file javaimp-jar-cache) jar) - (javaimp-cached-jar-classes jar)) - (t - (setf (alist-get file javaimp-jar-cache nil 'remove #'equal) nil) - (signal (car err) (cdr err))))) + (javaimp--get-file-classes-cached + file + 'javaimp-jar-file-cache + #'javaimp--read-jar-classes)) (defun javaimp--read-jar-classes (file) "Read FILE which should be a .jar or a .jmod and return classes @@ -502,20 +497,28 @@ If there's no such directive, then the last resort is just (defun javaimp--get-file-classes (file) (if-let ((buf (get-file-buffer file))) + ;; Don't use cache, just collect what we have in buffer (with-current-buffer buf (save-excursion (save-restriction (widen) (javaimp--get-buffer-classes)))) - (with-temp-buffer - (insert-file-contents file) - ;; We need only class-likes, and this is temp buffer, so for - ;; efficiency avoid parsing anything else - (let ((javaimp--parse-scope-hook #'javaimp--parse-scope-class)) - (javaimp--get-buffer-classes))))) + (javaimp--get-file-classes-cached + file + 'javaimp-source-file-cache + #'javaimp--read-source-classes))) + +(defun javaimp--read-source-classes (file) + (with-temp-buffer + (insert-file-contents file) + ;; We need only class-likes, and this is temp buffer, so for + ;; efficiency avoid parsing anything else + (let ((javaimp--parse-scope-hook #'javaimp--parse-scope-class)) + (javaimp--get-buffer-classes)))) (defun javaimp--get-buffer-classes () - "Return fully-qualified names of all class-like scopes." + "Return fully-qualified names of all class-like scopes in the +current buffer." (let ((package (javaimp--parse-get-package)) (scopes (javaimp--parse-get-all-scopes (lambda (scope) @@ -815,8 +818,9 @@ start (`javaimp-scope-start') instead." (defun javaimp-flush-cache () "Flush all caches." - (setq javaimp-jar-cache nil)) - + (interactive) + (setq javaimp-jar-file-cache nil + javaimp-source-file-cache nil)) (provide 'javaimp)