]> git.eshelyaron.com Git - dict.git/commitdiff
ENHANCED: teach sweep to jump to C code for built-in predicates V8.5.20-sweep-0.7.1
authorEshel Yaron <me@eshelyaron.com>
Wed, 19 Oct 2022 05:38:34 +0000 (08:38 +0300)
committerEshel Yaron <me@eshelyaron.com>
Wed, 19 Oct 2022 06:01:32 +0000 (09:01 +0300)
* sweeprolog.el:
- sweeprolog-swipl-sources: new user option.
- sweeprolog-native-predicate-location: new function.
- sweeprolog-predicate-location: use it.
- README.org: Built-in Native Predicates: new section.

NEWS.org
README.org
sweeprolog.el

index 40f95e6fb7de974f0960426e7f2c31723639bb57..4f589361afacc3b106aaff64003f9ada1909fb54 100644 (file)
--- a/NEWS.org
+++ b/NEWS.org
@@ -11,6 +11,24 @@ SWI-Prolog in Emacs.
 For further details, please consult the manual:
 <https://eshelyaron.com/sweep.html>.
 
+
+* Version 0.7.1 on 2022-10-19
+
+** Jumping to source works also for built-in predicates defined in C
+
+~sweep~ now knows how to find and jump to the definitions of native
+built-in SWI-Prolog predicates defined in C, under the condition that
+the user has the SWI-Prolog sources checked out locally.
+
+See ~C-h v sweeprolog-swipl-sources~ and the new section "Built-in
+Native Predicates" in the manual for more information about this
+feature.
+
+** Fixes and improvements to ~sweeprolog-describe-predicate~
+
+This version fixes some compatibility issues with Emacs versions prior
+to 29 in ~sweeprolog-describe-predicate~.  Reported by Jan Wielemaker.
+
 * Version 0.7.0 on 2022-10-17
 
 ** New command ~sweeprolog-describe-predicate~
index 711748ca88b44f41c78a05441b288504b629c3aa..28fc8cf99536f325464c16d852fe880ab3104b60 100644 (file)
@@ -1108,6 +1108,44 @@ For example, typing =C-x C-f library(pldoc/doc_man)= will open the
 source of the =pldoc_man= module from the Prolog library, and likewise
 =C-x C-f pack(.)= will open the Prolog packages directory.
 
+** Built-in Native Predicates
+:PROPERTIES:
+:CUSTOM_ID: goto-c-predicates
+:DESCRIPTION: Finding and jumping to definitions of built-in SWI-Prolog predicates defined in C
+:END:
+
+#+CINDEX: native built-in predicates
+Some of the built-in predicates provided by SWI-Prolog, such as ~is/2~,
+are implemented in C and included as native functions in the
+SWI-Prolog runtime.  It is sometimes useful to examine the
+implementation of such native built-in predicates by reading its
+definition in the SWI-Prolog C sources.  ~sweep~ knows about SWI-Prolog
+native built-ins, and can find and jump to their definitions in C when
+the user has the SWI-Prolog sources checked out locally.
+
+#+VINDEX: sweeprolog-swipl-sources
+The way ~sweep~ locates the SWI-Prolog sources depends on the user
+option ~sweeprolog-swipl-sources~.  When customized to a string, it is
+taken to be the path to the root directory of the SWI-Prolog source
+code.  If instead ~sweeprolog-swipl-sources~ is set to ~t~ (the default),
+~sweep~ will try to locate a local checkout of the SWI-Prolog sources
+automatically among known project root directories provided by Emacs'
+built-in ~project-known-project-roots~ from =project.el= (see [[info:emacs#Projects][Projects in
+the Emacs manual]] for more information about =project.el= projects).
+Lastly, setting ~sweeprolog-swipl-sources~ to ~nil~ disables searching for
+definitions of native built-ins.
+
+With ~sweeprolog-swipl-sources~ set, the provided commands for finding
+predicate definitions operate seamlessly on native built-ins to
+display their C definitions in ~c-mode~ buffers (see [[info:ccmode#Top][the Emacs CC Mode
+manual]] for information about working with C code in Emacs).  These
+commands include:
+- ~M-x sweeprolog-find-predicate~,
+- ~M-.~ (~xref-find-definitions~) in ~sweeprolog-mode~ buffers (see
+  [[#sweeprolog-xref][Definitions and references]]), and
+- ~s~ (~help-view-source~) in the =*Help*= buffer produced by ~M-x
+  sweeprolog-describe-predicate~ (see [[#prolog-help][Prolog Help]]).
+
 * Quick access to sweep commands
 :PROPERTIES:
 :CUSTOM_ID: quick-command-access
index 4d326472f04e070058d77ebbe0952efd8604f66d..3c1d9d7be7ad55ec2039acc44327d1a5d7af1718 100644 (file)
@@ -6,8 +6,8 @@
 ;; Maintainer: Eshel Yaron <~eshel/dev@lists.sr.ht>
 ;; Keywords: prolog languages extensions
 ;; URL: https://git.sr.ht/~eshel/sweep
-;; Package-Version: 0.7.0
-;; Package-Requires: ((emacs "28"))
+;; Package-Version: 0.7.1
+;; Package-Requires: ((emacs "28.1"))
 
 ;; This file is NOT part of GNU Emacs.
 
   "SWI-Prolog Embedded in Emacs."
   :group 'prolog)
 
+(defcustom sweeprolog-swipl-sources t
+  "Location of the SWI-Prolog source code root directory.
+
+When non-nil, the function `sweeprolog-predicate-location' will
+attempt to find the C defintions of SWI-Prolog native built-in
+predicates.
+
+The value of this option can be a string, in which case it should
+be a path to the SWI-Prolog source code root directory.  Any
+other non-nil value instructs `sweeprolog-predicate-location' to
+try and find the SWI-Prolog sources among known project roots
+obtained from `project-known-project-roots', which see."
+  :package-version '((sweeprolog . "0.4.6"))
+  :type '(choice (const  :tag "Detect"  t)
+                 (string :tag "Manual")
+                 (const  :tag "Disable" nil))
+  :group 'sweeprolog)
+
 (defcustom sweeprolog-module-header-comment-skeleton ?\n
   "Additional content for the topmost comment in module headers.
 
@@ -415,6 +433,7 @@ Otherwise set ARGS to nil."
   (interactive
    (and
     current-prefix-arg
+    (fboundp 'split-string-shell-command)
     (split-string-shell-command (read-string "swipl arguments: "))))
   (when-let ((top-levels (seq-filter (lambda (buffer)
                                        (eq 'sweeprolog-top-level-mode
@@ -464,13 +483,68 @@ When non-nil, only predicates whose name contains PREFIX are returned."
     (when (sweeprolog-true-p sol)
       (cdr sol))))
 
+(defun sweeprolog--mfn-to-functor-arity (mfn)
+  (let ((functor-arity (split-string (car (reverse (split-string mfn ":"))) "/")))
+    (cons (car functor-arity)
+          (string-to-number (cadr functor-arity)))))
+
+(defun sweeprolog--swipl-source-directory ()
+  (when sweeprolog-swipl-sources
+    (if (stringp sweeprolog-swipl-sources)
+        sweeprolog-swipl-sources
+      (when (fboundp 'project-known-project-roots)
+        (car (seq-filter
+              (lambda (root)
+                (member (car
+                         (reverse
+                          (seq-filter
+                           (lambda (s)
+                             (not (string-empty-p s)))
+                           (file-name-split root))))
+                        '("swipl" "swipl-devel")))
+              (project-known-project-roots)))))))
+
+(defun sweeprolog-native-predicate-location (mfn)
+  (let ((functor-arity (sweeprolog--mfn-to-functor-arity mfn)))
+    (when-let ((default-directory (sweeprolog--swipl-source-directory))
+               (match
+                (car (xref-matches-in-files
+                      (rx (or "PRED_IMPL" "FRG")
+                          (zero-or-more whitespace)
+                          "(\""
+                          (zero-or-more whitespace)
+                          (literal (car functor-arity))
+                          "\""
+                          (zero-or-more whitespace)
+                          ","
+                          (zero-or-more whitespace)
+                          (literal (number-to-string (cdr functor-arity))))
+                      (project-files (project-current)
+                                     (list (expand-file-name "src"
+                                                             default-directory))))))
+               (location (if (fboundp 'xref-match-item-location)
+                             (xref-match-item-location match)
+                           (xref-item-location match))))
+      (if (fboundp 'xref-file-location-file)
+          (cons (xref-file-location-file location)
+                (xref-file-location-line location))
+        (with-slots ((file file)
+                     (line line))
+            location
+          (cons file line))))))
+
 (defun sweeprolog-predicate-location (mfn)
-  "Return the source location where the predicate MFN is defined."
+  "Return the source location where the predicate MFN is defined.
+
+For native built-in predicates, the behavior of this function
+depends on the value of the user option
+`sweeprolog-swipl-sources', which see."
   (sweeprolog-open-query "user" "sweep" "sweep_predicate_location" mfn)
   (let ((sol (sweeprolog-next-solution)))
     (sweeprolog-close-query)
-    (when (sweeprolog-true-p sol)
-      (cdr sol))))
+    (if (sweeprolog-true-p sol)
+        (cdr sol)
+      (sweeprolog-native-predicate-location mfn))))
 
 (defun sweeprolog-predicate-apropos (pattern)
   "Return a list of predicates whose name resembeles PATTERN."
@@ -2788,7 +2862,8 @@ if-then-else constructs in SWI-Prolog."
                 nil
                 (font-lock-fontify-region-function . sweeprolog-colourise-some-terms)))
   (when sweeprolog-enable-eldoc
-    (setq-local eldoc-documentation-strategy #'eldoc-documentation-default)
+    (when (fboundp 'eldoc-documentation-default)
+      (setq-local eldoc-documentation-strategy #'eldoc-documentation-default))
     (add-hook 'eldoc-documentation-functions #'sweeprolog-predicate-modes-doc nil t))
   (when sweeprolog-enable-flymake
     (add-hook 'flymake-diagnostic-functions #'sweeprolog-diagnostic-function nil t)