Subject: bug#60587: Patch for adding links to symbols' help documentation

From: "H. Dieter Wilhelm" <[email-masked]>
Date: Sat, 14 Jan 2023 00:33:19 +0100

Eli Zaretskii <[email-masked]> writes:

>> +(require 'button)
>> +(require 'cl-lib)
>> +(require 'help-mode)                   ;redundant?
>
> If this is added to an existing file, there should be a ^L and some
> heading-style command before it.

I had a look at the usage of ^L in info.el but I can't discern any rule
or consistency.  The number of lines between its page delimiters are
over 900 and below 20.  I assume you want me to use ^L to separate a
different topic within info.el?

>> +                (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)))))))
>
> Can this be rewritten so as to avoid the need for error-prone updates
> of the sub-expression numbers every time Info-xref-symbol-regexp is
> modified?

What do you think about the following approach?

(defcustom info-symbol-context
  '(( variable . "variable\\|option")
    ;; defining symbol as variable
    ( function . "function\\|command\\|call")
    ;; defining symbol as function
    ( face . "face")
    ;; defining symbol as face
    ( ignore . "symbol\\|program\\|property")
    ;; ignore symbols following this context type
    ( definition . "source \\(?:code \\)?\\(?:of\\|for\\)"))
    ;; function definitions in files
  "Help."
  :type 'list
  :version "30.1"
  :group 'info)

;; Assembling the complete regexp
(defvar info-symbol-regexp
  (concat
   ;; context
   "\\(" ; ---- context start
   "\\<\\(" ; contex definition
   (string-remove-suffix
    "\\|"
    (mapconcat
     (lambda (x) (concat "\\(" (cdr x) "\\)\\|"))
     info-symbol-context ""))
   "\\)"  ; --- definition end
   "[ \t\n]+" ; --- separators to quoted symbols
   "\\)?"  ;; ---- end of context
   ;; quoted symbol
   "['`‘]"	  ; start quotes
   ;; Note: symbol starting with word-syntax character:
   "\\(\\sw\\(\\sw\\|\\s_\\)+\\|`\\)" ; symbol
   "['’]"				  ; end quotes
   )
  "Help.")

;; helper function
(defun info-check-type( type)
  "Check if TYPE corresponds to the current search result.
`match-string'."
  (let ((ictr info-symbol-regexp)
	(n 3)                           ;embedded within 2 groups
	)
    (while (not (eq type (caar ictr)))
       (setq n (1+ n))
       (setq ictr (cdr ictr)))
    (match-string n)
    ))

;;Here comes the function creating links
;;....
                (while (re-search-forward info-symbol-regexp nil t)
                  (let* ((data (match-string 8))
                         (sym (intern-soft data)))
                    (if sym
                        (cond
                         ((info-check-type 'variable)
                          (and (or (boundp sym)
                                   (get sym 'variable-documentation))
                               (info-button 8 'info-variable sym)))
                         ((info-check-type 'function)
                          (and (fboundp sym)
                               (info-button 8 'info-function sym)))
                         ((info-check-type 'face)
                          (and (facep sym)
                               (info-button 8 'info-face sym)))
                         ((info-check-type 'ignore))
                         ((info-check-type 'definition)
                          (info-button 8 'info-function-def sym))
                         ;; 
                         ((cl-some (lambda (x) (funcall (nth 1 x) sym))
                                   describe-symbol-backends)
                          (info-button 8 'info-symbol sym)))))))

-- 
Best wishes
H. Dieter Wilhelm
Zwingenberg, Germany