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
;; 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.
(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
(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."
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)