From 87e98628e5e6e73d016afbc09480d8bf1f0a70ee Mon Sep 17 00:00:00 2001 From: Eshel Yaron Date: Sun, 16 Oct 2022 18:22:08 +0300 Subject: [PATCH] ADDED: new command for showing help for Prolog modules * sweep.pl: sweep_module_html_documentation/2: new predicate. * sweeprolog.el: - sweeprolog-read-module-history: new variable. - sweeprolog-read-module-name: use it. - sweeprolog--describe-module: new function. - sweeprolog-describe-module: new command. - sweeprolog-help-prefix-map: new keymap. - sweeprolog-prefix-map: bind it keymap to `h'. * README.org: Prolog Help: new section. --- NEWS.org | 17 ++++++++++++- README.org | 33 +++++++++++++++++++----- sweep.pl | 18 +++++++++++++- sweeprolog.el | 69 +++++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 127 insertions(+), 10 deletions(-) diff --git a/NEWS.org b/NEWS.org index 232ce8b..3f61e9c 100644 --- a/NEWS.org +++ b/NEWS.org @@ -11,6 +11,21 @@ SWI-Prolog in Emacs. For further details, please consult the manual: . +* Version 0.6.3 on 2022-10-16 + +** New command ~sweeprolog-describe-module~ + +Experimental. Renders the full =PlDoc= documentation of the specified +Prolog module in a ~help-mode~ buffer. + +** Bug fix affecting ~sweeprolog-document-predicate-at-point~ + +This version includes a fix in ~sweeprolog-beginning-of-top-term~, which +is used to locate the beginning of the current clause. Previously +this function could hang when invoked with point before the first term +on the buffer. This affected commands that depend of this function, +such as ~M-x sweeprolog-document-predicate-at-point~. + * Version 0.6.2 on 2022-10-15 ** New command ~sweeprolog-export-predicate~ in ~sweeprolog-mode~ buffers @@ -20,7 +35,7 @@ For further details, please consult the manual: the current module's export list. Bound to =C-c C-e= in ~sweeprolog-mode-map~. -** Added a Prolog indicating the Prolog is running under ~sweep~ +** Added a Prolog flag indicating the Prolog is running under ~sweep~ =sweeprolog.el= now creates a boolean Prolog flag ~sweep~ set to ~true~ when initiating Prolog, to allow users to customize their Prolog init file diff --git a/README.org b/README.org index 5b28a7a..df8602c 100644 --- a/README.org +++ b/README.org @@ -872,6 +872,10 @@ called with a prefix argument (~C-u C-c C-`~), shows a list of diagnostics for all buffers in the current project. ** Exporting predicates +:PROPERTIES: +:CUSTOM_ID: exporting-predicates +:DESCRIPTION: Commands for adding Prolog predicates to their module's export list +:END: #+CINDEX: exported predicates By default, a predicate defined in Prolog module is not visible to @@ -894,6 +898,26 @@ the non-exported predicates defined in the current buffer. To force prompting for a predicate, invoke ~sweeprolog-export-predicate~ with a prefix argument (~C-u C-c C-e~). +* Prolog Help +:PROPERTIES: +:CUSTOM_ID: prolog-help +:DESCRIPTION: Commands for displaying detailed Prolog documentation +:END: + +#+CINDEX: prolog help +~sweep~ provides a way to read SWI-Prolog documentation via the standard +Emacs ~help~ user interface, akin to Emacs' built-in ~describe-function~ +(~C-h f~) and ~describe-variable~ (~C-h v~). For more information about +Emacs ~help~ and its special major mode, ~help-mode~, see [[info:emacs#Help Mode][Help Mode in the +Emacs manual]]. + +#+FINDEX: sweeprolog-describe-module +#+KINDEX: s (help-mode) +The command ~M-x sweeprolog-describe-module~ prompts for the name of a +Prolog module and displays its documentation in the =*Help*= buffer. To +jump to the source code from its documentation, press ~s~ +(~help-view-source~). + * The Prolog top-level :PROPERTIES: :CUSTOM_ID: prolog-top-level @@ -1270,11 +1294,6 @@ there some further improvements that we want to pursue: ~help-echo~ property that says what kind of token this is, to expose the precise semantics of each token to the user. -- Add a command for exporting the current predicate :: ~sweeprolog-mode~ - should provide a command for adding a predicate to the export list - of the module defined in the current buffer, defaulting to the - predicate at point. - - Add a command for updating the dependencies for the current module :: ~sweeprolog-mode~ should provide a command for adding and/or updating ~use_module/2~ and ~autoload/2~ directives as needed according to the predicates that the @@ -1356,7 +1375,9 @@ there some further improvements that we want to pursue: should include a command ~sweeprolog-describe-predicate~ that works similarly to the built-in ~describe-function~ by opening a ~help-mode~ buffer and populating it with the full cross-referenced - documentation of a given Prolog predicate. + documentation of a given Prolog predicate. We currently have + ~sweeprolog-describe-module~ as a proof of concept which should be + extended to cover predicate documentation as well. - Integrate with =project.el= adding support for SWI-Prolog packs :: It would be nice if ~sweep~ would "teach" =project.el= to detect diff --git a/sweep.pl b/sweep.pl index 62ea14b..4258444 100644 --- a/sweep.pl +++ b/sweep.pl @@ -61,7 +61,8 @@ sweep_top_level_threads/2, sweep_accept_top_level_client/2, sweep_local_predicate_export_comment/2, - write_sweep_module_location/0 + write_sweep_module_location/0, + sweep_module_html_documentation/2 ]). :- use_module(library(pldoc)). @@ -72,8 +73,10 @@ :- use_module(library(pldoc/doc_wiki)). :- use_module(library(pldoc/doc_modes)). :- use_module(library(pldoc/doc_man)). +:- use_module(library(pldoc/doc_html)). :- use_module(library(pldoc/man_index)). :- use_module(library(lynx/html_text)). +:- use_module(library(http/html_write)). :- use_module(library(prolog_pack)). :- meta_predicate with_buffer_stream(-, +, 0). @@ -426,9 +429,22 @@ sweep_module_path(ModuleName, Path) :- sweep_module_path_(Module, Path) :- module_property(Module, file(Path)), !. +sweep_module_path_(Module, Path) :- + xref_module(Path, Module), !. sweep_module_path_(Module, Path) :- '$autoload':library_index(_, Module, Path0), !, string_concat(Path0, ".pl", Path). +sweep_module_html_documentation(M0, D) :- + atom_string(M, M0), + ( sweep_module_path_(M, _) + -> true + ; '$autoload':library_index(_, M, Path), + xref_source(Path, [comments(store)]) + ), + doc_comment(M:module(Desc), Pos, _, Comment), + pldoc_html:pred_dom(M:module(Desc), [], Pos-Comment, DOM), + phrase(pldoc_html:html(DOM), HTML), + with_output_to(string(D), html_write:print_html(HTML)). sweep_modules_collection([], Modules) :- findall([M|P], ( module_property(M, file(P0)), atom_string(P0, P) ), Modules0, Tail), diff --git a/sweeprolog.el b/sweeprolog.el index dd906df..76b8106 100644 --- a/sweeprolog.el +++ b/sweeprolog.el @@ -6,7 +6,7 @@ ;; Maintainer: Eshel Yaron <~eshel/dev@lists.sr.ht> ;; Keywords: prolog languages extensions ;; URL: https://git.sr.ht/~eshel/sweep -;; Package-Version: 0.6.2 +;; Package-Version: 0.6.3 ;; Package-Requires: ((emacs "28")) ;; This file is NOT part of GNU Emacs. @@ -32,6 +32,9 @@ (require 'autoinsert) (require 'eldoc) (require 'flymake) +(require 'help-mode) +(require 'find-func) +(require 'shr) (defgroup sweeprolog nil "SWI-Prolog Embedded in Emacs." @@ -572,6 +575,8 @@ module name, F is a functor name and N is its arity." (when (sweeprolog-true-p sol) (cdr sol)))) +(defvar sweeprolog-read-module-history nil) + (defun sweeprolog-read-module-name () "Read a Prolog module name from the minibuffer, with completion." (let* ((col (sweeprolog-modules-collection)) @@ -585,7 +590,9 @@ module name, F is a functor name and N is its arity." (if des (concat pat (make-string (max 0 (- 80 (length pat))) ? ) des) pat))))))) - (completing-read sweeprolog-read-module-prompt col))) + (completing-read sweeprolog-read-module-prompt col nil nil nil + 'sweeprolog-read-module-history + sweeprolog-buffer-module))) (defun sweeprolog--set-buffer-module () @@ -1760,6 +1767,13 @@ Interactively, a prefix arg means to prompt for BUFFER." (sweeprolog--ensure-module) (when sweeprolog-init-on-load (sweeprolog-init)) +;;;###autoload +(defvar sweeprolog-help-prefix-map + (let ((map (make-sparse-keymap))) + (define-key map "m" #'sweeprolog-describe-module) + map) + "Keymap for `sweeprolog' help commands.") + ;;;###autoload (defvar sweeprolog-prefix-map (let ((map (make-sparse-keymap))) @@ -1768,6 +1782,7 @@ Interactively, a prefix arg means to prompt for BUFFER." (define-key map "R" #'sweeprolog-restart) (define-key map "T" #'sweeprolog-list-top-levels) (define-key map "e" #'sweeprolog-view-messages) + (define-key map "h" sweeprolog-help-prefix-map) (define-key map "l" #'sweeprolog-load-buffer) (define-key map "m" #'sweeprolog-find-module) (define-key map "p" #'sweeprolog-find-predicate) @@ -1933,6 +1948,8 @@ Interactively, PROJ is the prefix argument." (buffer-list)) ] [ "Open Top-level Menu" sweeprolog-list-top-levels t ] "--" + [ "Describe Prolog module" sweeprolog-describe-module t ] + "--" [ "Reset sweep" sweeprolog-restart t ] [ "View sweep messages" sweeprolog-view-messages t ])) @@ -2902,6 +2919,54 @@ if-then-else constructs in SWI-Prolog." (tabulated-list-print)) (pop-to-buffer-same-window buf))) +(defun sweeprolog--describe-module (mod) + (let ((page + (progn + (sweeprolog-open-query "user" + "sweep" + "sweep_module_html_documentation" + mod) + (let ((sol (sweeprolog-next-solution))) + (sweeprolog-close-query) + (when (sweeprolog-true-p sol) + (with-temp-buffer + (insert (cdr sol)) + (let ((shr-external-rendering-functions + '((a . shr-generic)))) + (shr-render-region (point-min) (point-max))) + (buffer-string))))))) + (help-setup-xref (list #'sweeprolog--describe-module mod) + (called-interactively-p 'interactive)) + (with-help-window (help-buffer) + (with-current-buffer (help-buffer) + (if-let ((path (sweeprolog-module-path mod))) + (progn + (setq help-mode--current-data + (list :symbol (intern mod) + :type 'swi-prolog-module + :file path)) + (if page + (insert (buttonize mod #'sweeprolog-find-module mod) + " is a SWI-Prolog module.\n\n" + page) + (insert (buttonize mod #'sweeprolog-find-module mod) + " is an undocumented SWI-Prolog module."))) + (insert mod " is not documented as a SWI-Prolog module.")))))) + +;;;###autoload +(defun sweeprolog-describe-module (mod) + "Display the full documentation for MOD (a Prolog module)." + (interactive (list (sweeprolog-read-module-name))) + (sweeprolog--describe-module mod)) + +(defvar sweeprolog-module-documentation-regexp (rx bol (zero-or-more whitespace) + ":-" (zero-or-more whitespace) + "module(")) + +(add-to-list 'find-function-regexp-alist + (cons 'swi-prolog-module + 'sweeprolog-module-documentation-regexp)) + (provide 'sweeprolog) ;;; sweeprolog.el ends here -- 2.39.2