;;; eev.el -- add support for e-scripts in Emacs.

;; Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008
;; 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 2, 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; see the file COPYING.  If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
;;
;; Author:     Eduardo Ochs <eduardoochs@gmail.com>
;; Maintainer: Eduardo Ochs <eduardoochs@gmail.com>
;; Version:    2008jul07
;; Keywords:   e-scripts, help, hyperlinks, hypertext, processes,
;;             shell, tex
;;
;; Latest version: <http://angg.twu.net/eev-current/eev.el>
;;       htmlized: <http://angg.twu.net/eev-current/eev.el.html>
;;       See also: <http://angg.twu.net/eev-current/README.html>
;;            and: <http://angg.twu.net/eev-current/eev-langs.el.html>

;;; Commentary:

;; A good introduction to eev is the article about it (called "Emacs
;; and eev, or: How to Automate Almost Everything"). Here's a link to
;; the article: <http://angg.twu.net/eev-article.html>.
;;
;; When I started using GNU Emacs in 1994 I immediately realized that
;; it could be used as my main interface to the system; essentially,
;; due to the way that Lisp was integrated in Emacs, by programming
;; just a few functions I could keep "executable logs" of everything
;; that I did... so I wrote `find-fline', `find-node', `eev' and
;; `code-c-d', and I knew that by using them I would soon learn enough
;; to be able to write the other functions that I needed.
;;
;; My central idea with eev - and I was so isolated that it took me
;; about five years to realize that it should really be called "my
;; idea" instead of "the way that Emacs was intended to be used" - was
;; that _everything that we do once should be easy to repeat later_.
;; This "everything" included not only executing commands at shell
;; prompts but also opening files, manpages, manuals in Info format,
;; etc, and locating information in them... At that time graphical
;; interfaces were not so prevalent, and it was quite natural then to
;; just dismiss them as a flawed idea; GUIs suggest that everything
;; should be done with "magic buttons", while Emacs (with eev) offers
;; us an alternative: instead of magic buttons whose innards are
;; hidden we can use small programs - often one-liners - that when
;; executed (and executing them shouldn't be much harder than pressing
;; a button) worked as buttons whose lids are open, with their inner
;; structure visible...
;;
;; "Buttons" to open files, info nodes, manpages, etc, were very easy
;; to implement as one-liners in Lisp; and it was trivial to put those
;; "sexp buttons" in almost all kinds of text files. In programs and
;; scripts they would appear after a comment sign; there would be at
;; most one of those per line, and they would always be the rightmost
;; part of a line. In plain text files we just had to warn possible
;; readers that the sexps sprinkled throught the text were "buttons" -
;; or, in modern terminology, "hyperlinks"... And in order to make
;; those buttons "work" in a file, i.e., be executable, we just had to
;; open the file in Emacs.
;;
;; The interface for executing blocks of shell commands was a bit more
;; unusual, as those blocks looked even less like buttons that the
;; hyperlink sexps did... I realized that I could suppose that:
;;   1) the user who would execute a block of shell command would know
;;      what (s)he was doing;
;;   2) the user executing a block of shell commands would generally be
;;      the same person who wrote the block;
;;   3) both would usually be me; 8-|
;;   4) the user executing a block knows on inspection which lines
;;      (s)he wants to execute, and (s)he can select those lines
;;      manually and issue a command - `M-x eev', typically - to save
;;      those lines in a temporary script; also, (s)he can switch to a
;;      shell and issue a command ("ee") that means "execute the lines
;;      stored in the temporary script";
;;   5) it is possible to send commands to other interpreters besides
;;      shells; the user knows this, and knows how to identify the
;;      language of each block, and knows the commands for sending the
;;      block for each of the supported interpreters.
;; One design decision forced itself on eev from the beginning: Emacs
;; should NOT, NEVER, EVER try to detect sexp hyperlinks or blocks of
;; commands, or the interpreter associated with a block of commands,
;; by itself; hyperlinks and blocks of commands were just plain text
;; with no special mark-up, and the user would be responsible by
;; selecting parts of a text himself and executing them in the right
;; way.
;;
;; That being so, it's no wonder that most people when confronted with
;; eev find it super-weird - especially nowadays, as everyone has got
;; used to Emacs being very good at syntactical analysis and context
;; detection. The idea of a user going over his notes, sometimes
;; adding text or making changes, and sometimes selecting manually a
;; block to execute - by running a function that would "do something
;; on the current block", where both this "something to do" and the
;; notion of the "current block" would depend on the function - now
;; might look very alien - but it was quite natural in the mid-90's...
;;
;; (By the way: the "current block" can be the sexp before point, or
;; the sexp that ends at the end of the current line; or the "region"
;; in Emacs, i.e., the text between "point" and "mark", of everything
;; around point until the first occurrence backwards and forward of
;; certain delimiters - other notions of "current block" are possible
;; but not common. And the "do something on the current block" can be
;; "execute it as lisp", "save it into a temporary script", "save it
;; in a temp script then run a program", etc.)
;;
;; The compensation for this apparent weirdness of eev is that
;; implementing support for sending commands to a new interpreter - or
;; for a new kind of hyperlink - is usually something that is
;; accomplished in a handful of lines of Lisp at most - see the
;; definitions for most "find-" functions in this file, and the file
;; (find-eevfile "eev-langs.el").
;;
;; So, one of the most important parts of eev is its extensibility. It
;; is - or it should be - trivial to extend it to support new external
;; interpreters and new kinds of "buttons" or "hyperlinks". Also,
;; sometimes people complain that they can't understand what's the
;; essence of eev; well, here are two articles about that:
;;
;;   <http://www.gnu.org/software/emacs/emacs-paper.html>
;;   <http://www.multicians.org/mepap.html>
;;
;; The "kernel" of eev, morally, is these functions,
;;   (find-efunctiondescr 'find-fline)
;;   (find-efunctiondescr 'find-node)
;;   (find-efunctiondescr 'eev)
;;   (find-efunctiondescr 'code-c-d)
;; and, to a much lesser degree, the ones in "eev-insert.el" and
;; "eev-steps.el":
;;   (find-eevfile "eev-insert.el")
;;   (find-eevfile "eev-steps.el")

;; <unfinished, as lots of docs in this file and elsewhere>
;; <the central point is that people should be using sexps much more,
;; everywhere - why - free software - programming for everyone>
;; <add a pointer to Forth>

;; How to install eev:
;; ===================
;; (find-file "INSTALL")
;; (find-file "eev-rctool")
;;
;; How to try eev without installing it:
;; =====================================
;; (add-to-list 'load-path "~/eev-current/")
;; (add-to-list 'load-path default-directory)
;; (require 'eev)
;; (eev-mode 1)
;; (ee-invade-global-namespace)
;; (require 'eev-insert)
;; (require 'eev-steps)
;; (require 'eev-glyphs)
;; (require 'eev-compose)
;; (eev-set-default-glyphs)
;;
;; Starting points (mainly docstrings):
;; ====================================
;; (find-efunctiondescr 'find-fline)
;; (find-efunctiondescr 'find-node)
;; (find-efunctiondescr 'eev)
;; (find-efunctiondescr 'eev-mode)
;; (find-efunctiondescr 'eev-mode "`pop-up-windows' is off")
;; (find-efunctiondescr 'code-c-d)
;; (find-eevfile "eev-insert.el" "create and display a buffer")
;; (find-efunctiondescr 'eemklinks-yank-pos-spec)
;; (find-efunctiondescr 'eesteps)

;; About the naming of function in this file
;; =========================================
;; Many functions in this file have very short names. This is
;; because they are intended to be used in one-liners in comments,
;; like this:
;;   (find-node "(emacs)Lisp Eval" "C-x C-e")
;;
;; Note: the "C-x C-e" part of the hyperlink above is a "pos-spec". Most
;; hyperlink functions defined by eev support "pos-spec-lists"; see:
;;   (find-efunctiondescr 'ee-goto-position)
;;
;; Prefixes:
;;   "find-"    functions are hyperlinks.
;;   "find-e"   functions are hyperlinks to "Emacs things".
;;   "ee"       execute block or send it to an external program
;;   "ee-"      internal functions (and variables).
;; Suffixes:
;;   "0"        means "more low-level", and
;;   "00"       means "even more low-level". For example:
;;   "sh"       means "run on a shell, display the output in a buffer",
;;   "sh0"      means "run on a shell, display the output in the echo area",
;;   "sh00"     means "same as `sh0', but don't strip the last newline";
;;   "pp"       means "pretty-print a sexp, display the result in a buffer",
;;   "pp0"      means "pretty-print a sexp, display in the echo area"
;; Prefixes and suffixes:

;;   "eeb-"     bounded wrapper (see eev-bounded)
;;   "-bounded" bounded wrapper (see eev-bounded)

;;   "find-"    functions are generated by `(code-c-d "xxx" ...)'.


;; Structure of this file:
;; autoloads for external functions
;; environment variables
;; variables
;; basic hyperlinks: find-fline and find-node
;; support for pos-specs in hyperlinks
;; hyperlinks to anchors
;; hyperlinks to the output of Emacs's help-like functions
;; hyperlinks to the source code of Emacs functions and variables
;; hyperlinks to buffers
;; pretty-printing sexps
;; hyperlinks to other things internal to Emacs
;; hyperlinks to the output of shell commands
;; hyperlinks to manpages
;; hyperlinks to files in html
;; hyperlinks to pages in dvi/ps/pdf documents
;; around point / ask
;; hyperlinks to information about Debian packages
;; code-ps/dvi: mass-producing hyperlink functions
;; code-c-d: mass-producing hyperlink functions
;; examples of calls to code-c-d (debian-centric)
;; temporary highlighting (flashing)
;; evaluating sexps (alternatives to eval-last-sexp)
;; eev and friends (or: saving regions as temporary scripts)
;; setting `pop-up-windows' to nil inside eev-mode
;; eev mode keymap
;; eev mode
;; invading the global namespace
;; aliases for compatibility with previous versions

;; For printing:
;; (find-angg ".emacs" "eea2ps")
;; (progn (find-eev "eev.el") (eea2ps3 (point-min) (point-max)))

;; Big letters courtesy of Figlet.




;;;              _        _                 _     
;;;   __ _ _   _| |_ ___ | | ___   __ _  __| |___ 
;;;  / _` | | | | __/ _ \| |/ _ \ / _` |/ _` / __|
;;; | (_| | |_| | || (_) | | (_) | (_| | (_| \__ \
;;;  \__,_|\__,_|\__\___/|_|\___/ \__,_|\__,_|___/
;;;                                               
;;; autoloads for external functions
;; (find-elnode "Autoload")

(autoload 'Info-goto-node "info")
(autoload 'Info-find-node "info")
(autoload 'find-function-read "find-func")
(autoload 'pp-to-string "pp")
(autoload 'Man-fontify-manpage "man" nil t)
(autoload 'word-at-point "thingatpt")
(autoload 'list-iso-charset-chars     "mule-diag")
(autoload 'list-non-iso-charset-chars "mule-diag")



;;;   ___ _ ____   __  __   ____ _ _ __ ___ 
;;;  / _ \ '_ \ \ / /  \ \ / / _` | '__/ __|
;;; |  __/ | | \ V /    \ V / (_| | |  \__ \
;;;  \___|_| |_|\_/      \_/ \__,_|_|  |___/
;;;
;;; Set some environment variables (for ee-expand, getenv,
;;; shell buffers, xterms started from Emacs, etc).

;; (find-eevrcfile ".bashrc")
;; (find-eevrcfile ".zshrc")

(defun ee-expand (fname)
"Expand \"~\"s and \"$ENVVAR\"s in file names, but only at the beginning of the string."
  (cond ((string-match "^\\$\\([A-Za-z_][0-9A-Za-z_]*\\)\\(.*\\)" fname)
         (concat (getenv (match-string 1 fname))
                 (match-string 2 fname)))
        ((string-match "^\\(~\\([a-z][0-9a-z_]*\\)?\\)\\(/.*\\)?$" fname)
         (concat (expand-file-name (match-string 1 fname))
                 (match-string 3 fname)))
        (t fname)))

(defun ee-setenv (envvar value)
  "In case the environment variable ENVVAR was not set set it to VALUE."
  (if (null (getenv envvar))
      (setenv envvar (ee-expand value))))

(ee-setenv "EEVDIR"
           (let ((fname (locate-library "eev")))
             (if fname (directory-file-name (file-name-directory fname))
               "$HOME/eev-current")))   ; eev.el, etc
(ee-setenv "EEVTMPDIR" "$HOME/.eev")    ; ee.sh and other temp scripts

(ee-setenv "EEVRCDIR"  "$EEVDIR/rcfiles")
(ee-setenv "EE"        "$EEVTMPDIR/ee.sh")
(ee-setenv "EEG"       "$EEVTMPDIR/ee.eeg")
(ee-setenv "EEGDB"     "$EEVTMPDIR/ee.gdb")
(ee-setenv "EETEX"     "$EEVTMPDIR/ee.tex")
(ee-setenv "EEC"       "$EEVTMPDIR/ee.c")
(ee-setenv "EETMPC"    "$EEVTMPDIR/tmp.c")
(ee-setenv "EEAOUT"    "$EEVTMPDIR/ee.aout")

(ee-setenv "S"         "$HOME/snarf")   ; for `find-psne-links'





;;;                  _       _     _
;;;                 (_)     | |   | |          
;;; __   ____ _ _ __ _  __ _| |__ | | ___  ___ 
;;; \ \ / / _` | '__| |/ _` | '_ \| |/ _ \/ __|
;;;  \ V / (_| | |  | | (_| | |_) | |  __/\__ \
;;;   \_/ \__,_|_|  |_|\__,_|_.__/|_|\___||___/
;;;
;;; variables
;;;

(defvar ee-eevdir       (ee-expand "$EEVDIR/")
  "The directory where the elisp files for eev live.")
(defvar ee-eevtmpdir    (ee-expand "$EEVTMPDIR/")
  "The directory where the temporary script files are put.")
(defvar ee-eevrcdir     (ee-expand "$EEVRCDIR/")
  "The directory where some auxiliary rcfiles for eev are to be found.")

(defvar ee-file         (ee-expand "$EE")
  "The temporary script file used by `eev'.")
(defvar ee-file-tex     (ee-expand "$EETEX")
  "The temporary script file used by `eelatex'.")
(defvar ee-file-gdb     (ee-expand "$EEGDB")
  "The temporary script file used by `eegdb'.")
(defvar ee-file-generic (ee-expand "$EEG"))

(defvar eelatex-eevscript
  "cd $EEVTMPDIR/; latex tmp.tex && xdvi tmp.dvi &" "See `eelatex'.")
(defvar ee-anchor-format       nil       "See `ee-goto-anchor'.")

;; To do: check where these variables are used and unify them.
;; (find-eev "eev-insert.el")
(defvar ee-hyperlink-prefix "# ")
(defvar ee-comment-prefix "# ")

;; Emacs 22 needs these `put's. See:
;; (find-elnode "File Local Variables" "`safe-local-variable' property")
(put 'ee-anchor-format     'safe-local-variable 'stringp)
(put 'ee-comment-prefix    'safe-local-variable 'stringp)
(put 'ee-hyperlink-prefix  'safe-local-variable 'stringp)

(defvar ee-find-man-flag nil)           ; for asynchronous `ee-goto-position's
(defvar ee-find-man-pos-spec-list nil)  ; for asynchronous `ee-goto-position's
(defvar ee-buffer-name nil)             ; overridden by `let's
(defvar ee-arg nil)                     ; overridden by `let's
(defvar ee-info-file nil)               ; for eev-insert.el
(defvar ee-info-code nil)               ; for eev-insert.el
(defvar ee-pop-up-windows nil)          ; for an eegud hack, not working

;; (setq eeb-highlight-spec '(highlight 0.2))
(defvar ee-highlight-spec  '(highlight 0.75)) ; to do: rename highlight->flash
(defvar eeb-highlight-spec '(highlight 0.5))
(defvar eek-highlight-spec '(region 0.75))
(defvar eeflash-default '(highlight 0.5))

;; (defvar eev-mode-map nil)            ; moved down to make the html nicer
;; (defvar eev-mode-global-settings-restorer nil)   ; below
;; (defvar eev-mode-global-settings-saver ...)      ; below

;; (defvar code-c-d-keywords nil                    ; below
;;   "An alist of (KEYWORD . SEXP) pairs. See `code-c-d'.")

(defvar code-c-d-list nil
  "Each (code-c-d C D) call generates an entry (C (ee-expand D)) in this list.
A new entry with the same C as a previous one removes the old
one. This list is maintained by `code-c-d-register' and is used
by some functions in \"eev-insert.el\".")





;;;  _               _        _ _       _        
;;; | |__   __ _ ___(_) ___  | (_)_ __ | | _____ 
;;; | '_ \ / _` / __| |/ __| | | | '_ \| |/ / __|
;;; | |_) | (_| \__ \ | (__  | | | | | |   <\__ \
;;; |_.__/ \__,_|___/_|\___| |_|_|_| |_|_|\_\___/
;;;                                              
;;; Basic links: find-fline and find-noe

(defun find-fline (fname &rest pos-spec-list)
  "Hyperlink to a file (or a directory).
This function is similar to `find-file' but it supports a
\"pos-spec-list\" - see `ee-goto-position'.
Examples:\n
  (find-file  \"~/.emacs\")
  (find-fline \"~/.emacs\")
  (find-fline \"~/.emacs\" \"Beginning of the eev block\")"
  (find-file (ee-expand fname))
  (apply 'ee-goto-position pos-spec-list))

(defun find-node (nodestr &rest pos-spec-list)
  "Hyperlink to an info page.
This function is similar to `info' but it supports a
\"pos-spec-list\" - see `ee-goto-position'.
Examples:\n
  (info \"(emacs)Lisp Eval\")
  (find-node \"(emacs)Lisp Eval\" \"C-x C-e\")"
  (Info-goto-node nodestr)
  (apply 'ee-goto-position pos-spec-list))



;;;                                                _ _     _       
;;;  _ __   ___  ___       ___ _ __   ___  ___    | (_)___| |_ ___ 
;;; | '_ \ / _ \/ __| ___ / __| '_ \ / _ \/ __|___| | / __| __/ __|
;;; | |_) | (_) \__ \|___|\__ \ |_) |  __/ (__|___| | \__ \ |_\__ \
;;; | .__/ \___/|___/     |___/ .__/ \___|\___|   |_|_|___/\__|___/
;;; |_|                       |_|                                   
;;;
;;; support for pos-spec-lists in hyperlinks
;;;

(defun ee-goto-position (&optional pos-spec &rest rest)
  "Process the \"absolute pos-spec-lists\" arguments in hyperlink functions.
POS-SPEC, the first element of a pos-spec-list, is treated
specially; if it is a string then jump to the first occurrence of
that string in the buffer, and if it a number jump to the line
with that number in the buffer; if it is nil, do nothing.

The rest of the pos-spec-list, REST, is treated by
`ee-goto-rest'.

Many kinds of hyperlinks - for example,

  (find-efunction 'ee-goto-position)

already jump to specific positions of a buffer; those hyperlink
functions support \"relative pos-spec-lists\", and they invoke
`ee-goto-rest' straight away to handle their pos-spec-lists -
they skip the first \"absolute\" pos-spec."
  (when pos-spec
    (cond ((numberp pos-spec)
           (goto-char (point-min))
           (forward-line (1- pos-spec)))
          ((stringp pos-spec)
           (goto-char (save-excursion             ; This used to be just:
                        (goto-char (point-min))   ; (goto-char (point-min))
                        (search-forward pos-spec) ; (search-forward pos-spec)
                        (point))))                ;
          (t (error "This is not a valid pos-spec: %S" pos-spec)))
    (if rest (ee-goto-rest rest))))

(defun ee-goto-rest (list)
  "Process \"relative pos-spec-lists\".
For each element in LIST, if it is:

  a string -> jump to the next occurrence of that string in the
              current buffer
  a number -> go down that many lines
  a list   -> evaluate the list (take care!)

anything else generates an error - but users are encouraged to
create their own extended versions of this function and override
the standard definition."
  (cond ((null list))
        ((stringp (car list))
         (search-forward (car list))
         (ee-goto-rest (cdr list)))
        ((numberp (car list))
         (forward-line (car list))
         (ee-goto-rest (cdr list)))
        ((consp (car list))
         (eval (car list))
         (ee-goto-rest (cdr list)))
        (t (error "Not a valid pos-spec item: %S" (car list)))))




;;;                   _                    
;;;   __ _ _ __   ___| |__   ___  _ __ ___ 
;;;  / _` | '_ \ / __| '_ \ / _ \| '__/ __|
;;; | (_| | | | | (__| | | | (_) | |  \__ \
;;;  \__,_|_| |_|\___|_| |_|\___/|_|  |___/
;;;
;;; hyperlinks to anchors
;;;

(defun ee-format-as-anchor (tag)
  "Convert TAG into an anchor using `ee-anchor-format'."
  (if ee-anchor-format
      (format ee-anchor-format tag)
    (error "`ee-anchor-format' is nil - can't convert string to anchor")))

(defun ee-goto-anchor (&optional tag &rest rest)
  "Like `ee-goto-position', but TAG is converted to an anchor.
If the anchor obtained from TAG is not found then issue an error
but do not move point.
For example, if `ee-anchor-format' is \"<<%s>>\" then

  (ee-goto-anchor \"foo\" \"bar\")

searches for the first occurrence of \"<<foo>>\" in the current
buffer, then for the first occurrence of \"bar\" after that. If
\"<<foo>>\" is not found then do not move point.

It is good style to set `ee-goto-anchor' globally to nil and only
use anchors in files where `ee-anchor-format' is declared in the
local variables section of the file; see:

  (find-node \"(emacs)File Variables\")
  (find-node \"(emacs)Specifying File Variables\")

a hint: one way of forcing reloading the local variables by hand
is by running `\\[normal-mode]'. 

The glyphs defined in (find-eev \"eev-glyphs.el\") can be used to
make anchors using characters that stand out."
  (if tag (goto-char
           (save-excursion
             (goto-char (point-min))
             (search-forward (ee-format-as-anchor tag))
             (point))))
  (ee-goto-rest rest))



(defun find-anchor (fname &optional tag &rest pos-spec-list)
  "Like `find-fline', but TAG is converted to an anchor if not nil.
See `ee-goto-anchor'."
  (find-fline fname)
  (apply 'ee-goto-anchor tag pos-spec-list))

(defun ee-to (tag &rest pos-spec-list)
  "Like `find-anchor', but does not switch to another buffer or file."
  ;; To do: include an example of an index.
  ;; Maybe a link to a files in "examples/"? (find-eevexfile "lua.e")
  (interactive "sAnchor: ")
  (apply 'ee-goto-anchor tag pos-spec-list))




;;;   __ _           _                    _   _   _     
;;;  / _(_)_ __   __| |    __      _____ | |_| |_| |__  
;;; | |_| | '_ \ / _` |____\ \ /\ / / _ \| __| __| '_ \ 
;;; |  _| | | | | (_| |_____\ V  V / (_) | |_| |_| |_) |
;;; |_| |_|_| |_|\__,_|      \_/\_/ \___/ \__|\__|_.__/ 
;;;
;;; hyperlinks to the output of Emacs's help-like functions
;;;

(defun find-wottb-call (sexp bufname &rest pos-spec-list)
  "Hyperlink to functions that call `with-output-to-temp-buffer'.
First evaluate SEXP with a trick to not let it split the current window,
then switch to the buffer that it created (it must be called BUFNAME),
then go to the position specified by POS-SPEC-LIST.\n
\(This is a horrible hack.)"
  (let ((same-window-buffer-names
         (cons bufname same-window-buffer-names)))
    (eval sexp))
  (set-buffer bufname)                  ; why is this needed?
  (apply 'ee-goto-position pos-spec-list))

(defun find-eapropos (regexp &rest pos-spec-list)
  "Hyperlink to the result of running `apropos' on REGEXP."
  (interactive "sApropos symbol (regexp): ")
  (apply 'find-wottb-call '(apropos regexp) "*Apropos*" pos-spec-list))

(defun find-efunctiondescr (symbol &rest pos-spec-list)
  "Hyperlink to the result of running `describe-function' on SYMBOL."
  (interactive (find-function-read))
  (apply 'find-wottb-call '(describe-function symbol) "*Help*" pos-spec-list))

(defun find-evariabledescr (symbol &rest pos-spec-list)
  "Hyperlink to the result of running `describe-variable' on SYMBOL."
  (interactive (find-function-read 'variable))
  (apply 'find-wottb-call '(describe-variable symbol) "*Help*" pos-spec-list))

(defalias 'find-evardescr 'find-evariabledescr)

(defun find-ekeydescr (key &rest pos-spec-list)
  "Hyperlink to the result of running `describe-key' on KEY."
  (interactive "kFind function on key: ")
  (apply 'find-wottb-call '(describe-key key) "*Help*" pos-spec-list))

(defun find-efacedescr (face &rest pos-spec-list)
  "Hyperlink to the result of running `describe-face' on FACE."
  (interactive (list (read-face-name "Describe face")))
  (apply 'find-wottb-call '(describe-face face) "*Help*" pos-spec-list))

(defun find-efaces (&rest pos-spec-list)
  "Hyperlink to the result of running `list-faces-display'."
  (interactive)
  (apply 'find-wottb-call '(list-faces-display) "*Faces*" pos-spec-list))

(defun find-ecolors (&rest pos-spec-list)
  "Hyperlink to the result of running `list-colors-display'."
  (interactive)
  (apply 'find-wottb-call '(list-colors-display) "*Colors*" pos-spec-list))

(defun find-efunctiond (function &rest pos-spec-list)
  "Hyperlink to the result of running `disassemble' on FUNCTION."
  (interactive (find-function-read))
  (apply 'find-wottb-call '(disassemble function) "*Disassemble*"
         pos-spec-list))




;;;   __ _           _            __                  _   _             
;;;  / _(_)_ __   __| |      ___ / _|_   _ _ __   ___| |_(_) ___  _ __  
;;; | |_| | '_ \ / _` |____ / _ \ |_| | | | '_ \ / __| __| |/ _ \| '_ \ 
;;; |  _| | | | | (_| |____|  __/  _| |_| | | | | (__| |_| | (_) | | | |
;;; |_| |_|_| |_|\__,_|     \___|_|  \__,_|_| |_|\___|\__|_|\___/|_| |_|
;;;                                                                      
;;; hyperlinks to the source code of Emacs functions and variables
;;;

(defun find-ebufferandpos (buffer-and-pos &rest pos-spec-list)
  "Internal use; hyperlink to a \"buffer and pos\" structure.
Emacs has some standard (i.e., non-eev) functions that can be
used as hyperlinks, like `find-function' and `find-variable';
they call internal functions like `find-function-noselect' and
`find-variable-noselect', that return structures of the form
BUFFER-AND-POS, that are conses like (#<buffer foo> . 42). This
function jumps to the position described by a cons like that, and
then processes an optional relative POS-SPEC-LIST using
`ee-goto-rest'.

Functions like `find-efunction' and `find-evariable' (defined in
eev.el) are wrappers around `find-function' and `find-variable'
that add support for a relative pos-spec-list after the symbol."
  (if (not (bufferp (car buffer-and-pos)))
      (error "Bad (BUFFER . POS): %S" buffer-and-pos))
  (switch-to-buffer (car buffer-and-pos))
  (goto-char (cdr buffer-and-pos))
  (ee-goto-rest pos-spec-list))

(defun find-efunction (symbol &rest pos-spec-list)
  "Hyperlink to the result of running `find-function' on SYMBOL.
The `find-function' function of Emacs can be used as a hyperlink
- it finds the Elisp source code of SYMBOL -, but it doesn't
support a POS-SPEC-LIST like this function does."
  (interactive (find-function-read))
  (apply 'find-ebufferandpos (find-function-noselect symbol) pos-spec-list))

(defun find-evariable (symbol &rest pos-spec-list)
  "Hyperlink to the result of running `find-variable' on SYMBOL."
  (interactive (find-function-read 'variable))
  (apply 'find-ebufferandpos (find-variable-noselect symbol) pos-spec-list))

(defun find-eCfunction (fun &rest pos-spec-list)
  "Hyperlink to the source in C for an Emacs primitive."
  (interactive (find-function-read))
  (apply 'find-ebufferandpos
         (find-function-search-for-symbol
          fun nil (help-C-file-name (indirect-function fun) 'fun))
         pos-spec-list))

(defun find-eCvariable (symbol &rest pos-spec-list)
  "Hyperlink to the definition in the C source of an Emacs variable."
  (interactive (find-function-read 'variable))
  (apply 'find-ebufferandpos
         (find-variable-noselect
          symbol (help-C-file-name symbol 'var))
         pos-spec-list))




;;;   __ _           _            _            __  __           
;;;  / _(_)_ __   __| |       ___| |__  _   _ / _|/ _| ___ _ __ 
;;; | |_| | '_ \ / _` |_____ / _ \ '_ \| | | | |_| |_ / _ \ '__|
;;; |  _| | | | | (_| |_____|  __/ |_) | |_| |  _|  _|  __/ |   
;;; |_| |_|_| |_|\__,_|      \___|_.__/ \__,_|_| |_|  \___|_|   
;;;                                                             
;;; Hyperlinks to buffers

(defun find-ebuffer (buffer &rest pos-spec-list)
  "Hyperlink to an Emacs buffer (existing or not)."
  (interactive "bBuffer: ")
  (switch-to-buffer buffer)
  (apply 'ee-goto-position pos-spec-list))

;; `find-escratchbuffer', `find-eoutput', `find-eeffect' are obsolete -
;; use `find-eoutput-reuse' and `find-eoutput-rerun' instead.
;;
(defun find-escratchbuffer (buffer-name &rest pos-spec-list)
  "Hyperlink to an empty scratch buffer named BUFFER-NAME.
If a buffer named BUFFER-NAME exists then try to kill it with
`kill-buffer' to create a scratch buffer in its place. If the
buffer contains something precious then `kill-buffer' will ask
the user for confirmation; if the user decides not to kill the
buffer then this function aborts with an error."
  (if (get-buffer buffer-name)
      (if (kill-buffer buffer-name)
          (switch-to-buffer buffer-name)
        (error "Not killing the buffer %s" buffer-name))
    (switch-to-buffer buffer-name)))

(defun find-eoutput (code &rest pos-spec-list)
  "Hyperlink to the output of running CODE in an empty scratch buffer.
CODE is run again every time this hyperlink if followed; compare
with `find-eeffect' and `find-sh'."
  (find-escratchbuffer (or ee-buffer-name "*output*"))
  ;; (delete-region (point-min) (point-max))
  (eval code)
  (goto-char (point-min))
  (apply 'ee-goto-position pos-spec-list))

(defun find-eeffect (ee-buffer-name code &rest pos-spec-list)
  "Hyperlink to the effect of running CODE in Emacs.
If the buffer EE-BUFFER-NAME does not exist then create it and
run CODE there; if the buffer already exists then reuse it -
suppose that its contents are already the result of running CODE
and do not run CODE again."
  (if (get-buffer ee-buffer-name)
      (apply 'find-ebuffer ee-buffer-name pos-spec-list)
    (find-ebuffer ee-buffer-name)
    (eval code)
    (set-buffer-modified-p nil)
    (goto-char (point-min))
    (apply 'ee-goto-position pos-spec-list)))





;;;   __ _           _                        _               _   
;;;  / _(_)_ __   __| |       ___  ___  _   _| |_ _ __  _   _| |_ 
;;; | |_| | '_ \ / _` |_____ / _ \/ _ \| | | | __| '_ \| | | | __|
;;; |  _| | | | | (_| |_____|  __/ (_) | |_| | |_| |_) | |_| | |_ 
;;; |_| |_|_| |_|\__,_|      \___|\___/ \__,_|\__| .__/ \__,_|\__|
;;;                                              |_|              
;; find-eoutput-rerun and find-eoutput-reuse.
;; 2007jul07: I finally copied this from eev-mini.el to here.
;; "find-eoutput", and "find-eeffect", above, are obsolete.
;; All functions that used to call them should call these.
;;
;; Note that the code for the older "find-eoutput" and "find-eeffect"
;; functions, above, had some mentions of checking if the buffer was a
;; scratch buffer before deleting its contents. Should we implement
;; some "test of scratchness" here, or should we just warn people
;; using these functions that they should follow the convention that
;; buffers with names like "*this*" are scratch buffers, and functions
;; based on these should name their buffers in this way?

(defun find-eoutput-rerun (buffer-name code &rest pos-spec-list)
  "Hyperlink to the effect of running CODE in Emacs.
If the buffer BUFFER-NAME does not exist then create it and run
CODE in it. If the buffer already exists, then \"run CODE
again\" (compare with `find-output-reuse'): delete the buffer,
recreate it, and run CODE in it.\n
For simplicity we are deleting the buffer and then recreating it,
but it could be better to just delete the buffer's contents. This
needs to be thought out."
  (if (get-buffer buffer-name)            ; if the buffer exists
      (if (not (kill-buffer buffer-name)) ; try to kill it; confirm if needed
          (error "Not killing the buffer %s" buffer-name)))
  (switch-to-buffer buffer-name)          ; create the buffer
  (eval code)                             ; always run CODE on the empty buffer
  (goto-char (point-min))
  (apply 'ee-goto-position pos-spec-list))

(defun find-eoutput-reuse (buffer-name code &rest pos-spec-list)
  "Hyperlink to the effect of running CODE in Emacs.
If the buffer BUFFER-NAME does not exist then create it and run
CODE in it. If the buffer already exists, then \"reuse
it\" (compare with `find-output-rerun'): switch to it, ignore the
CODE argument, and process the POS-SPEC-LIST."
  (if (get-buffer buffer-name)          ; if the buffer exists
      (switch-to-buffer buffer-name)    ; then just switch to it
    (switch-to-buffer buffer-name)      ; otherwise switch to it and
    (eval code)                         ; run CODE to produce its contents
    (goto-char (point-min)))
  (apply 'ee-goto-position pos-spec-list))

(defun find-estring (string &rest pos-spec-list)
  "Visit a temporary buffer whose contents are given by STR.
The default name for the buffer is \"*string*\", but this can be
overriden by setting `ee-buffer-name' to another name with a `let'.
If the buffer already exists its contents are destroyed.
The buffer is not made read-only."
  (apply 'find-eoutput-rerun (or ee-buffer-name "*string*")
         `(insert ,string) pos-spec-list))

(defun find-estring-elisp (string &rest pos-spec-list)
  "Visit a temporary buffer whose contents are given by STR.
This function is similar to `find-estring', but this one also
runs `emacs-lisp-mode' in the buffer."
  (apply 'find-eoutput-rerun (or ee-buffer-name "*string*")
         `(progn (insert ,string) (emacs-lisp-mode)) pos-spec-list))







;;;   __ _           _                        
;;;  / _(_)_ __   __| |      ___ _ __  _ __  
;;; | |_| | '_ \ / _` |____ / _ \ '_ \| '_ \ 
;;; |  _| | | | | (_| |____|  __/ |_) | |_) |
;;; |_| |_|_| |_|\__,_|     \___| .__/| .__/ 
;;;                             |_|   |_|    
;;; pretty-priting sexps

;; "pp0" -> "pretty-print a Lisp object in a very compact way".
;;
(defun ee-pp0 (object &optional tick)
  "Convert OBJECT (usually a sexp) into a string, for use in hyperlinks.
Quote newlines to make it fit in a single line.
If TICK is non-nil and OBJECT is a list then precede it with a \"'\".
The result of this function is always a string that can be `read' as Lisp."
  (let ((str (let ((print-escape-newlines t)
                   (print-escape-nonascii t) ; isn't escaping esc, \r, etc
                   (print-quoted t))
               (prin1-to-string object))))
    (setq str (replace-regexp-in-string "\r" "\\\\r" str))
    (if (and tick (consp object))
        (setq str (concat "'" str)))
    str))

(defun find-epp0 (object)
  "Display a pretty-printed version of OBJECT in the echo area.
This function uses `message' and so it only makes sense to call
it from commands bound to keys, not by sexps that are evaluated
explicitly. Try this: (progn (message \"foo\") \"bar\")"
  (message (ee-pp0 object)))

(defun find-epp (object &rest pos-spec-list)
  "Visit a temporary buffer containing a pretty-printed version of OBJECT."
  (let ((ee-buffer-name (or ee-buffer-name "*pp*")))
    (apply 'find-estring (pp-to-string object) pos-spec-list)))

(defun find-efunctionpp (symbol &rest pos-spec-list)
"Visit a temporary buffer containing the pretty-printed Lisp code for SYMBOL."
  (interactive (find-function-read))
  (let ((ee-buffer-name
         (or ee-buffer-name (format "*function %S*" symbol))))
    (apply 'find-epp
           (symbol-function symbol)
           ;; Note: if instead of the above we use
           ;;  `(fset ',symbol ',(symbol-function symbol))
           ;; the we get a buffer in which we can edit the code for SYMBOL.
           pos-spec-list)))

(defun find-etpat (&rest pos-spec-list)
"Hyperlink to a pretty-version of the result of (text-properties-at (point))."
  (interactive)
  (let* ((ee-buffer-name
          (or ee-buffer-name "*(text-properties-at (point))*")))
    (apply 'find-epp (text-properties-at (point)) pos-spec-list)))

(defun find-etpat0 ()
  "Show the result of (text-properties-at (point)) in the echo area."
  (interactive)
  (find-epp0 (text-properties-at (point))))




;;;   __ _           _                             
;;;  / _(_)_ __   __| |       _____  ____  ____  __
;;; | |_| | '_ \ / _` |_____ / _ \ \/ /\ \/ /\ \/ /
;;; |  _| | | | | (_| |_____|  __/>  <  >  <  >  < 
;;; |_| |_|_| |_|\__,_|      \___/_/\_\/_/\_\/_/\_\
;;;                                                
;;; hyperlinks to other things internal to Emacs

;; Bug: `list-iso-charset-chars' and friends are not defined in the
;; Unicode-2 branch of Emacs...

(defun find-echarsetchars (charset &rest pos-spec-list)
  "See: (find-efunction 'list-charset-chars)
Examples: (find-echarsetchars 'mule-unicode-0100-24ff \"733x\")
          (find-echarsetchars 'mule-unicode-2500-33ff)"
  (interactive (list (read-charset "Character set: ")))
  (apply 'find-eoutput-reuse "*charset*"
         '(cond ((charsetp charset)
                 (list-iso-charset-chars charset))
                ((assq charset non-iso-charset-alist)
                 (list-non-iso-charset-chars charset))
                (t (error "Invalid character set %s" charset)))
         pos-spec-list))

(defun find-eccldump (ccl-code &rest pos-spec-list)
  "Hyperlink to the result of running `ccl-dump' on CCL-CODE.
Example: (find-eccldump ccl-decode-mule-utf-8)"
  (apply 'find-eoutput-reuse "*ccl-dump*"
         `(ccl-dump ,ccl-code) pos-spec-list))

(defun find-ekeymapdescr (keymap &rest pos-spec-list)
  "Hyperlink to the list of bindings in KEYMAP.
Example: (find-ekeymapdescr isearch-mode-map \"toggle-regexp\")"
  ;; To do: add the buttons/link thing
  (apply 'find-estring (substitute-command-keys "\\<keymap>\\{keymap}")
         pos-spec-list))

(defun ee-minor-mode-keymap (mode-symbol)
  "An auxiliary function for `find-ekeymapdescr'.
Example: (find-ekeymapdescr (ee-minor-mode-keymap 'eev-mode))"
  (cdr (assq mode-symbol minor-mode-map-alist)))

(defun ee-insert (&rest rest)
  "Insert characters, strings, or ranges of characters.
Example: (ee-insert '(?a ?z) 10 \"Foo!\")"
  (while rest
    (let ((o (car rest)))
      (cond ((stringp o) (insert o))
            ((numberp o) (if (char-valid-p o) (insert o)))
            ((consp o) (mapc 'ee-insert (apply 'number-sequence o)))
            (t (error "Not string/int/pair: %S" o))))
    (setq rest (cdr rest))))

(defun find-einsert (what &rest rest)
"See `ee-insert'.
Example of use: (find-einsert '((32 1000) 10 (8000 12000)))"
  (apply 'find-eoutput-reuse "*einsert*"
         `(apply 'ee-insert ',what) rest))





;;;   __ _           _           _     
;;;  / _(_)_ __   __| |      ___| |__  
;;; | |_| | '_ \ / _` |_____/ __| '_ \ 
;;; |  _| | | | | (_| |_____\__ \ | | |
;;; |_| |_|_| |_|\__,_|     |___/_| |_|
;;;                                    
;;; hyperlinks to the output of shell commands
;;;

(defun find-sh (command &rest pos-spec-list)
  "Hyperlink to the result of running the shell command COMMAND.
If a buffer named COMMAND does not exist then create it and put
there the output or running COMMAND; if a buffer named COMMAND
already exists then reuse it and do not run COMMAND again."
  (interactive "sShell command: ")
  (if (get-buffer command)              ; if the buffer already exists
      (switch-to-buffer command)        ; then just switch to it
    (switch-to-buffer command)          ; otherwise create it
    (insert (shell-command-to-string command)) ; prepare its contents
    (goto-char (point-min)))            ; and place point at its beginning
  (apply 'ee-goto-position pos-spec-list))

(defalias 'find-sh00 'shell-command-to-string)

(defun find-sh0 (command)
  "Hyperlink to the result of running the shell command COMMAND.
This function does not create a buffer like `find-sh' does;
instead, it just returns the output of COMMAND as string,
removing a trailing newline from the output if one is found.
Follow a `find-sh0' hyperlink just displays the output of the
COMMAND in the echo area."
  (replace-regexp-in-string "\n$" "" (shell-command-to-string command)))



;; The two functions below bypass calling a shell and instead run
;; external programs directly. Note that the suffix "0" means "do not
;; create a new buffer, just display the result in the echo area or
;; return it", and the suffix "00" means "be even more low-level than
;; with "0": do not strip out the final newline".

;; Note: these functions are much faster than find-sh on some
;; badly-designed OSs.
;; I commented out these definitions because these functions
;; are defined in a better way below.

' (defun find-callprocess00 (prog &rest args)
    "Example: (find-callprocess00 \"lua\" \"-e\" \"print(1+2)\")"
    (with-output-to-string
      (with-current-buffer
          standard-output
        (apply 'call-process prog nil t nil args))))

' (defun find-callprocess0 (&rest args)
    "Example: (find-callprocess0 \"lua\" \"-e\" \"print(1+2)\")"
    (replace-regexp-in-string "\n$" "" (apply 'find-callprocess00 args)))




;;;                                              
;;;  _ __  _ __ ___   ___ ___  ___ ___  ___  ___ 
;;; | '_ \| '__/ _ \ / __/ _ \/ __/ __|/ _ \/ __|
;;; | |_) | | | (_) | (_|  __/\__ \__ \  __/\__ \
;;; | .__/|_|  \___/ \___\___||___/___/\___||___/
;;; |_|                                          
;;

;; 2007sep29: Copied these functions from eev-mini.el to here...
;; In a near future all calls to external processes in eev will happen
;; through these functions... mainly because (1) they accept their
;; "program-and-args" argument as either a string (to be split at
;; whitespace) or as a list of strings, (2) they can either expand
;; each "word" or "program-and-args" with ee-expand or keep all words
;; unchanged, (3) they're short and clean.

;; Sorry, no docstrings yet... some tests:
;; (find-callprocess0  '("lua51" "-e" "print(1+2)"))
;; (find-callprocess00 '("lua51" "-e" "print(1+2)"))

;; Suffixes:
;; "-ne" means "(do) not ee-expand"
;; "0"  means "don't display in a temp buffer, just return the string"
;; "00" means "like `0', but more low-level: don't strip the trailing newline".

(defun ee-split   (str) (if (stringp str) (split-string str "[ \t\n]+") str))
(defun ee-unsplit (list) (if (listp list) (mapconcat 'identity list " ") list))
(defun ee-split-and-expand (str) (mapcar 'ee-expand (ee-split str)))
(defun ee-no-trailing-nl   (str) (replace-regexp-in-string "\n$" "" str))

(defun find-bgprocess-ne (program-and-args)
  (let ((argv (ee-split program-and-args)))
    (apply 'start-process (car argv) "*Messages*" argv)))

(defun find-callprocess00-ne (program-and-args)
  (let ((argv (ee-split program-and-args)))
    (with-output-to-string
      (with-current-buffer standard-output
        (apply 'call-process (car argv) nil t nil (cdr argv))))))

(defun find-callprocess0-ne (program-and-args)
  (ee-no-trailing-nl (find-callprocess00 program-and-args)))

(defun find-comintprocess-ne (name program-and-args)
  (let ((argv (ee-split program-and-args)))
    (apply 'make-comint name (car argv) nil (cdr argv))
    (switch-to-buffer (format "*%s*" name))))

(defun find-bgprocess     (program-and-args)
  (find-bgprocess-ne      (ee-split-and-expand program-and-args)))
(defun find-callprocess00 (program-and-args)
  (find-callprocess00-ne  (ee-split-and-expand program-and-args)))
(defun find-callprocess0  (program-and-args)
  (find-callprocess0-ne   (ee-split-and-expand program-and-args)))
(defun find-comintprocess (name program-and-args)
  (find-comintprocess-ne   name (ee-split-and-expand program-and-args)))


;; New, 2008jan02
;; Compare with `ee-find-grep'

(defun ee-find-comintprocess-ne (dir name program-and-args)
  (switch-to-buffer
   (with-temp-buffer
     (cd dir)
     (find-comintprocess-ne name program-and-args)
     (current-buffer))))

(defun ee-find-comintprocess (dir name program-and-args)
  (ee-find-comintprocess-ne
   (ee-expand dir) name (ee-split-and-expand program-and-args)))




;;;   __ _           _                             
;;;  / _(_)_ __   __| |      _ __ ___   __ _ _ __  
;;; | |_| | '_ \ / _` |_____| '_ ` _ \ / _` | '_ \ 
;;; |  _| | | | | (_| |_____| | | | | | (_| | | | |
;;; |_| |_|_| |_|\__,_|     |_| |_| |_|\__,_|_| |_|
;;;                                                
;;; hyperlinks to manpages
;;;

(defadvice Man-notify-when-ready (around find-man (man-buffer) activate)
  "After rendering a manpage jump to `ee-find-man-pos-spec-list'."
  (if (not ee-find-man-flag)
      ad-do-it
    (switch-to-buffer man-buffer)
    (apply 'ee-goto-position ee-find-man-pos-spec-list)
    (setq ee-find-man-flag nil)))

(defun find-man (manpage &rest pos-spec-list)
  "Hyperlink to a manpage."
  (interactive (list (ee-manpagename-ask)))
  (setq ee-find-man-flag t
        ee-find-man-pos-spec-list pos-spec-list)
    (man manpage))

;; Missing: find-woman. (find-node "(woman)Top")




;;;   __ _           _               _____           
;;;  / _(_)_ __   __| |    __      _|___ / _ __ ___  
;;; | |_| | '_ \ / _` |____\ \ /\ / / |_ \| '_ ` _ \ 
;;; |  _| | | | | (_| |_____\ V  V / ___) | | | | | |
;;; |_| |_|_| |_|\__,_|      \_/\_/ |____/|_| |_| |_|
;;;
;;; hyperlinks to files in html
;;;

;; To do: factor this and create a function `ee-expand-url'.

(defun find-w3m (url &rest pos-spec-list)
  "Hyperlink to a page in HTML.
Use w3m to render the page as text in an Emacs buffer.
Apply `ee-expand' to URL; this changes URL when it starts with
\"~\" or \"$\". After that if URL starts with \"/\" prepend
\"file://\" to it.

These operations on URL keep \"real urls\" unchanged and convert
several kinds of filenames into urls that w3m can process - but
it doesn't convert relative filenames into urls. See
`expand-file-name'."
  (interactive "Murl: ")
  (let ((enable-local-variables nil)    ; workaround for a w3m-el bug
        (w3m-async-exec nil))
    (w3m (replace-regexp-in-string "^/" "file:///" (ee-expand url))))
  (ee-goto-rest pos-spec-list))




;;;   __ _           _          _       _    __                                
;;;  / _(_)_ __   __| |      __| |_   _(_)  / / __  ___ _ __   __ _  __ _  ___ 
;;; | |_| | '_ \ / _` |____ / _` \ \ / / | / / '_ \/ __| '_ \ / _` |/ _` |/ _ \
;;; |  _| | | | | (_| |____| (_| |\ V /| |/ /| |_) \__ \ |_) | (_| | (_| |  __/
;;; |_| |_|_| |_|\__,_|     \__,_| \_/ |_/_/ | .__/|___/ .__/ \__,_|\__, |\___|
;;;                                          |_|       |_|          |___/      
;;; hyperlinks to pages in dvi/ps/pdf documents
;;;

(defun ee-dvipage (fname &optional page xdviargs)
  `("xdvi" ,@xdviargs ,@(if page (list (format "+%d" page))) ,fname))
(defun ee-pspage (fname &optional page gvargs)
  `("gv" ,@gvargs ,@(if page (list (format "--page=%d" page))) ,fname))
(defun ee-xpdfpage (fname &optional page xpdfargs)
  `("xpdf" ,@xpdfargs ,fname ,(format "%s" (or page 1))))

(defun find-dvipage  (fname &optional page &rest rest)
  (find-bgprocess (ee-dvipage fname page)))
(defun find-pspage   (fname &optional page &rest rest)
  (find-bgprocess (ee-pspage fname page)))
(defun find-xpdfpage (fname &optional page &rest rest)
  (find-bgprocess (ee-xpdfpage fname page)))

(defun find-pdftotext (fname &rest rest)
  (apply 'find-sh (format "pdftotext -layout %s -" fname) rest))
(defun find-pstotext (fname &rest rest)
  (apply 'find-sh (format "cat %s | pstotext" fname) rest))
(defun find-zpstotext (fname &rest rest)
  (apply 'find-sh (format "zcat %s | pstotext" fname) rest))

;;;                _                         __  _       _ 
;;;   ___ ___   __| | ___       _ __  ___   / /_| |_   _(_)
;;;  / __/ _ \ / _` |/ _ \_____| '_ \/ __| / / _` \ \ / / |
;;; | (_| (_) | (_| |  __/_____| |_) \__ \/ / (_| |\ V /| |
;;;  \___\___/ \__,_|\___|     | .__/|___/_/ \__,_| \_/ |_|
;;;                            |_|                         
;;;
;;; code-ps/dvi: mass-producing hyperlink functions

(defun ee-code-ps (code psfile)
  (format "
    (defun find-%spage (&optional n &rest comments) (interactive)
      (find-pspage %S n))
  " code psfile))
(defun ee-code-dvi (code dvifile)
  (format "
    (defun find-%spage (&optional n &rest comments) (interactive)
      (find-dvipage %S n))
  " code dvifile))
(defun ee-code-xpdf (code pdffile)
  (format "
    (defun find-%spage (&optional n &rest comments) (interactive)
      (find-xpdfpage %S n))
  " code pdffile))
(defun ee-code-pdftotext (code pdffile)
  (format "
    (defun find-%stext (&rest rest) (interactive)
      (apply 'find-pdftotext %S rest))
  " code pdffile))
(defun ee-code-pstotext (code psfile)
  (format "
    (defun find-%stext (&rest rest) (interactive)
      (apply 'find-pstotext %S rest))
  " code psfile))
(defun ee-code-zpstotext (code zpsfile)
  (format "
    (defun find-%stext (&rest rest) (interactive)
      (apply 'find-zpstotext %S rest))
  " code zpsfile))

(defun code-ps        (c f) (eval (ee-read (ee-code-ps        c f))))
(defun code-dvi       (c f) (eval (ee-read (ee-code-dvi       c f))))
(defun code-xpdf      (c f) (eval (ee-read (ee-code-xpdf      c f))))
(defun code-pdftotext (c f) (eval (ee-read (ee-code-pdftotext c f))))
(defun code-pstotext  (c f) (eval (ee-read (ee-code-pstotext  c f))))
(defun code-zpstotext (c f) (eval (ee-read (ee-code-zpstotext c f))))

(defun find-code-ps        (c f) (find-estring-elisp (ee-code-ps        c f)))
(defun find-code-dvi       (c f) (find-estring-elisp (ee-code-dvi       c f)))
(defun find-code-xpdf      (c f) (find-estring-elisp (ee-code-xpdf      c f)))
(defun find-code-pdftotext (c f) (find-estring-elisp (ee-code-pdftotext c f)))
(defun find-code-pstotext  (c f) (find-estring-elisp (ee-code-pstotext  c f)))
(defun find-code-zpstotext (c f) (find-estring-elisp (ee-code-zpstotext c f)))

;; An example of usage:
;; (eev     "psne http://www.tannerlectures.utah.edu/lectures/Coetzee99.pdf")
;; (find-pspage "$S/http/www.tannerlectures.utah.edu/lectures/Coetzee99.pdf")
;; (code-ps        "livesofanimals" "$S/http/www.tannerlectures.utah.edu/lectures/Coetzee99.pdf")
;; (code-pdftotext "livesofanimals" "$S/http/www.tannerlectures.utah.edu/lectures/Coetzee99.pdf")
;; (find-livesofanimalspage 1)
;; (find-livesofanimalstext)
;; (find-livesofanimalspage (+ -110 147) "Rilke's panther")
;; (find-livesofanimalstext        "147" "Rilke's panther")
;; "The jaguar's vision, unlike the panther's, is not blunted. On the
;; contrary, his eyes drill through the darkness of space. The cage
;; has no reality to him, he is elsewhere."



;; 2007nov18: I'm commenting out the block below -
;; it contains old code that is being replaced by
;; the code above.
;; The new code doesn't have docstrings yet, and I'm
;; planning to adapt some of the old docstrings for
;; the new functions - so I can't just delete this.
'(

(defun find-dvipage-old (fname &optional n &rest ignore)
  "Write into $EE a command that opens the dvi file FNAME at page N.
The command is \"xdvi +N FNAME\".
See `eev'."
  (interactive "fDVI file: ")
  (let ((command (format "xdvi +%d %s &" (or n 1) fname)))
    (eev command nil)
    command))

;; Note added in 2008mar03: according to jemarch (gv's maintainer),
;; gv 3.5.8 (and earlier versions) accept short arguments only,
;; gv 3.6.0 and gv 3.6.1 accept long arguments only,
;; gv 3.6.2 (and later versions) accept both long and short arguments.
;; To select a starting page in a "short arguments" version we have to
;; use "-page 42" instead of "--page=42".

(defun find-pspage-old (fname &optional n &rest ignore)
  "Write into $EE a command that opens the ps/pdf file FNAME at page N.
The command is \"gv -page N FNAME\".
See `eev'."
  (interactive "fPS or PDF file: ")
  (let ((command (format "gv -page %d %s &" (or n 1) fname)))
    (eev command nil)
    command))

;; (eebg-xdvi "/usr/share/doc/gdb/refcard.dvi.gz")
;; (eebg-gv "/usr/share/doc/gv/gv.ps.gz" 3 '("-scale" "-2"))
;; (eebg-channel-xterm "A" "bash" '("-gravity" "nw"))

(defun find-dvipagenow (fname &optional page xdviargs)
  "Launch an xdvi process browsing the dvi file FNAME, starting at PAGE.
The process is invoked like this: \"xdvi +PAGE $XDVIARGS FNAME\".
XDVIARGS is a list of strings - by default ().
It runs in background and its output (including error messages)
goes to the buffer \"*Messages*\"."
  (interactive "fdvi file: ")
  (apply 'start-process "xdvi" "*Messages*"
         `("xdvi"
           ,@(if page (list (format "+%d" page)))
           ,@xdviargs
           ,(ee-expand fname))))

(defun find-pspagenow (fname &optional page gvargs)
  "Launch a gv process browsing the ps or pdf file FNAME, starting at PAGE.
The process is invoked like this: \"gv --page=N $GVARGS FNAME\".
GVARGS is a list of strings - by default ().
It runs in background and its output (including error messages)
goes to the buffer \"*Messages*\"."
  (interactive "fPS or PDF file: ")
  (apply 'start-process "gv" "*Messages*"
         `("gv"
          ,@(if page (list (format "--page=%d" page)))
          ,@gvargs
          ,(ee-expand fname))))

(defalias 'find-dvipage 'find-dvipagenow)
(defalias 'find-pspage  'find-pspagenow)

(defalias 'eebg-xdvi 'find-dvipagenow)  ; backward compatibility
(defalias 'eebg-gv   'find-pspagenow)   ; backward compatibility

(defun code-ps (code psfile)
  "Define a function `find-CODEpage' as a hyperlink to a page in PSFILE.
See `find-pspage', `code-c-d' and `code-dvi'.
An example:\n
  (code-ps \"foo\" \"/tmp/bar.ps\")\n
runs:\n
  (defun find-foopage (&optional n &rest comments)
     (interactive)
     (find-pspage \"/tmp/bar.ps\" n))"
  (ee-eval-read-format
   "(defun find-%spage (&optional n &rest comments) (interactive)
       (find-pspage %S n))"
   code psfile))

(defun code-dvi (code dvifile)
  "Define a function `find-CODEpage' as a hyperlink to a page in DVIFILE.
See `find-dvipage', `code-c-d' and `code-ps'.
An example:\n
  (code-dvi \"foo\" \"/tmp/bar.dvi\")\n
runs:\n
  (defun find-foopage (&optional n &rest comments)
    (interactive)
    (find-dvipage \"/tmp/bar.dvi\" n))"
  (ee-eval-read-format
   "(defun find-%spage (&optional n &rest comments) (interactive)
       (find-dvipage %S n))"
   code dvifile))

)
;; End of a block of old code commented out.




;;;                                                  _
;;;                                  _              (_)      _
;;;   __ _ _ __ ___  _   _ _ __   __| |  _ __   ___  _ _ __ | |_ 
;;;  / _` | '__/ _ \| | | | '_ \ / _` | | '_ \ / _ \| | '_ \| __|
;;; | (_| | | | (_) | |_| | | | | (_| | | |_) | (_) | | | | | |_ 
;;;  \__,_|_|  \___/ \__,_|_| |_|\__,_| | .__/ \___/|_|_| |_|\__|
;;;                                     |_|                      
;;; around point / ask
;;; inspired by: (find-efile "thingatpt.el")
;;;

(defun ee-message (object)
  "An obsolete hack to debug functions bound to keys. See the code."
  (message "%S" object)
  object)

(defun ee-message-maybe (object)
  "An obsolete hack to debug functions bound to keys. See the code."
  (if show-it (message "%S" object))
  object)

(defalias 'ee-maybe-showing-it 'ee-message-maybe) ; backward compatibilty

;; A way to examine the result of the functions below - by executing
;; them with `M-x functionname' with point on some interesting place -
;; without using ee-message-maybe:
;; (progn (find-estring "Mmm foobar") (eek "5*<right>") (ee-manpagename-around-point))

(defun ee-stuff-around-point (chars &optional show-it)
  (interactive "MChars: \np")           ; for tests
  (ee-message-maybe
   (save-excursion
     (let* ((e (progn (skip-chars-forward  chars) (point)))
            (s (progn (skip-chars-backward chars) (point))))
       (buffer-substring s e)))))

(defun ee-debpkgname-around-point (&optional show-it)
"Return the name of the Debian package around point.
This function is not very smart."
  (interactive "p")
  (ee-stuff-around-point "a-z0-9-+." show-it))

(defun ee-debpkgname-ask (&optional prompt show-it)
"Ask for the name of a Debian package; the default is the debpkgname at point."
  (interactive (list nil t))
  (ee-message-maybe
   (read-string (or prompt "Debian package name: ")
                (ee-debpkgname-around-point))))

(defun ee-manpagename-around-point (&optional show-it)  
"Return the manpagename around point.
This function is not very smart - it doesn't understand section names."
  (interactive "p")
  (ee-stuff-around-point "A-Za-z0-9-+_:." show-it))

(defun ee-manpagename-ask (&optional prompt show-it)
"Ask for the name of a manpage; the default is the manpage name at point."
  (interactive (list nil t))
  (ee-message-maybe
   (read-string (or prompt "Manpage: ")
                (ee-manpagename-around-point))))



;;;      _      _     _             
;;;   __| | ___| |__ (_) __ _ _ __  
;;;  / _` |/ _ \ '_ \| |/ _` | '_ \ 
;;; | (_| |  __/ |_) | | (_| | | | |
;;;  \__,_|\___|_.__/|_|\__,_|_| |_|
;;;                                 
;;; hyperlinks to information about Debian packages
;;;

(defun find-Package (fname &optional packagename &rest pos-spec-list)
  "Hyperlink to \"Package: \" achors in Debian package control files.
See: `find-status', `find-available', (find-man \"grep-dctrl\")"
  (find-fline fname)
  (apply 'ee-goto-position
         (if packagename (format "\nPackage: %s\n" packagename))
         pos-spec-list))

(defun find-status (packagename &rest pos-spec-list)
  "Hyperlink to the info about the package PACKAGENAME in /var/lib/dpkg/status.
This is Debian-specific. See `find-Package'."
  (interactive (list (ee-debpkgname-ask)))
  (apply 'find-Package "/var/lib/dpkg/status" packagename pos-spec-list))

(defun find-available (packagename &rest pos-spec-list)
"Hyperlink to the info about the package PACKAGENAME in /var/lib/dpkg/available.
This is Debian-specific. See `find-Package'."
  (interactive (list (ee-debpkgname-ask)))
  (apply 'find-Package "/var/lib/dpkg/available" packagename pos-spec-list))

(defun find-grep-status (grepargs &rest pos-spec-list)
  (interactive "sgrep-status ")
  (apply 'find-sh (concat "grep-status " grepargs) pos-spec-list))

(defun find-grep-available (grepargs &rest pos-spec-list)
  (interactive "sgrep-available ")
  (apply 'find-sh (concat "grep-available " grepargs) pos-spec-list))



;;;                _                          _ 
;;;   ___ ___   __| | ___        ___       __| |
;;;  / __/ _ \ / _` |/ _ \_____ / __|____ / _` |
;;; | (_| (_) | (_| |  __/_____| (_|_____| (_| |
;;;  \___\___/ \__,_|\___|      \___|     \__,_|
;;;                                             
;;; code-c-d: mass-producing hyperlink functions

(defun