From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.ciao.gmane.io!not-for-mail From: dieter@duenenhof-wilhelm.de (H. Dieter Wilhelm) Newsgroups: gmane.emacs.devel Subject: Re: [ELPA] New package: inform Date: Sun, 10 May 2020 20:19:38 +0200 Message-ID: <868shz64at.fsf@duenenhof-wilhelm.de> References: <86lfm3k05m.fsf@duenenhof-wilhelm.de> <868si2kfg8.fsf@duenenhof-wilhelm.de> <83v9l6iv0g.fsf@gnu.org> <86r1vuit3q.fsf@duenenhof-wilhelm.de> <86mu6iilr5.fsf@duenenhof-wilhelm.de> Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Injection-Info: ciao.gmane.io; posting-host="ciao.gmane.io:159.69.161.202"; logging-data="64699"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.3 (gnu/linux) Cc: Eli Zaretskii , emacs-devel@gnu.org To: Stefan Monnier Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Sun May 10 20:20:45 2020 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1jXqZA-000Gj5-Ol for ged-emacs-devel@m.gmane-mx.org; Sun, 10 May 2020 20:20:45 +0200 Original-Received: from localhost ([::1]:42406 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jXqZ9-0000bJ-8Z for ged-emacs-devel@m.gmane-mx.org; Sun, 10 May 2020 14:20:43 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:44034) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jXqYH-0007m2-6x for emacs-devel@gnu.org; Sun, 10 May 2020 14:19:49 -0400 Original-Received: from mout.kundenserver.de ([212.227.126.135]:60545) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1jXqYE-00079n-R4; Sun, 10 May 2020 14:19:48 -0400 Original-Received: from ping ([92.116.149.52]) by mrelayeu.kundenserver.de (mreue009 [212.227.15.167]) with ESMTPSA (Nemesis) id 1Mspy4-1jE7nv3g52-00tC9z; Sun, 10 May 2020 20:19:40 +0200 In-Reply-To: (Stefan Monnier's message of "Fri, 08 May 2020 11:04:43 -0400") X-Provags-ID: V03:K1:nQFJpaCUnPpEXJdLRivOTV4iwZ1chRo7vOMoUyIErdefTKhHEEy tcFvAPq6fUqtmOibv4Gl+dvv/VEg+TVy/olG5shl2XExGtzSmHE9oSt2Kj5ywKYTy/l3yE3 nR/ONWVxOJuxku41rqnqROjstRmHtmlMguLunfELlc+NQa+4TvcEZ85m4By3no+8Lu+sCI8 UYDR4VGSt2Lzs6onlFnxw== X-UI-Out-Filterresults: notjunk:1;V03:K0:aIDgnjT+Eac=:jnOr3bimYym3livon5dE9k jPKd95nrBF//7corgHsWOJh9YyCFk5fsQhJ0Rxve4vOj+hdoSsJmlfkuj1ppRAkPk64TFtM8j Kqe2j8tkiqVx2FbILVT981vjga/h1IUQNiF0bh5N7EGTpcaudZMCs34QJaiwX3nBuftqzc3Bk SltBvVLHSoASiBlbFbz4jMmpDaktfBf4JqSM9CODQgqr/hlPAdQ3dhVFcFttBSJutBR8tbrws nmhm7jaoB3BRyCdcsTeT+gJHMBJvOkpwl7N4hQZYvP96EwDcFmt+NhbWUf0FkFtIUCsZLsSAf z1PSKUYG1LoafD8ukd0CeTqz/flxhVp4iEoRWHvFaHCs7BEtI815GfZzZQzFuDHg9dGsvYp+k /BOXllyFo/b+7DHLfhsFNFa0JY7nCe7iz7yyccIspbqRJ7M6rC8teqkSJXxCjFBTX5c8L3Msd iDteOSPQRdwbfY6vJDiYlsFJzvu0l12y/Q0YdoMnaqtj/w7vViX+tAvW0anDHCMsBLbR4DE3y O90lyJtA7BCGE6LLjBng5L2l44/YtJs8tgW26xKzsZ9jWszgMTD5YIeAOhw9dB5hyXb2Nyy/B zrZPev027aovgcDz81QHQf04bek+/yPeeTOf1NAUHf/+xknRb0Vrn7oGQZ1iRG05q6TJOL9AC VUiG1qH/Qb0etiYyG2xU/rI3QE4pLziZPTjov7xZsWX9TD1tPLtAPPCp+YoOIDpUhxnxOXfLS BvpY78WQOMyaLyChN6yX84Zb6aZpJUUjYLcv8PhGuIygZh/on7xDRlqelCX8nYlE8SOSTxrv Received-SPF: none client-ip=212.227.126.135; envelope-from=dieter@duenenhof-wilhelm.de; helo=mout.kundenserver.de X-detected-operating-system: by eggs.gnu.org: First seen = 2020/05/10 14:19:44 X-ACL-Warn: Detected OS = Linux 3.11 and newer X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, URIBL_BLOCKED=0.001 autolearn=_AUTOLEARN X-Spam_action: no action X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.io gmane.emacs.devel:249692 Archived-At: Stefan Monnier writes: >> After a second thought, it might be more practical to check if a >> document is coming from the `package-user-dir' or info/ and collect over >> time a - hopefully - small list of none-Elisp/Emacs related documents to >> filter them out. > > Indeed, I suspect a test like > > - if it's in the blacklist =3D> don't activate > - if it comes from Emacs's own directory =3D> activate > - if it comes from an ELPA package =3D> activate > - else =3D> don't activate > > will be a good enough start. The blacklist should likely use regexps > and will presumably start with the Ada manual and SICP. Here's a first prototype along this line, I'm looking forward to your advice, I'm not sure how to activate this linking, hope the autoloading below will do... modified lisp/info-xref.el @@ -1,4 +1,4 @@ -;;; info-xref.el --- check external references in an Info document -*- lex= ical-binding: t -*- +;;; info-xref.el --- Cross references in an Info document -*- lexical-bind= ing: t -*- =20 ;; Copyright (C) 2003-2020 Free Software Foundation, Inc. =20 @@ -38,6 +38,119 @@ ;; `M-x info-xref-docstrings' checks docstring "Info node ..." hyperlinks = in ;; source files (and other files). =20 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; This library provides links of symbols (functions, variables, +;; faces) within Emacs' Info viewer to their builtin help +;; documentation. This linking is done, when the symbol names in +;; texinfo documentations (like the Emacs- and Elisp manual) are + +;; 1. Quoted symbol names like `quoted-symbol' or: + +;; 2. Function names are prefixed by M-x, for example M-x +;; function-name or are quoted and prefixed like `M-x function-name'. + +;; 3. Function names appearing behind the following forms, which +;; occur, for example, in the Elisp manual: + +;; -- Special Form: function-name +;; -- Command: +;; -- Function: +;; -- Macro: + +;; 4. And variables names behind the following text: + +;; -- User Option: variable-name +;; -- Variable: + +;; In any case all symbol names must be known to Emacs, i.e. their +;; names are found in the variable `obarray'. + +;; You can follow the additional links with the usual Info +;; keybindings. The customisation variable +;; `mouse-1-click-follows-link' is influencing the clicking behavior +;; (and the tooltips) of the links, the variable's default is 450 +;; (milli seconds) setting it to nil means only clicking with mouse-2 +;; is following the link (hint: Drew Adams). + +;; The link color of symbols - referencing their builtin documentation +;; - is distinct from links which are referencing further Info +;; documentation. + +;; Inform is checking if the Info documents are relevant Elisp and +;; Emacs related files to avoid false positives. Please see the +;; customization variable `inform-none-emacs-or-elisp-documents'. + +;; The code uses mostly mechanisms from Emacs' lisp/help-mode.el file. + +;;; Change Log: + +;; 1.3: + +;; Inform is checking if the Info documents are relevant Elisp and +;; Emacs related files to avoid false positives. + +;; 1.2: + +;; Link Elisp descriptions of symbols to their help documentation, +;; like the following function example: -- Function: eval form + +;; Distinguish color of texinfo links (`link' type) and Help links +;; (`font-lock-function-name-face') + +;;; TODO: + +;; Currently inconsistent link colors to help buffers: In *info* +;; different as in *Help* buffers! + +;; Check the application `inform-xref-symbol-regexp' for additional +;; symbol prefixes without quoting of symbol-names + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Does the following belong to customize.el? + +;; Generalise linking to "customization buffers" for the "easy +;; customization" info documentation see also the customization +;; section in the elisp manual + +;; - distinguish the Customization-links from Help- and Info-links +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;; Ideas: + +;; Link the help buffers back to higher level info manual subjects, +;; similar to help-fns+.el from Drew Adams. + +;; Twice clicking or RETurning removes *Help* buffer (idea: Drew +;; Adams) + +;; Different colors for different symbol types (idea: Drew Adams) see +;; package helpful and info+ / info-colors on Melpa and see +;; font-lock.el for common faces. + +;; - Do we need to indicate an already visited Help link with a +;; different color? + +;; - Would it be be good to overtake all colors of package +;; "info-colors"? + +;; - Do we need to distinguish the link FONTS? No, difficult to read! + +;; Back / Forward button in help buffer - back to info buffer or +;; remain in help mode? + +;; Linking of standard symbol properties? + +;; - (info "(elisp) Standard Properties") + +;; Elisp manual examples: +;; (symbol-name 'car) ... ? + +;; Shortening the verbose texinfo URLs? But how to handle the changed +;; indentation? + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;;; History: =20 ;; Version 3 - new M-x info-xref-docstrings, use compilation-mode @@ -556,6 +669,301 @@ info-xref-docstrings =20 (info-xref-check-node node))))))))) =20 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(require 'button) +(require 'cl-lib) +(require 'help-mode) ;redundant? + +;; activate inform without manually loading it. Is there a better way? +;; ;;;###autoload (require 'info-xref) + +;; this is spawning lisp/info-xref.el's definition to 'info! This +;; group is sorted now in 'docs and 'info! -FIXME- +(defgroup info-xref nil + "Customisation 'info-xref' subgroup of info. +Check external cross-references in Info documents and provide +hyperlinks from symbols to their help documentation." + :group 'info) + +;;;###autoload +(defcustom info-xref-make-xref-flag t + "Non-nil means create symbol links in info buffers." + :type '(choice (const :tag "Create links" t) + (const :tag "Do not link" nil)) + :group 'info-xref) + +(require 'cl-seq) +;; Info-director-list must be initialised +(info-initialize) +(defvar Info-xref-emacs-info-dir-content + (mapcar 'file-name-nondirectory ;'file-name-sans-extension + (directory-files + (car + ;; search for the main Emacs' info/ directory + (cl-member "[^.]emacs" Info-directory-list :test 'string-match-p)) + ;; don't list "." and ".." + t "[^.]$")) + "List of file names in Emacs' own info/ directory.") + +;; Turn into regexp list necessary? Stefan +;; Switch to alist with explanation of file name? +(defcustom info-xref-none-emacs-or-elisp-documents + '("aarm2012" ; Stefan: Ada manual, Elpa archive + "arm2012" ; Stefan: Ada manual + "sicp" ; T.V: Structure and Interpretation of Computer Programs, + ; Melpa archive + ) + "List of all none GNU-Emacs or Elisp documentation. +Or other documents not to be checked for linking to their help +documentation. The list must contains only the base name of the +files (without their file name extension \".info\")." + :type '(repeat string) + :group 'info-xref) + +(defun Info-xref-check-docu-p () + "Check if the current info file is relevant to Emacs. +That means `Info-current-file' is either found in Emacs' info/ +directory or in `package-user-dir' and is not included in the +`info-xref-none-emacs-or-elisp-documents' list." + (let* ((ifile Info-current-file) + (ifi (when ifile + (file-name-sans-extension + (file-name-nondirectory ifile)))) + (pdir (when (boundp 'package-user-dir) + (expand-file-name + package-user-dir))) + (ifiles Info-xref-emacs-info-dir-content) + (ndocu info-xref-none-emacs-or-elisp-documents)) + (and ifile + (or (assoc-string (concat ifi ".info") ifiles) + ;; info files might be archived! + (assoc-string (concat ifi ".info.gz") ifiles) + (when pdir (string-match pdir ifile))) + (not (assoc-string ifi ndocu))))) + +(defvar describe-symbol-backends) ;from help-mode.el +(defvar help-xref-following) ;dito + +;; this toggles the complete linking process +;;;###autoload +(when info-xref-make-xref-flag + (add-hook 'Info-selection-hook 'Info-xref-make-xrefs)) + +(defface Info-xref-color + '((t (:inherit font-lock-doc-face + ;; font-lock-preprocessor-face ; similar to link face (default) + ;; font-lock-builtin-face ; similar (default Emacs) + ;; font-lock-function-name-face ; similar (default) + ;; Info-xref-face + ))) + "Face for the `symbol' reference items in `info' nodes." + :group 'info-colors) + +;; Button types + +(define-button-type 'Info-xref + 'link t ;for Info-next-reference-or-link + 'follow-link t + 'face 'Info-xref-color + 'action #'Info-xref-button-action) + +(define-button-type 'Info-xref-function + :supertype 'Info-xref + 'Info-xref-function 'describe-function + 'Info-xref-echo (purecopy "mouse-2, RET: describe this function")) + +(define-button-type 'Info-xref-variable + :supertype 'Info-xref + 'Info-xref-function 'describe-variable + 'Info-xref-echo (purecopy "mouse-2, RET: describe this variable")) + +(define-button-type 'Info-xref-face + :supertype 'Info-xref + 'Info-xref-function 'describe-face + 'Info-xref-echo (purecopy "mouse-2, RET: describe this face")) + +(define-button-type 'Info-xref-symbol + :supertype 'Info-xref + 'Info-xref-function #'describe-symbol + 'Info-xref-echo (purecopy "mouse-2, RET: describe this symbol")) + +(define-button-type 'Info-xref-function-def + :supertype 'Info-xref + 'Info-xref-function (lambda (fun &optional file type) + (or file + (setq file (find-lisp-object-file-name fun type))) + (if (not file) + (message "Unable to find defining file") + (require 'find-func) + (when (eq file 'C-source) + (setq file + (help-C-file-name (indirect-function fun) 'fun))) + ;; Don't use find-function-noselect because it follows + ;; aliases (which fails for built-in functions). + (let ((location + (find-function-search-for-symbol fun type file))) + (pop-to-buffer (car location)) + (run-hooks 'find-function-after-hook) + (if (cdr location) + (goto-char (cdr location)) + (message "Unable to find location in file"))))) + 'Info-xref-echo (purecopy "mouse-2, RET: find function's definition")) + +;; Functions + +(defun Info-xref-button-action (button) + "Call BUTTON's help function." + (Info-xref-do-xref nil + (button-get button 'Info-xref-function) + (button-get button 'Info-xref-args))) + +(defun Info-xref-do-xref (_pos function args) + "Call the help cross-reference function FUNCTION with args ARGS. +Things are set up properly so that the resulting `help-buffer' has +a proper [back] button." + ;; There is a reference at point. Follow it. + (let ((help-xref-following nil)) + (apply + function (if (eq function 'info) + (append args (list (generate-new-buffer-name "*info*")))args)))) + +(defun Info-xref-button (match-number type &rest args) + "Make a hyperlink for cross-reference text previously matched. +MATCH-NUMBER is the subexpression of interest in the last matched +regexp. TYPE is the type of button to use. Any remaining arguments are +passed to the button's Info-xref-function when it is invoked. +See `Info-xref-make-xrefs' Don't forget ARGS." ; -TODO- + ;; Don't mung properties we've added specially in some instances. + (unless (button-at (match-beginning match-number)) + ;; (message "Creating button: %s." args) + (make-text-button (match-beginning match-number) + (match-end match-number) + 'type type 'Info-xref-args args))) + +(defconst Info-xref-symbol-regexp + (purecopy (concat "\\(\\<\\(\\(variable\\|option\\)\\|" ; Link to var + "\\(function\\|command\\|call\\)\\|" ; Link to funct= ion + "\\(face\\)\\|" ; Link to face + "\\(symbol\\|program\\|property\\)\\|" ; Don't link + "\\(source \\(?:code \\)?\\(?:of\\|for\\)\\)\\)" + "[ \t\n]+\\)?" + ;; Note starting with word-syntax character: + "['`=E2=80=98]\\(\\sw\\(\\sw\\|\\s_\\)+\\|`\\)['=E2=80= =99]")) + "Regexp matching doc string references to symbols. + +The words preceding the quoted symbol can be used in doc strings to +distinguish references to variables, functions and symbols.") + +;;;###autoload +(defun Info-xref-make-xrefs (&optional buffer) + "Parse and hyperlink documentation cross-references in the given BUFFER. + +Find cross-reference information in a buffer and activate such cross +references for selection with `help-follow'. Cross-references have +the canonical form `...' and the type of reference may be +disambiguated by the preceding word(s) used in +`Info-xref-symbol-regexp'. + +Function names are also prefixed by \"M-x\", for example \"M-x +function-name\" or are quoted and prefixed like `M-x +function-name'. + +Also Function names appearing behind the following forms, which +occur, for example, in the Elisp manual: + + -- Special Form: function-name + -- Command: + -- Function: + -- Macro: + +And variables names behind the following text: + + -- User Option: variable-name + -- Variable: + +Faces only get cross-referenced if preceded or followed by the +word `face'. Variables without variable documentation do not get +cross-referenced, unless preceded by the word `variable' or +`option'." + (interactive "b") + (when (Info-xref-check-docu-p) + (with-current-buffer (or buffer (current-buffer)) + (save-excursion + (goto-char (point-min)) + ;; Skip the header-type info, though it might be useful to parse + ;; it at some stage (e.g. "function in `library'"). + ;; (forward-paragraph) + (with-silent-modifications ;from Stefan + (let (;(stab (syntax-table)) + (case-fold-search t) + (inhibit-read-only t)) + (with-syntax-table emacs-lisp-mode-syntax-table + ;; Quoted symbols + (save-excursion + (while (re-search-forward Info-xref-symbol-regexp nil t) + (let* ((data (match-string 8)) + (sym (intern-soft data))) + (if sym + (cond + ((match-string 3) ; `variable' &c + (and (or (boundp sym) ; `variable' doesn't ensure + ; it's actually bound + (get sym 'variable-documentation)) + (Info-xref-button 8 'Info-xref-variable sym))) + ((match-string 4) ; `function' &c + (and (fboundp sym) ; similarly + (Info-xref-button 8 'Info-xref-function sym))) + ((match-string 5) ; `face' + (and (facep sym) + (Info-xref-button 8 'Info-xref-face sym))) + ((match-string 6)) ; nothing for `symbol' + ((match-string 7) + (Info-xref-button 8 'Info-xref-function-def sym)) + ((cl-some (lambda (x) (funcall (nth 1 x) sym)) + describe-symbol-backends) + (Info-xref-button 8 'Info-xref-symbol sym))))))) + + ;; (info "(elisp) Eval") + ;; Elisp manual -- Special Form: + ;; -- Command: + ;; -- Function: function-name function + ;; -- Macro: + (save-excursion + (while (re-search-forward + "-- \\(Special Form:\\|Command:\\|Function:\\|Macro:\\) " + nil t) + (looking-at "\\(\\sw\\|\\s_\\)+") + (let ((sym (intern-soft (match-string 0)))) + (if (fboundp sym) + (Info-xref-button 0 'Info-xref-function sym))))) + + ;; -- User Option: + ;; -- Variable: variable-name + (save-excursion + (while (re-search-forward + "-- \\(User Option:\\|Variable:\\) " + nil t) + (looking-at "\\(\\sw\\|\\s_\\)+") + (let ((sym (intern-soft (match-string 0)))) + (if (boundp sym) + (Info-xref-button 0 'Info-xref-variable sym))))) + + ;; M-x prefixed functions + (save-excursion + (while (re-search-forward + ;; Assume command name is only word and symbol + ;; characters to get things like `use M-x foo->bar'. + ;; Command required to end with word constituent + ;; to avoid `.' at end of a sentence. + ;; "\\