;;; eev-code.el -- `code-c-d', that generates and evaluates Lisp defuns. ;; Copyright (C) 2012-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: 20201228 ;; Keywords: e-scripts ;; ;; Latest version: ;; htmlized: ;; See also: ;; ;; ;; (find-eev-intro) ;; (find-code-c-d-intro) ;;; Commentary: ;; This file defines `code-c-d', that is used to mass-produce ;; short(er) hyperlinks, as explained here: ;; ;; (find-eev-quick-intro "9. Shorter hyperlinks") ;; (find-eev-quick-intro "9.1. `code-c-d'") ;; ;; and it also defines `find-code-c-d', that is a debugging function ;; that can be considered as a hyperlink to templated text. Try: ;; ;; (find-code-c-d "CODE" "/DIR/" :info "INFO") ;; «.alists» (to "alists") ;; «.code-c-d-pairs» (to "code-c-d-pairs") ;; «.ee-tail-call2» (to "ee-tail-call2") ;; «.code-c-d» (to "code-c-d") ;; «.code-c-d-s» (to "code-c-d-s") ;;; _ _ _ ;;; __ _| (_)___| |_ ___ ;;; / _` | | / __| __/ __| ;;; | (_| | | \__ \ |_\__ \ ;;; \__,_|_|_|___/\__|___/ ;;; ;; «alists» (to ".alists") ;; A simple and flexible implementation of argument lists. ;; Inspired by: (find-node "(cl)Argument Lists") ;; (find-node "(cl)Argument Lists" "&body") ;; See also: (find-elnode "Symbol Type" ":" "keyword") ;; (find-elnode "Constant Variables") ;; Test: (ee-aref '((1 . one) (2 . two) (3 . three)) 2) ;; -> two (defun ee-aref (alist idx) "Like `aref', but for alists. Example: (ee-aref '((1 . one) (2 . two) (3 . three)) 2) -> two" (cdr (assoc idx alist))) ;; Test: (ee-adel '((1 . one) (2 . two) (3 . three)) 2) ;; -> ((1 . one) (3 . three)) ;; (defun ee-adel (alist idx) "Like `remq', but for alists. This is non-destructive, so wrap it in a setq. Example: (ee-adel '((1 . one) (2 . two) (3 . three)) 2) -> ((1 . one) (3 . three))" (remq (assoc idx alist) alist)) ;; Test: (ee-aset '((1 . one) (2 . two) (3 . three)) 2 'foo) ;; -> ((2 . foo) (1 . one) (3 . three)) ;; (defun ee-aset (alist idx newelt) "Like `aset', but for alists. This is non-destructive, so wrap it in a setq. Example: (ee-aset '((1 . one) (2 . two) (3 . three)) 2 'foo) -> ((2 . foo) (1 . one) (3 . three))" (cons (cons idx newelt) (ee-adel alist idx))) ;; Tests: (ee-areplace '((1 . one) (2 . two) (3 . three)) 2 'foo) ;; -> ((1 . one) (2 . foo) (3 . three)) ;; (ee-areplace '((1 . one) (2 . two) (3 . three)) 0 'zero) ;; -> ((0 . zero) (1 . one) (2 . two) (3 . three)) ;; (defun ee-areplace (alist idx newelt) "Like `ee-aset', but keeping the order. Examples: (ee-areplace '((1 . one) (2 . two) (3 . three)) 2 'foo) -> ((1 . one) (2 . foo) (3 . three)) (ee-areplace '((1 . one) (2 . two) (3 . three)) 0 'zero) -> ((0 . zero) (1 . one) (2 . two) (3 . three))" (if (ee-aref alist idx) (progn (setcdr (assoc idx alist) newelt) alist) (cons (cons idx newelt) alist))) ;;; _ _ _ ;;; ___ ___ __| | ___ ___ __| | _ __ __ _(_)_ __ ___ ;;; / __/ _ \ / _` |/ _ \_____ / __|____ / _` |_____| '_ \ / _` | | '__/ __| ;;; | (_| (_) | (_| | __/_____| (_|_____| (_| |_____| |_) | (_| | | | \__ \ ;;; \___\___/ \__,_|\___| \___| \__,_| | .__/ \__,_|_|_| |___/ ;;; |_| ;; ;; «code-c-d-pairs» (to ".code-c-d-pairs") ;; Used by: (find-eev "eev-elinks.el" "ee-code-c-d-filter") (defvar ee-code-c-d-pairs nil "Each (code-c-d C D) call generates an entry (C (ee-expand D)) here. A new entry with the same C as a previous one will replace the previous one. This list is maintained by `ee-code-c-d-add-pair' and is used by `ee-find-xxxfile-sexps' and `find-file-links'.") (defun ee-code-c-d-add-pair (c d) (setq ee-code-c-d-pairs (ee-areplace ee-code-c-d-pairs c (list d)))) ;;; _ _ _ _ _ ;;; ___ ___ | |_ __ _(_) | ___ __ _| | | ;;; / _ \/ _ \_____| __/ _` | | |_____ / __/ _` | | | ;;; | __/ __/_____| || (_| | | |_____| (_| (_| | | | ;;; \___|\___| \__\__,_|_|_| \___\__,_|_|_| ;;; ;; «ee-tail-call2» (to ".ee-tail-call2") ;; The name "tail call" is misleading - this is recursive, ;; but not a tail call in the usual sense. ;; 2019mar29: commented out. ;; Moved its functionality into `ee-code-c-d-rest'. ;;(defun ee-tail-call2 (fmt c d rest) ;; "An internal function used to support keyword-argument pairs." ;; (cond ((null rest) "") ;; ((keywordp (car rest)) ;; (apply (intern (format fmt (car rest))) ;; c d (cdr rest))) ;; (t (error "Wrong rest: %S" rest)))) ;;; _ _ ;;; ___ ___ __| | ___ ___ __| | ;;; / __/ _ \ / _` |/ _ \_____ / __|____ / _` | ;;; | (_| (_) | (_| | __/_____| (_|_____| (_| | ;;; \___\___/ \__,_|\___| \___| \__,_| ;;; ;; «code-c-d» (to ".code-c-d") ;; See: (find-eev-quick-intro "9.1. `code-c-d'") ;; Try: (find-code-c-d "lua51" "~/usrc/lua-5.1.4/") ;; (find-code-c-d "lua51" "~/usrc/lua-5.1.4/" :anchor) ;; (find-code-c-d "lua51" "~/usrc/lua-5.1.4/" :tags :w3m) ;; code-c-d: top-level functions ;; (defun code-c-d (c d &rest rest) "See: (find-code-c-d-intro) Try this: (find-code-c-d \"CODE\" \"/DIR/\" :info \"INFO\")" (ee-code-c-d-add-pair c d) (eval (ee-read (apply 'ee-code-c-d c d rest)))) (defun find-code-c-d (c d &rest rest) (find-estring-elisp (apply 'ee-code-c-d c d rest))) (defun ee-code-c-d (c d &rest rest) (if (stringp (car rest)) (setq rest (cons :info rest))) (concat (ee-code-c-d-base c d) (ee-code-c-d-rest c d rest))) ;; Support for extra arguments (defun ee-code-c-d-rest (c d rest) (cond ((null rest) "") ((keywordp (car rest)) (apply (intern (format "ee-code-c-d-%S" (car rest))) c d (cdr rest))) (t (error "Wrong rest: %S" rest)))) (defun find-code-c-d-rest (c d &rest rest) (find-estring-elisp (ee-code-c-d-rest c d rest))) (defun ee-code-c-d-base (c d) (ee-template0 "\ ;; {(ee-S `(find-code-c-d ,c ,d ,@rest))} ;; {(ee-S `(ee-code-c-d-base ,c ,d))} ;; See: (find-eev-quick-intro \"9.1. `code-c-d'\") ;; (setq ee-{c}dir \"{d}\") (defun ee-{c}file (str) (concat (ee-expand ee-{c}dir) str)) (defun find-{c}file (str &rest pos-spec-list) (interactive (list \"\")) (apply 'find-fline (ee-{c}file str) pos-spec-list)) (defun find-{c}sh (command &rest pos-spec-list) (apply 'find-sh-at-dir ee-{c}dir command pos-spec-list)) (defun find-{c}sh0 (command) (funcall 'ee-find-xxxsh0 ee-{c}dir command)) (defun find-{c}sh00 (command) (funcall 'ee-find-xxxsh00 ee-{c}dir command)) (defun find-{c}grep (grep-command-args &rest pos-spec-list) (apply 'ee-find-grep ee-{c}dir grep-command-args pos-spec-list)) ")) (defun ee-code-c-d-:info (c d info &rest rest) (concat (ee-template0 " ;; {(ee-S `(ee-code-c-d-:info ,c ,d ,info ,@rest))} (defun find-{c}node (page &rest pos-spec-list) (interactive (list \"\")) (setq ee-info-code \"{c}\") ;; for M-h M-i (setq ee-info-file \"{info}\") ;; for M-h M-i (apply 'find-node (format \"({info})%s\" page) pos-spec-list)) ") (ee-code-c-d-rest c d rest))) (defun ee-code-c-d-:linfo (c d manual &rest rest) (concat (ee-template0 " ;; {(ee-S `(ee-code-c-d-:linfo ,c ,d ,manual ,@rest))} (defun find-{c}node (section &rest pos-spec-list) (interactive (list \"\")) (apply 'ee-find-node ee-{c}dir \"{manual}\" section pos-spec-list)) ") (ee-code-c-d-rest c d rest))) (defun ee-code-c-d-:gz (c d &rest rest) (concat (ee-template0 " ;; {(ee-S `(ee-code-c-d-:gz ,c ,d ,@rest))} (defun find-{c}file (str &rest pos-spec-list) (interactive (list \"\")) ;; (ee-use-{c}-tags) (apply 'find-fline-gz (ee-{c}file str) pos-spec-list)) ") (ee-code-c-d-rest c d rest))) (defun ee-code-c-d-:anchor (c d &rest rest) (concat (ee-template0 " ;; {(ee-S `(ee-code-c-d-:anchor ,c ,d ,@rest))} (defun find-{c} (str &rest pos-spec-list) (apply 'find-anchor (ee-{c}file str) pos-spec-list)) ") (ee-code-c-d-rest c d rest))) (defun ee-code-c-d-:tags (c d &rest rest) (concat (ee-template0 " ;; {(ee-S `(ee-code-c-d-:anchor ,c ,d ,@rest))} (setq ee-{c}tagsfile \"{d}TAGS\") (defun ee-use-{c}-tags () (setq tags-file-name ee-{c}tagsfile)) (defun find-{c}tag (str &rest pos-spec-list) (ee-use-{c}-tags) (apply 'ee-find-tag str pos-spec-list)) (defun find-{c}file (str &rest pos-spec-list) (interactive (list \"\")) (ee-use-{c}-tags) (apply 'find-fline (ee-{c}file str) pos-spec-list)) ") (ee-code-c-d-rest c d rest))) (defun ee-code-c-d-:w3m (c d &rest rest) (concat (ee-template0 " ;; {(ee-S `(ee-code-c-d-:gz ,c ,d ,@rest))} (defun find-{c}w3m (furl &rest pos-spec-list) (apply 'find-w3m (ee-{c}file furl) pos-spec-list)) ") (ee-code-c-d-rest c d rest))) (defun ee-code-c-d-:wget (c d url &rest rest) (concat (ee-template0 " ;; {(ee-S `(ee-code-c-d-:wget ,c ,d ,url ,@rest))} (defun ee-{c}url (semiurl) (concat \"{url}\" semiurl)) (defun find-{c}wget (semiurl &rest pos-spec-list) (interactive (list \"\")) (apply 'find-wget (ee-{c}url semiurl) pos-spec-list)) ") (ee-code-c-d-rest c d rest))) (defun ee-code-c-d-:grep (c d &rest rest) (ee-code-c-d-rest c d rest)) ; compat ;; Support functions. ;; Maybe I should rewrite some of them using `ee-at0'... ;; (defun ee-find-node (dir manual page &rest pos-spec-list) (apply 'find-node (format "(%s%s)%s" dir manual page) pos-spec-list)) (defun ee-find-grep (dir grep-command-args &rest pos-spec-list) "Example: (ee-find-grep ee-eetcdir \"grep -niH -e tetris *\") Note: the POS-SPEC-LIST arguments are currently not used." (let ((default-directory (ee-expand (or dir default-directory)))) (grep grep-command-args))) (defun ee-find-xxxsh (dir command &rest pos-spec-list) "Run COMMAND at DIR and display the result. See `code-c-d'." (apply 'find-sh (format "cd %s\n%s" dir command) pos-spec-list)) (defun ee-find-xxxsh0 (dir command) "Run COMMAND at DIR and return the result. See `code-c-d'." (find-sh0 (format "cd %s\n%s" dir command))) (defun ee-find-xxxsh00 (dir command) "Run COMMAND at DIR and return the result. See `code-c-d'." (find-sh00 (format "cd %s\n%s" dir command))) (defun ee-find-tag (tag &rest pos-spec-list) (let ((tags-add-tables nil)) (find-tag tag)) (ee-goto-rest pos-spec-list)) ;; a test ;; (find-estring-elisp (ee-code-c-d-base "@@@" "!!!")) ;; (find-estring-elisp (ee-code-c-d "CCC" "DDD")) ;;; _ _ ;;; ___ ___ __| | ___ ___ __| |___ ;;; / __/ _ \ / _` |/ _ \_____ / __|____ / _` / __| ;;; | (_| (_) | (_| | __/_____| (_|_____| (_| \__ \ ;;; \___\___/ \__,_|\___| \___| \__,_|___/ ;;; ;; «code-c-d-s» (to ".code-c-d-s") ;; Some default `code-c-d's (debian-centric). (defun ee-locate-library (fname) (if (locate-library fname) (file-name-directory (locate-library fname)))) (defvar ee-eev-source-directory (ee-locate-library "eev-code.el")) (defvar ee-emacs-lisp-directory (or (ee-locate-library "loadup.el") (format "/usr/share/emacs/%d.%d/lisp/" emacs-major-version emacs-minor-version))) (defvar ee-emacs-leim-directory (or (ee-locate-library "leim-list.el") (format "/usr/share/emacs/%d.%d/leim/" emacs-major-version emacs-minor-version))) (code-c-d "e" ee-emacs-lisp-directory "emacs" :gz) ; (find-enode "Top") (code-c-d "el" ee-emacs-lisp-directory "elisp" :gz) ; (find-elnode "Top") (code-c-d "eli" ee-emacs-lisp-directory "eintr" :gz) ; (find-elinode "Top") (code-c-d "cl" (ee-efile "emacs-lisp/") "cl" :gz) ; (find-clnode "Top") (code-c-d "eleim" ee-emacs-leim-directory :gz) (code-c-d "equail" (ee-eleimfile "quail/") :gz) (code-c-d "eetc" data-directory :gz) (code-c-d "eev" ee-eev-source-directory :anchor) ; (find-eev "") ;; (find-efile "") ;; (find-equailfile "") ;; (find-equailfile "latin-ltx.el") ;; Debian: (code-c-d "ud" "/usr/share/doc/" :gz) ; (find-udfile "bash/") (code-c-d "vldi" "/var/lib/dpkg/info/") ; (find-vldifile "bash.list") ;; Used by `find-epackage-links': (code-c-d "elpa" "~/.emacs.d/elpa/") ;; (find-elpafile "") (provide 'eev-code) ;; Local Variables: ;; coding: utf-8-unix ;; no-byte-compile: t ;; End: