From d4e9e269dd0c867e3bf8a6645fede2fe51308ecb Mon Sep 17 00:00:00 2001
From: Eshel Yaron <me@eshelyaron.com>
Date: Thu, 16 Feb 2023 14:34:45 +0200
Subject: [PATCH] ADDED: mode line indication for loaded buffers

* sweep.pl (sweep_source_file_load_time/2): new predicate.
(sweep_load_buffer/2): also update source modification time based.
* sweeprolog.el (sweeprolog-buffer-load-time)
(sweeprolog-buffer-loaded-since-last-modification-p): new functions.
(sweeprolog-load-buffer): use it.
(sweeprolog-mode): add mode line indication if buffer is loaded.
---
 README.org    | 10 +++++-----
 sweep.pl      | 15 ++++++++++-----
 sweeprolog.el | 42 +++++++++++++++++++++++++++++++++++-------
 3 files changed, 50 insertions(+), 17 deletions(-)

diff --git a/README.org b/README.org
index 3644f12..8765342 100644
--- a/README.org
+++ b/README.org
@@ -1308,6 +1308,11 @@ buffer otherwise.  To choose a different buffer to load while visiting
 a ~sweeprolog-mode~ buffer, invoke ~sweeprolog-load-buffer~ with a prefix
 argument (~C-u C-c C-l~).
 
+The mode line displays the work "Loaded" next to the "Sweep" major
+mode indicator if the current buffer has is loaded and it hasn't been
+modified since.  See [[info:emacs#Mode Line][Mode Line]] in the Emacs manual for more
+information about the mode line.
+
 More relevant information about loading code in SWI-Prolog can be
 found in [[https://www.swi-prolog.org/pldoc/man?section=consulting][Loading Prolog source files]] in the SWI-Prolog manual.
 
@@ -2513,11 +2518,6 @@ some improvements remain to be pursued:
   modifications, but careful consideration is required to make sure
   ~sweeprolog-mode~ overrides all conflicting ~prolog-mode~ features.
 
-- Reflect buffer status in the mode line :: It may be useful to
-  indicate in the mode line whether the current ~sweeprolog-mode~ buffer
-  has been loaded into the Prolog runtime and/or if its
-  cross-reference data is up to date.
-
 - Make predicate completion aware of module-qualification :: predicate
   completion should detect when the prefix it's trying to complete
   starts with a module-qualification ~foo:ba<|>~ and restrict completion
diff --git a/sweep.pl b/sweep.pl
index 7f0fb34..046e7eb 100644
--- a/sweep.pl
+++ b/sweep.pl
@@ -78,7 +78,8 @@
             sweep_terms_at_point/2,
             sweep_predicate_dependencies/2,
             sweep_async_goal/2,
-            sweep_interrupt_async_goal/2
+            sweep_interrupt_async_goal/2,
+            sweep_source_file_load_time/2
           ]).
 
 :- use_module(library(pldoc)).
@@ -651,15 +652,19 @@ sweep_op_info_(Op, _Path, [Type|Pred]) :-
     current_op(Pred, Type0, Op),
     atom_string(Type0, Type).
 
-sweep_load_buffer([String|Path0], Result) :-
+sweep_source_file_load_time(Path0, Time) :-
+    atom_string(Path, Path0),
+    source_file_property(Path, modified(Time)).
+
+sweep_load_buffer([String,Modified,Path0], _) :-
     atom_string(Path, Path0),
     with_buffer_stream(Stream,
                        String,
-                       sweep_load_buffer_(Stream, Path, Result)).
+                       sweep_load_buffer_(Stream, Modified, Path)).
 
-sweep_load_buffer_(Stream, Path, true) :-
+sweep_load_buffer_(Stream, Modified, Path) :-
     set_stream(Stream, file_name(Path)),
-    @(load_files(Path, [stream(Stream)]), user).
+    @(load_files(Path, [modified(Modified), stream(Stream)]), user).
 
 with_buffer_stream(Stream, String, Goal) :-
     setup_call_cleanup(( new_memory_file(H),
diff --git a/sweeprolog.el b/sweeprolog.el
index 1d60f5c..fd5dc50 100644
--- a/sweeprolog.el
+++ b/sweeprolog.el
@@ -2938,6 +2938,22 @@ GOAL.  Otherwise, GOAL is set to a default value specified by
                 (cancel-timer sweeprolog-top-level-timer)))
             nil t))
 
+(defun sweeprolog-buffer-load-time (&optional buffer)
+  (setq buffer (or buffer (current-buffer)))
+  (sweeprolog--query-once "sweep" "sweep_source_file_load_time"
+                          (with-current-buffer buffer
+                           (or (buffer-file-name)
+                               (expand-file-name (buffer-name))))))
+
+(defun sweeprolog-buffer-loaded-since-last-modification-p ()
+  (when-let ((mtime (or sweeprolog--buffer-last-modified-time
+                        (and (buffer-file-name)
+                             (float-time
+                              (file-attribute-modification-time
+                               (file-attributes (buffer-file-name)))))))
+             (ltime (sweeprolog-buffer-load-time)))
+    (<= mtime ltime)))
+
 (defun sweeprolog-load-buffer (buffer)
   "Load the Prolog buffer BUFFER into the embedded SWI-Prolog runtime.
 
@@ -2958,13 +2974,21 @@ buffer to load."
                                    (with-current-buffer n
                                      (eq major-mode 'sweeprolog-mode))))))))
   (with-current-buffer buffer
-    (let* ((beg (point-min))
-           (end (point-max))
-           (contents (buffer-substring-no-properties beg end)))
-      (if (sweeprolog--query-once "sweep" "sweep_load_buffer"
-                                  (cons contents (buffer-file-name)))
-          (message "Loaded %s." (buffer-name))
-        (user-error "Loading %s failed!" (buffer-name))))))
+    (if (sweeprolog-buffer-loaded-since-last-modification-p)
+        (message "Buffer %s already loaded." (buffer-name))
+      (let* ((beg (point-min))
+             (end (point-max))
+             (contents (buffer-substring-no-properties beg end)))
+        (if (sweeprolog--query-once "sweep" "sweep_load_buffer"
+                                    (list contents
+                                          (or sweeprolog--buffer-last-modified-time
+                                              (float-time))
+                                          (or (buffer-file-name)
+                                              (expand-file-name (buffer-name)))))
+            (progn
+              (message "Loaded %s." (buffer-name))
+              (force-mode-line-update))
+          (user-error "Loading %s failed!" (buffer-name)))))))
 
 
 ;;;; Prolog file specifications
@@ -4270,6 +4294,10 @@ certain contexts to maintain conventional Prolog layout."
   (setq-local adaptive-fill-regexp "[ \t]*")
   (setq-local fill-indent-according-to-mode t)
   (setq-local comment-multi-line t)
+  (setq-local mode-line-process
+              '(:eval
+                (when (sweeprolog-buffer-loaded-since-last-modification-p)
+                  "/Loaded")))
   (setq-local font-lock-defaults
               '(nil
                 nil
-- 
2.39.5