;;; eev-hlinks.el --- `find-here-links' and variants. ;; Copyright (C) 2020 Free Software Foundation, Inc. ;; ;; This file is part of GNU eev. ;; ;; GNU eev is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; GNU eev is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;; ;; Author: Eduardo Ochs ;; Maintainer: Eduardo Ochs ;; Version: 20201231 ;; Keywords: e-scripts ;; ;; Latest version: ;; htmlized: ;; See also: ;; ;; ;; (find-eev-intro) ;; (find-here-links-intro) ;;; Commentary: ;; This file implements `find-here-links', its variants for beginners, ;; and the many low-level functions that are needed to make them work. ;; ;; `find-here-links' generates a temporary buffer with links to ;; "here". There are several kinds of "here"s - see: ;; ;; (find-here-links-intro "3. `find-here-links'") ;; (find-here-links-intro "3. `find-here-links'" "several kinds") ;; ;; The "here" buffer is sometimes called the "target" buffer. See: ;; ;; (find-here-links-intro "4. `find-here-links-3'") ;; (find-here-links-intro "4. `find-here-links-3'" "terminology") ;; ;; For each kind of "here" we have a "test function" that tests if the ;; current buffer is of that kind of here and a "links function" that ;; generates links for that kind of here. Here's the conventions on ;; their names. A sexp like ;; ;; (find-man "1 date") ;; ;; opens a manpage buffer; the test function and the links function ;; for manpage buffers are: ;; ;; (ee-man-bufferp) ;; (ee-find-man-links) ;; ;; They all have the same stem - "man" - but different prefixes and ;; suffixes. ;; TODO: Some of the `ee-find-*-links' functions are defined in other ;; files. Which ones? Give examples! ;; ;; (find-eapropos "ee-find-.*-links") ;; The main workhorse function in this file is `ee-find-here-links', ;; that _currently_ uses a big `cond' to run these test functions in a ;; certain order until one of them returns true, and then it returns ;; the result of the links function associated to that test (and to ;; that kind of "here"). But I am trying to rewrite it... ;; «.ee-types-of-here» (to "ee-types-of-here") ;; «.tests-and-links» (to "tests-and-links") ;; «.ee-which-here-tests» (to "ee-which-here-tests") ;; ;; «.find-here-links» (to "find-here-links") ;; «.find-here-links-beginner» (to "find-here-links-beginner") ;; «.find-here-links-3» (to "find-here-links-3") ;;; __ _ _ _ _ _ _ ;;; / _(_)_ __ __| | | |__ ___ _ __ ___ | (_)_ __ | | _____ ;;; | |_| | '_ \ / _` |_____| '_ \ / _ \ '__/ _ \_____| | | '_ \| |/ / __| ;;; | _| | | | | (_| |_____| | | | __/ | | __/_____| | | | | | <\__ \ ;;; |_| |_|_| |_|\__,_| |_| |_|\___|_| \___| |_|_|_| |_|_|\_\___/ ;;; ;; «find-here-links» (to ".find-here-links") ;; See: (find-eev-quick-intro "`M-h M-h'") ;; (find-efunction 'find-grep-links) ;; (find-efunction 'find-einfo-links) ;; (find-efunction 'find-file-links) ;; (find-find-links-links "\\M-h" "here" "") ;; (find-efunction 'find-ecolors) ;; Moved the key binding to: ;; (find-eevfile "eev-mode.el" "\\M-h\\M-h") ;; (define-key eev-mode-map "\M-h\M-h" 'find-here-links) ;; TODO: support cases like these: ;; (find-efunctiondescr 'condition-case) ;;; _ __ _ ;;; | |_ _ _ _ __ ___ ___ ___ / _| | |__ ___ _ __ ___ ;;; | __| | | | '_ \ / _ \/ __|_____ / _ \| |_ _____| '_ \ / _ \ '__/ _ \ ;;; | |_| |_| | |_) | __/\__ \_____| (_) | _|_____| | | | __/ | | __/ ;;; \__|\__, | .__/ \___||___/ \___/|_| |_| |_|\___|_| \___| ;;; |___/|_| ;; ;; «ee-types-of-here» (to ".ee-types-of-here") ;; New code. Not working yet. Commented out. ;; Ugliness: `ee-add-type-of-here' runs `sort' too often. ;; See: (find-eev "eev-code.el" "alists") ;; (find-elnode "Sequence Functions" "Function: sort ") ' (progn (setq ee-types-of-here nil) (defun ee-sort-types-of-here () (setq ee-types-of-here (sort ee-types-of-here (lambda (a b) (string< (car a) (car b)))))) (defun ee-add-type-of-here (priority testcode linkscode) (let* ((label (format "%s %s" priority (ee-S testcode)))) (setq ee-types-of-here (ee-aset ee-types-of-here label (list testcode linkscode))))) (defun ee-add-toh-major (testcode linkscode) (ee-add-type-of-here "20 major" testcode linkscode)) (defun ee-add-toh-bname (testcode linkscode) (ee-add-type-of-here "40 bname" testcode linkscode)) (defun ee-add-toh-bhelp (testcode linkscode) (ee-add-type-of-here "60 help " testcode linkscode)) (defun ee-add-toh-other (testcode linkscode) (ee-add-type-of-here "80 other" testcode linkscode)) ;; By major mode: (ee-add-toh-major '(ee-info-bufferp) '(ee-find-info-links)) (ee-add-toh-major '(ee-man-bufferp) '(ee-find-man-links)) (ee-add-toh-major '(ee-grep-bufferp) '(ee-find-grep-links)) (ee-add-toh-major '(ee-w3m-bufferp) '(ee-find-w3m-links)) (ee-add-toh-major '(ee-dired-bufferp) '(ee-find-file-links)) (ee-add-toh-major '(ee-wdired-bufferp) '(ee-find-file-links)) (ee-add-toh-major '(ee-custom-bufferp) '(ee-find-custom-links)) (ee-add-toh-major '(ee-epackages-bufferp) '(ee-find-epackages-links)) ;; By buffer name: (ee-add-toh-bname '(ee-intro-bufferp) '(ee-find-intro-links)) (ee-add-toh-bname '(ee-ecolors-bufferp) '(ee-find-ecolors-links)) (ee-add-toh-bname '(ee-efaces-bufferp) '(ee-find-efaces-links)) ;; (ee-add-toh-bname '(ee-freenode-bufferp) '(ee-find-freenode-links)) ;; (ee-add-toh-bname '(ee-pdftext-bufferp) '(ee-find-pdftext-links)) ;; When the buffer name is "*Help*" we parse the first line: (ee-add-toh-bhelp '(ee-efunctiondescr-bufferp) '(ee-find-efunctiondescr-links)) (ee-add-toh-bhelp '(ee-efacedescr-bufferp) '(ee-find-efacedescr-links)) (ee-add-toh-bhelp '(ee-evardescr-bufferp) '(ee-find-evardescr-links)) (ee-add-toh-bhelp '(ee-epackage-bufferp) '(ee-find-epackage-links)) ;; Other cases: (ee-add-toh-other '(ee-file-bufferp) '(ee-find-file-links)) (ee-sort-types-of-here) ;; Inspect the data structures: ;; (find-epp ee-types-of-here) ;; (find-estring (mapconcat 'car ee-types-of-here "\n")) ) ;;; _ _ _ _ _ _ ;;; | |_ ___ ___| |_ ___ __ _ _ __ __| | | (_)_ __ | | _____ ;;; | __/ _ \/ __| __/ __| / _` | '_ \ / _` | | | | '_ \| |/ / __| ;;; | || __/\__ \ |_\__ \ | (_| | | | | (_| | | | | | | | <\__ \ ;;; \__\___||___/\__|___/ \__,_|_| |_|\__,_| |_|_|_| |_|_|\_\___/ ;;; ;; «tests-and-links» (to ".tests-and-links") ;; For each kind of here we have: ;; a) a test function that tests if the current buffer is of that kind, ;; b) a function that return hyperlinks for that kind of here. ;; ;; Idea: rename them, and use names like: ;; ee-here-info-p ;; ee-here-info-links ;; Some tools for detecting which kind of buffer we're in. (defun ee-buffer-re (re) (if (string-match re (buffer-name)) (match-string 1 (buffer-name)))) (defun ee-buffer-eq (str) (string= str (buffer-name))) (defun ee-buffer-help0 () (ee-buffer-eq "*Help*")) (defun ee-buffer-help-re0 (re n) (if (ee-buffer-help0) (save-excursion (goto-char (point-min)) (if (looking-at re) (match-string n))))) (defun ee-buffer-help (re n) (intern (or (ee-buffer-help-re0 re n) "nil"))) ;; By major mode (defun ee-grep-bufferp () (eq major-mode 'grep-mode)) (defun ee-man-bufferp () (eq major-mode 'Man-mode)) (defun ee-rcirc-bufferp () (eq major-mode 'rcirc-mode)) (defun ee-info-bufferp () (eq major-mode 'Info-mode)) (defun ee-dired-bufferp () (eq major-mode 'dired-mode)) (defun ee-wdired-bufferp () (eq major-mode 'wdired-mode)) (defun ee-w3m-bufferp () (eq major-mode 'w3m-mode)) (defun ee-custom-bufferp () (eq major-mode 'Custom-mode)) (defun ee-epackages-bufferp () (eq major-mode 'package-menu-mode)) ;; By buffer name (defun ee-intro-bufferp () (ee-buffer-re "^\\*(find-\\(.*\\)-intro)\\*$")) (defun ee-freenode-bufferp () (ee-buffer-re "^\\(.*\\).freenode\\.net")) (defun ee-ecolors-bufferp () (ee-buffer-eq "*Colors*")) (defun ee-efaces-bufferp () (ee-buffer-eq "*Faces*")) (defun ee-pdftext-bufferp () (ee-buffer-re "^pdftotext")) ;; By buffer name (when it is "*Help*") (defvar ee-efunctiondescr-re "^\\([^ \t\n]+\\) is a[^\t\n]*\\(function\\|Lisp macro\\|special form\\)") (defun ee-efunctiondescr-bufferp () (ee-buffer-help ee-efunctiondescr-re 1)) (defun ee-find-efunctiondescr-links () (let ((f (ee-efunctiondescr-bufferp))) `((find-efunction-links ',f) (find-efunctiondescr ',f)))) (defvar ee-evardescr-re "^\\([^ \t\n]+\\) is a variable") (defun ee-evardescr-bufferp () (ee-buffer-help ee-evardescr-re 1)) (defun ee-find-evardescr-links () (let ((v (ee-evardescr-bufferp))) `((find-evariable-links ',v) (find-evardescr ',v)))) (defvar ee-efacedescr-re "^Face: \\([^ \t\n]+\\)") (defun ee-efacedescr-bufferp () (ee-buffer-help ee-efacedescr-re 1)) (defun ee-find-efacedescr-links () (let ((f (ee-efacedescr-bufferp))) `((find-eface-links ',f) (find-efacedescr ',f)))) (defvar ee-epackage-re "^\\([^ \t\n]+\\) is a[ -~]+ package") (defvar ee-epackage-re-27 "^Package \\([^ \t\n]+\\) is") ; for Emacs 27 (defun ee-epackage-bufferp () (or (ee-buffer-help ee-epackage-re 1) (ee-buffer-help ee-epackage-re-27 1))) (defun ee-find-epackage-links () (let ((p (ee-epackage-bufferp))) (list (ee-find-epackage-links0 p "{c}" "{d}")))) ;; By buffer name (when the mode is man) (defvar ee-man-re "^\\*Man \\(.*\\)\\*$") (defun ee-find-man-links () (let ((mp (ee-buffer-re ee-man-re))) `((find-man ,mp)))) (defvar ee-custom-re "^\\*Customize Group: \\(.*\\)\\*$") (defun ee-find-custom-links () (let* ((name (ee-buffer-re ee-custom-re)) (symbol (intern (downcase (replace-regexp-in-string " " "-" name))))) `((find-customizegroup ',symbol)))) ;; Other cases (defun ee-file-bufferp () buffer-file-name) (defun ee-find-dired-links () `((find-extra-file-links ,(ee-dired-to-fname 'no-error)) "" ,@(ee-find-file-links))) (defun ee-find-efaces-links () `((find-efaces))) (defun ee-find-ecolors-links () `((find-ecolors))) (defun ee-find-epackages-links () `((find-epackages))) (defun ee-find-pdftext-links () (ee-pdflike-page-links)) ;; to to: ;; ee-find-w3m-links ;; ee-find-ecolor-links ;; (defun ee-find-here-links () (cond ;; by major mode ((ee-info-bufferp) (cons "" (ee-find-info-links))) ; M-h M-i ((ee-man-bufferp) (cons "" (ee-find-man-links))) ; ? ((ee-grep-bufferp) (cons "" (ee-find-grep-links))) ; M-h M-g ((ee-w3m-bufferp) (cons "" (ee-find-w3m-links))) ; M-h M-w ;; ((ee-dired-bufferp) (cons "" (ee-find-dired-links))) ; ? ((ee-dired-bufferp) (cons "" (ee-find-file-links))) ; M-h f ((ee-wdired-bufferp) (cons "" (ee-find-file-links))) ; M-h f ((ee-custom-bufferp) (cons "" (ee-find-custom-links))) ; ? ((ee-epackages-bufferp) (cons "" (ee-find-epackages-links))) ; ? ;; by buffer name ((ee-intro-bufferp) (cons "" (ee-find-intro-links))) ; M-h M-i ((ee-freenode-bufferp) (cons "" (ee-find-freenode-links))) ; ? ((ee-ecolors-bufferp) (cons "" (ee-find-ecolors-links))) ; ? ((ee-efaces-bufferp) (cons "" (ee-find-efaces-links))) ; ? ((ee-pdftext-bufferp) (cons "" (ee-find-pdftext-links))) ; ? ;; by buffer name, when it is "*Help*" ((ee-efunctiondescr-bufferp) (cons "" (ee-find-efunctiondescr-links))) ((ee-efacedescr-bufferp) (cons "" (ee-find-efacedescr-links))) ((ee-evardescr-bufferp) (cons "" (ee-find-evardescr-links))) ((ee-epackage-bufferp) (cons "" (ee-find-epackage-links))) ;; other cases ((ee-file-bufferp) (cons "" (ee-find-file-links))) ; M-h f (t (list "" "Not implemented!" "See:" '(find-efunction 'ee-find-here-links))) )) (defun find-here-links-test (sexp) "See: (find-links-intro \"`find-here-links'\")" (find-wset "13o_2o_o" sexp '(find-here-links))) ;; (find-man "1 cat") ;; (progn (find-man "1 cat") (buffer-name)) ;; (find-eevfile "eev-rcirc.el") (defun ee-find-here-links0 () `(,(ee-H "See: ") (find-eev-quick-intro "4.1. `find-here-links'") (find-emacs-keys-intro "1. Basic keys (eev)" "M-h M-h") (find-here-links-intro "4. `find-here-links-3'") )) ;;; __ _ _ _ _ _ _ ;;; / _(_)_ __ __| | | |__ ___ _ __ ___ | (_)_ __ | | _____ ;;; | |_| | '_ \ / _` |_____| '_ \ / _ \ '__/ _ \_____| | | '_ \| |/ / __| ;;; | _| | | | | (_| |_____| | | | __/ | | __/_____| | | | | | <\__ \ ;;; |_| |_|_| |_|\__,_| |_| |_|\___|_| \___| |_|_|_| |_|_|\_\___/ ;;; ;; (find-find-links-links "\\M-h" "here" "") ;; (defun find-here-links (&rest pos-spec-list) "Visit a temporary buffer containing hyperlinks pointing to here." (interactive) (apply 'find-elinks `(;; The first line of a find-here-links buffer DOES NOT ;; regenerates the buffer - instead the first lines point to ;; help pages. ,@(ee-find-here-links0) ,@(ee-find-here-links) ) pos-spec-list)) ;; Test: (find-here-links) ;; (progn (find-enode "Screen") (find-here-links)) ;;; _ _ ;;; | |__ ___ __ _(_)_ __ _ __ ___ _ __ ;;; | '_ \ / _ \/ _` | | '_ \| '_ \ / _ \ '__| ;;; | |_) | __/ (_| | | | | | | | | __/ | ;;; |_.__/ \___|\__, |_|_| |_|_| |_|\___|_| ;;; |___/ ;; ;; «find-here-links-beginner» (to ".find-here-links-beginner") ;; This is a hack for beginners that is explained in a tutorial. See: ;; (find-refining-intro "4. A tip for beginners") ;; (find-refining-intro "4. A tip for beginners" "find-here-links-beginner") ;; (defun find-here-links-beginner (&optional arg) "A variant of `find-here-links' that may create a three-window setting." (interactive "P") (if arg (find-here-links-3) (find-here-links))) ;; «find-here-links-3» (to ".find-here-links-3") ;; See: (find-here-links-intro "4. `find-here-links-3'") ;; (find-here-links-intro "5. `find-here-links-1'") ;; (defvar ee-window-configuration-before-M-h-M-3 nil) (defun find-here-links-3 () "A variant of `find-here-links' that creates a three-window setting. Before creating the three windows this function tries to save the current window configuration to the variable `ee-window-configuration-before-M-h-M-3', but if that variable is not nil we abort instead of overwriting it. See: (find-here-links-intro \"4. `find-here-links-3'\")" (interactive) (if ee-window-configuration-before-M-h-M-3 (let ((overwrite (yes-or-no-p "Overwrite `ee-window-configuration-before-M-h-M-3'? "))) (if (not overwrite) (error)))) (setq ee-window-configuration-before-M-h-M-3 (current-window-configuration)) (find-wset "13_o2_o_coo" nil '(find-here-links) '(eejump-1))) (defun find-here-links-1 () "Restore the window configuration before `find-here-links-3'. See: (find-here-links-intro \"5. `find-here-links-1'\")" (interactive) (set-window-configuration ee-window-configuration-before-M-h-M-3) (setq ee-window-configuration-before-M-h-M-3 nil)) (provide 'eev-hlinks) ;; Local Variables: ;; coding: utf-8-unix ;; no-byte-compile: t ;; End: