From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: "Drew Adams" Newsgroups: gmane.emacs.devel Subject: RE: adding manual cross-ref links to *Help* Date: Mon, 13 Jun 2011 14:01:52 -0700 Message-ID: <6D7CA6598EAD4E3DB7B2E5D992BBDFF4@us.oracle.com> References: <9CE56B14F4964F7A8D872D3553176C61@us.oracle.com> <8762octf66.fsf@mail.jurta.org> NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_NextPart_000_007D_01CC29D2.72CD9B50" X-Trace: dough.gmane.org 1307999339 19827 80.91.229.12 (13 Jun 2011 21:08:59 GMT) X-Complaints-To: usenet@dough.gmane.org NNTP-Posting-Date: Mon, 13 Jun 2011 21:08:59 +0000 (UTC) Cc: emacs-devel@gnu.org To: "'Juri Linkov'" Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Mon Jun 13 23:08:55 2011 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([140.186.70.17]) by lo.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1QWENQ-0007XX-TA for ged-emacs-devel@m.gmane.org; Mon, 13 Jun 2011 23:08:53 +0200 Original-Received: from localhost ([::1]:48274 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QWENP-0000Wo-DR for ged-emacs-devel@m.gmane.org; Mon, 13 Jun 2011 17:08:51 -0400 Original-Received: from eggs.gnu.org ([140.186.70.92]:51620) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QWEGq-0007iO-Qk for emacs-devel@gnu.org; Mon, 13 Jun 2011 17:02:05 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QWEGo-000510-KT for emacs-devel@gnu.org; Mon, 13 Jun 2011 17:02:04 -0400 Original-Received: from rcsinet10.oracle.com ([148.87.113.121]:64676) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QWEGo-00050l-4G for emacs-devel@gnu.org; Mon, 13 Jun 2011 17:02:02 -0400 Original-Received: from rtcsinet21.oracle.com (rtcsinet21.oracle.com [66.248.204.29]) by rcsinet10.oracle.com (Switch-3.4.2/Switch-3.4.2) with ESMTP id p5DL1wnf015280 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Mon, 13 Jun 2011 21:02:00 GMT Original-Received: from acsmt358.oracle.com (acsmt358.oracle.com [141.146.40.158]) by rtcsinet21.oracle.com (8.14.4+Sun/8.14.4) with ESMTP id p5DL1vD3024542 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Mon, 13 Jun 2011 21:01:58 GMT Original-Received: from abhmt001.oracle.com (abhmt001.oracle.com [141.146.116.10]) by acsmt358.oracle.com (8.12.11.20060308/8.12.11) with ESMTP id p5DL1pc2022640; Mon, 13 Jun 2011 16:01:51 -0500 Original-Received: from dradamslap1 (/130.35.179.10) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Mon, 13 Jun 2011 14:01:50 -0700 X-Mailer: Microsoft Office Outlook 11 In-Reply-To: <8762octf66.fsf@mail.jurta.org> Thread-Index: AcwoYrenW0JugEZ7S5GjQQFP86o3+wBozOpQ X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.6090 X-Source-IP: rtcsinet21.oracle.com [66.248.204.29] X-CT-RefId: str=0001.0A090209.4DF67AC9.0054:SCFSTAT5015188,ss=1,fgs=0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 3) X-Received-From: 148.87.113.121 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.14 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.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:140435 Archived-At: This is a multi-part message in MIME format. ------=_NextPart_000_007D_01CC29D2.72CD9B50 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit > Adding cross-reference links is easier to do with Help buffer > templates that improves `Info-virtual-files'. I'll submit a > patch here soon. Thanks. It's fine if you implement the same features in a different way. I welcome the feature, however it's done. I requested it at least as far back as 2006. I finally got around to adding it to my own code, thanks to the virtual indexing code that you added to Emacs. I hope you will give users as much control over whether and when the indexes of the manuals are searched, for this. But your explanation is a bit vague. What is this about Help buffer templates? And what is not easy about just adding a line like this to each `describe-*' command: (Info-make-manuals-xref function) ; Link to manuals. Yes, my overall patch is larger than that. It could be much smaller if your virtual indexing code allowed for links to more than one manual at a time. Likewise, if index-entry matching could optionally use an exact match. Those two enhancements would I think be welcome in any case. Anyway, my patch is attached, in case someone decides to go for it. ------=_NextPart_000_007D_01CC29D2.72CD9B50 Content-Type: application/octet-stream; name="help-fns-2011-06-13.patch" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="help-fns-2011-06-13.patch" diff -c -w help-fns.el help-fns-patched-2011-06-13.el=0A= *** help-fns.el Mon Jun 13 09:36:56 2011=0A= --- help-fns-patched-2011-06-13.el Mon Jun 13 11:20:32 2011=0A= ***************=0A= *** 212,217 ****=0A= --- 212,242 ----=0A= :group 'help=0A= :version "23.2")=0A= =0A= + (defcustom help-cross-reference-manuals '(("emacs" "elisp"))=0A= + "*Manuals to search, for a `*Help*' buffer link to the manuals.=0A= + A cons.=0A= + =0A= + The car is a list of manuals to search, or the symbol `all', to=0A= + search all. If nil, then do not create a cross-reference link.=0A= + =0A= + The cdr is a boolean:=0A= + =0A= + Non-`nil' means search the manuals, then create a cross-ref link:=0A= + create it only if some search hits are found.=0A= + =0A= + `nil' means create a cross-ref link without searching manuals=0A= + first (but only if there are some manuals to search)."=0A= + :set #'(lambda (sym defs)=0A= + (custom-set-default sym defs)=0A= + (setq Info-indexed-nodes ()))=0A= + :type '(cons=0A= + (choice :tag "Which Manuals"=0A= + (repeat :tag "Specific Manuals (files)" string)=0A= + (const :tag "All Manuals" all))=0A= + (boolean :tag "Search Before Creating Button?"))=0A= + :group 'help=0A= + :version "24.1")=0A= + =0A= (defun help-highlight-arg (arg)=0A= "Highlight ARG as an argument name for a *Help* buffer.=0A= Return ARG in face `help-argument-name'; ARG is also downcased=0A= ***************=0A= *** 586,593 ****=0A= (use (format ";\nuse `%s' instead." use))=0A= (t "."))=0A= "\n"))=0A= ! (insert "\n"=0A= ! (or doc "Not documented."))))))))=0A= =0A= =0C=0A= ;; Variables=0A= --- 611,619 ----=0A= (use (format ";\nuse `%s' instead." use))=0A= (t "."))=0A= "\n"))=0A= ! (insert "\n")=0A= ! (when doc (Info-make-manuals-xref function)) ; Link to = manuals.=0A= ! (insert (or doc "Not documented."))))))))=0A= =0A= =0C=0A= ;; Variables=0A= ***************=0A= *** 880,889 ****=0A= (princ output))))=0A= =0A= (with-current-buffer standard-output=0A= ;; Return the text we displayed.=0A= (buffer-string))))))))=0A= =0A= - =0A= ;;;###autoload=0A= (defun describe-syntax (&optional buffer)=0A= "Describe the syntax specifications in the syntax table of BUFFER.=0A= --- 906,915 ----=0A= (princ output))))=0A= =0A= (with-current-buffer standard-output=0A= + (unless valvoid (Info-make-manuals-xref variable)) ; = Link to manuals.=0A= ;; Return the text we displayed.=0A= (buffer-string))))))))=0A= =0A= ;;;###autoload=0A= (defun describe-syntax (&optional buffer)=0A= "Describe the syntax specifications in the syntax table of BUFFER.=0A= =0A= Diff finished. Mon Jun 13 11:46:48 2011=0A= ------=_NextPart_000_007D_01CC29D2.72CD9B50 Content-Type: application/octet-stream; name="info-2011-06-13.patch" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="info-2011-06-13.patch" diff -c -w info.el info-patched-2011-06-13.el=0A= *** info.el Mon Jun 13 09:44:32 2011=0A= --- info-patched-2011-06-13.el Mon Jun 13 13:54:26 2011=0A= ***************=0A= *** 2151,2156 ****=0A= --- 2151,2329 ----=0A= (Info-next-reference)=0A= (Info-next-reference))=0A= =0C=0A= + (defvar Info-indexed-file "*Indexed*"=0A= + "Info file for virtual manual from = `Info-index-entries-across-manuals'.")=0A= + =0A= + (defvar Info-indexed-nodes ()=0A= + "Alist of cached nodes with matching index entries.=0A= + Each element is (NODENAME STRING MATCHES), where:=0A= + NODENAME is the name of the node that is indexed,=0A= + STRING is the search string passed to `Info-index-occurrences',=0A= + MATCHES is a list of index matches found by `Info-index-occurrences'.=0A= + =0A= + This has the same structure as `Info-apropos-nodes', but the search=0A= + was made by `Info-index-occurrences', not by `Info-apropos-matches',=0A= + so that matches are exact.")=0A= + =0A= + (defun Info-indexed-find-file (filename &optional _noerror)=0A= + "Index-search implementation of `Info-find-file'."=0A= + filename)=0A= + =0A= + (defun Info-indexed-find-node (_filename nodename &optional = _no-going-back)=0A= + "Index-search implementation of `Info-find-node-2'."=0A= + (let* ((nodeinfo (assoc nodename Info-indexed-nodes))=0A= + (matches (nth 2 nodeinfo)))=0A= + (when matches=0A= + (insert (format "\n\^_\nFile: %s, Node: %s, Up: Top\n\n" = Info-indexed-file nodename))=0A= + (insert "Index Matches\n")=0A= + (insert "*************\n\n")=0A= + (insert "Index entries that match `" (nth 1 nodeinfo) "':\n\n")=0A= + (insert "\0\b[index\0\b]\n")=0A= + (if (eq matches t)=0A= + (insert "No matches found.\n")=0A= + (insert "* Menu:\n\n")=0A= + (dolist (entry matches)=0A= + (insert (format "* %-38s (%s)%s.%s\n" (format "%s [%s]:" = (nth 1 entry) (nth 0 entry))=0A= + (nth 0 entry) (nth 2 entry)=0A= + (if (nth 3 entry) (format " (line %s)" (nth = 3 entry)) ""))))))))=0A= + =0A= + (add-to-list 'Info-virtual-files '("\\`\\*Indexed\\*\\'"=0A= + (find-file . Info-indexed-find-file)=0A= + (find-node . = Info-indexed-find-node)))=0A= + =0A= + (defun Info-make-manuals-xref (symbol)=0A= + "Create a cross-ref link for index entries for SYMBOL in manuals.=0A= + `help-cross-reference-manuals' controls which manual(s) are searched.=0A= + Do nothing if its car is `nil' (no manuals to search).=0A= + If its cdr is `nil' then create the link without first searching any=0A= + manuals. Otherwise, create the link only if there are search hits in=0A= + the manuals."=0A= + (when (car help-cross-reference-manuals) ; Create no link if no = manuals to search.=0A= + (let ((manuals (car help-cross-reference-manuals))=0A= + (search-now-p (cdr help-cross-reference-manuals))=0A= + (symb-name (if (stringp symbol) symbol (symbol-name = symbol))))=0A= + (when (or (not search-now-p)=0A= + (save-current-buffer (Info-any-index-occurrences-p = symb-name manuals)))=0A= + (let ((buffer-read-only nil))=0A= + (insert (format "\n\nFor more information %s the "=0A= + (if (cdr help-cross-reference-manuals) "see" = "check")))=0A= + (help-insert-xref-button "manuals" 'help-info-manual-lookup = symb-name manuals)=0A= + (insert ".\n\n"))))))=0A= + =0A= + (define-button-type 'help-info-manual-lookup=0A= + :supertype 'help-xref=0A= + 'help-function #'(lambda (string &optional manuals)=0A= + (Info-index-entries-across-manuals string = manuals))=0A= + 'help-echo "mouse-2, RET: Look it up in the manuals")=0A= + =0A= + (defun Info-index-entries-across-manuals (string &optional manuals)=0A= + "Look up STRING in indexes of Info MANUALS on your system.=0A= + Looks for exact matches: STRING is expected to be an index entry.=0A= + Build an Info menu of the possible matches.=0A= + MANUALS has the form of `help-cross-reference-manuals'."=0A= + (let ((nodes Info-indexed-nodes)=0A= + nodename)=0A= + (while (and nodes (not (equal string (nth 1 (car nodes)))))=0A= + (setq nodes (cdr nodes)))=0A= + (if nodes=0A= + (Info-find-node Info-indexed-file (car (car nodes)))=0A= + (setq nodename (format "Index for `%s'" string))=0A= + (push (list nodename string (Info-index-occurrences string = manuals)) Info-indexed-nodes)=0A= + (Info-find-node Info-indexed-file nodename))))=0A= + =0A= + ;; Similar to `Info-apropos-matches', but using exact matches. =0A= + (defun Info-index-occurrences (index-entry &optional manuals)=0A= + "Collect occurrences of INDEX-ENTRY in MANUALS.=0A= + MANUALS has the form of `help-cross-reference-manuals'.=0A= + Return a list of the form ((FILE INDEX-ENTRY NODE LINE)), where:=0A= + FILE is the name of an Info file,=0A= + NODE is an Info node name,=0A= + LINE is the line number of the INDEX-ENTRY occurrence in that node."=0A= + (unless (string=3D index-entry "")=0A= + ;; Unlike `Info-apropos-matches', we match only the exact string = as an index entry.=0A= + (let ((pattern (format "\n\\* +\\([^\n]*%s\\):[ \t]+\\([^\n]+\\)\=0A= + \\.\\(?:[ \t\n]*(line +\\([0-9]+\\))\\)?"=0A= + (regexp-quote index-entry)))=0A= + matches index-nodes node)=0A= + (message "Searching indexes of %s..." (if (eq manuals 'all)=0A= + "all manuals"=0A= + (concat "manuals "=0A= + (mapconcat = #'identity manuals ", "))))=0A= + (condition-case nil=0A= + (with-temp-buffer=0A= + (Info-mode)=0A= + (Info-directory)=0A= + (goto-char (point-min))=0A= + (re-search-forward "\\* Menu: *\n" nil t)=0A= + (when (eq manuals 'all)=0A= + (setq manuals ())=0A= + (let (manual)=0A= + (while (re-search-forward "\\*.*: *(\\([^)]+\\))" nil = t)=0A= + ;; `add-to-list' ensures no dups in `manuals', so = the `dolist' runs faster.=0A= + (setq manual (match-string 1))=0A= + (set-text-properties 0 (length manual) nil manual)=0A= + (add-to-list 'manuals manual))))=0A= + (dolist (manual manuals)=0A= + (message "Searching indexes of manual `%s'..." manual)=0A= + (when (setq index-nodes (Info-index-nodes = (Info-find-file manual)))=0A= + (Info-find-node manual (car index-nodes))=0A= + (while (progn (goto-char (point-min))=0A= + (while (re-search-forward pattern nil t)=0A= + (setq matches (cons (list manual=0A= + = (match-string-no-properties 1)=0A= + = (match-string-no-properties 2)=0A= + = (match-string-no-properties 3))=0A= + matches)))=0A= + (setq index-nodes (cdr index-nodes)=0A= + node (car index-nodes)))=0A= + (Info-goto-node node)))))=0A= + (error nil))=0A= + matches)))=0A= + =0A= + ;; Like `Info-index-occurrences', but just return non-nil as soon as = we know there is a match.=0A= + (defun Info-any-index-occurrences-p (index-entry &optional manuals)=0A= + "Return non-nil if there are any occurrences of INDEX-ENTRY in = MANUALS.=0A= + MANUALS has the form of `help-cross-reference-manuals'."=0A= + (and (not (string=3D index-entry ""))=0A= + ;; Unlike `Info-apropos-matches', we match only the exact = string as an index entry.=0A= + (let ((pattern (format "\n\\* +\\([^\n]*%s\\):[ = \t]+\\([^\n]+\\)\=0A= + \\.\\(?:[ \t\n]*(line +\\([0-9]+\\))\\)?"=0A= + (regexp-quote index-entry)))=0A= + (any? nil)=0A= + index-nodes node)=0A= + (message "Searching indexes of %s..." (if (eq manuals 'all)=0A= + "all manuals"=0A= + (concat "manuals "=0A= + (mapconcat = #'identity manuals ", "))))=0A= + (condition-case nil=0A= + (with-temp-buffer=0A= + (Info-mode)=0A= + (Info-directory)=0A= + (goto-char (point-min))=0A= + (re-search-forward "\\* Menu: *\n" nil t)=0A= + (when (eq manuals 'all)=0A= + (setq manuals ())=0A= + (let (manual)=0A= + (while (re-search-forward "\\*.*: *(\\([^)]+\\))" = nil t)=0A= + ;; `add-to-list' ensures no dups in `manuals', so = the `dolist' runs faster.=0A= + (setq manual (match-string 1))=0A= + (set-text-properties 0 (length manual) nil manual)=0A= + (add-to-list 'manuals manual))))=0A= + (setq any? (catch 'Info-any-index-occurrences-p=0A= + (dolist (manual manuals)=0A= + (message "Searching indexes of manual = `%s'..." manual)=0A= + (when (setq index-nodes = (Info-index-nodes (Info-find-file manual)))=0A= + (Info-find-node manual (car = index-nodes))=0A= + (while (progn (goto-char (point-min))=0A= + (when = (re-search-forward pattern nil t)=0A= + (throw = 'Info-any-index-occurrences-p t))=0A= + (setq index-nodes (cdr = index-nodes)=0A= + node (car = index-nodes)))=0A= + (Info-goto-node node))))=0A= + nil)))=0A= + (error nil))=0A= + any?)))=0A= + =0C=0A= (add-to-list 'Info-virtual-nodes=0A= '("\\`\\*TOC\\*\\'"=0A= (find-node . Info-toc-find-node)=0A= =0A= Diff finished. Mon Jun 13 13:54:47 2011=0A= ------=_NextPart_000_007D_01CC29D2.72CD9B50--