;;; eev-bounded.el -- functions like `eev-bounded', `eelatex-bounded', etc.
;; Copyright (C) 2012 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: 20121226
;; Keywords: e-scripts
;;
;; Latest version:
;; htmlized:
;; See also:
;;
;;
;; (find-eev-intro)
;; (find-bounded-intro)
;;; Commentary:
;;
;; This file adds support for "bounded functions" to eev. For example:
;; `M-x eev' saves the region between point and mark into the
;; temporary script file; `M-x eev-bounded' saves the region around
;; point, up to the first occurrences of a certain delimiters before
;; and after point, into the temporary script file.
;;
;; Big letters courtesy of Figlet.
;; See: (find-bounded-intro)
;; «.code-bounded» (to "code-bounded")
;; «.obsolete» (to "obsolete")
;;; _ _ _ _ _
;;; __| | ___| (_)_ __ ___ (_) |_ ___ _ __ ___
;;; / _` |/ _ \ | | '_ ` _ \| | __/ _ \ '__/ __|
;;; | (_| | __/ | | | | | | | | || __/ | \__ \
;;; \__,_|\___|_|_|_| |_| |_|_|\__\___|_| |___/
;;;
(defvar ee-delimiter-hash "\n#\n" "See `eev-bounded'.")
(defvar ee-delimiter-percent "\n%\n" "See `eelatex-bounded'.")
(defvar ee-delimiter-semicolon "\n;;\n" "See `eeeval-boudned'.")
(put 'ee-delimiter-hash 'safe-local-variable 'stringp)
(put 'ee-delimiter-percent 'safe-local-variable 'stringp)
(put 'ee-delimiter-semicolon 'safe-local-variable 'stringp)
(defun ee-sdelim-to-s (sdelim)
"Search backwards for STR and return the position after STR.
This function does not move point."
(+ (save-excursion (search-backward sdelim))
(length sdelim)))
(defun ee-edelim-to-e (edelim)
"Search forward for STR and return the position before STR.
This function does not move point."
(+ (save-excursion (search-forward edelim))
(- (length edelim))))
;;; _ _ _ _
;;; ___ ___ __| | ___ | |__ ___ _ _ _ __ __| | ___ __| |
;;; / __/ _ \ / _` |/ _ \_____| '_ \ / _ \| | | | '_ \ / _` |/ _ \/ _` |
;;; | (_| (_) | (_| | __/_____| |_) | (_) | |_| | | | | (_| | __/ (_| |
;;; \___\___/ \__,_|\___| |_.__/ \___/ \__,_|_| |_|\__,_|\___|\__,_|
;;;
;; «code-bounded» (to ".code-bounded")
;; See: (find-bounded-intro "Defining new bounded functions")
(defun code-bounded (newf f delim &optional adjust face dur)
(eval (ee-read
(ee-code-bounded newf f delim adjust face dur))))
(defun find-code-bounded (newf f delim &optional adjust face dur)
(find-estring-elisp
(ee-code-bounded newf f delim adjust face dur)))
(defun ee-code-bounded (newf f delim &optional adjust face dur)
(setq adjust (or adjust 1))
(setq face (or face 'highlight))
(setq dur (or dur 0.75))
(ee-template0 "
\(defun {newf} ()
\"Run the function `{f}' on a delimited region around point.
See: (find-bounded-intro)\"
(interactive)
(setq ee-bounded-function '{newf})
(let* ((s (ee-sdelim-to-s {(ee-S delim)}))
(e (ee-edelim-to-e {(ee-S delim)})))
(ee-flash s (+ e {adjust})
'{(ee-S face)} {dur})
({f} (ee-se-to-string s e))))
"))
(code-bounded 'eev-bounded 'eev 'ee-delimiter-hash)
(code-bounded 'eeg-bounded 'eeg 'ee-delimiter-hash)
(code-bounded 'eegdb-bounded 'eegdb 'ee-delimiter-hash)
(code-bounded 'eelatex-bounded 'eelatex 'ee-delimiter-percent)
(code-bounded 'eeeval-bounded 'eeeval 'ee-delimiter-semicolon)
(code-bounded 'eeb-eval 'eeeval 'ee-delimiter-semicolon)
;; Tests:
;; (find-code-bounded 'eev-bounded 'eev "\n#\n")
;; (find-code-bounded 'eev-bounded 'eev 'ee-delimiter-hash)
;;; _ __ _ _
;;; __| | ___ / _| __ _ _ _| | |_
;;; / _` |/ _ \ |_ / _` | | | | | __|
;;; | (_| | __/ _| (_| | |_| | | |_
;;; \__,_|\___|_| \__,_|\__,_|_|\__|
;;;
;; See: (find-bounded-intro "The default bounded function")
(defvar ee-bounded-function
'(lambda () (error "ee-bounded-function not set"))
"See: (find-bounded-intro)")
(defun ee-bounded-function ()
"See: (find-bounded-intro)"
(interactive)
(funcall ee-bounded-function))
;; (define-key eev-mode-map [f3] 'ee-bounded-function)
(provide 'eev-bounded)
;;; _ _ _
;;; ___ | |__ ___ ___ | | ___| |_ ___
;;; / _ \| '_ \/ __|/ _ \| |/ _ \ __/ _ \
;;; | (_) | |_) \__ \ (_) | | __/ || __/
;;; \___/|_.__/|___/\___/|_|\___|\__\___|
;;;
;; «obsolete» (to ".obsolete")
;; Obsolete code that I don't want to delete yet
;; (mainly because the docstrings have some good ideas in them)
' (progn
(defun ee-add-quote (obj)
"Return OBJ is OBJ is constant; else return 'OBJ."
(if (or (numberp obj) (stringp obj)
(eq obj nil) (eq obj t) (keywordp obj))
obj
(list 'quote obj)))
(defun ee-pp0q (obj)
"Like (ee-pp0 OBJ), but add a \"'\" in front if needed."
(ee-pp0 (ee-add-quote obj)))
(defun ee-eeb-define-docstring
(eeb-fun fun sdelim edelim flash-spec adjust extra-docs)
"Used internally by `ee-eeb-define' to generate the docstring."
(let ((args `(,eeb-fun ,fun ,sdelim ,edelim ,flash-spec ,adjust
,@(if extra-docs (list extra-docs)))))
(format "Run `%S' on a delimited region around point.
This is a wrapper function created by a sexp equivalent to first
one below (see `eeb-define'). To inspect the code that it
generates run the second sexp; and for an explanation of the
parameters, and a for a way of experimenting with them, see
`eeb-define-try'.\n
(eeb-define %s)
(find-eeb-define %s)%s"
fun
(mapconcat 'ee-pp0q args " ")
(mapconcat 'ee-pp0q args " ")
(if extra-docs (concat "\n\n" extra-docs) ""))))
(defun ee-eeb-define
(eeb-fun fun sdelim &optional edelim flash-spec adjust extra-docs)
"See `eeb-define' and `eeb-define-try'.
This function generates the code for defining EEB-FUN, as a string,
and returns it without `read'ing or `eval'ing it. An example:\n
(find-estring (ee-eeb-define 'eev-bounded 'eev 'ee-delimiter-hash nil t t))"
(format
"(defun %S ()
%S
(interactive)
(setq eeb-defaults '%s)
(eeb-default-new))"
eeb-fun
(ee-eeb-define-docstring
eeb-fun fun sdelim edelim flash-spec adjust extra-docs)
(ee-pp0 (list fun sdelim edelim flash-spec adjust))))
;; Tests:
;; (find-eeb-define 'eev-bounded 'eev "\n#\n" nil t t)
;; (find-eeb-define 'eev-bounded 'eev "\n#\n" nil t t "Example\nHere")
;; (eeb-define 'eev-bounded 'eev "\n#\n" nil t t)
;; (eeb-define 'eev-bounded 'eev "\n#\n" nil t t "Example\nHere")
;; (eeb-define 'eev-bounded 'eev 'ee-delimiter-hash nil t t "Example\nHere")
;; (find-efunctiondescr 'eev-bounded)
;; Note: the sexps in the docstring might come out wrong if they
;; contain nasty unibyte characters (this is a known possible bug).
(defun eeb-define
(eeb-fun fun sdelim &optional edelim flash-spec adjust extra-docs)
"Define EEB-FUN as a wrapper around FUN.
Use the delimiters SDELIM and EDELIM to find the region around
point where where FUN will operate; highlight the region using
FLASH-SPEC and ADJUST. If you want to add an example or extra
explanations to the docstring of EEB-FUN use EXTRA-DOCS.
See `eeb-define-try' for a detailed explanation of the parameters
and for a way of experimenting with them; see `find-eeb-define'
for a way to inspect to wrapper code."
(eval (read (ee-eeb-define
eeb-fun
fun sdelim edelim
flash-spec adjust extra-docs))))
(defun find-eeb-define (&rest rest)
(find-estring (apply 'ee-eeb-define rest))
(emacs-lisp-mode))
(defun eeb-define-try
(eeb-fun fun sdelim &optional edelim flash-spec adjust extra-docs)
"This is similar to `eeb-define', but instead of defining EEB-FUN run it now.
The \"default action over bounded regions\" is determined by the
five entries in the list stored in the variable `eeb-defaults'
\(described below). All the \"bounded functions\", like
`eev-bounded', work by setting the variable `eeb-defaults' and
then calling the function `eeb-default-new', that interprets the
entries in `eeb-defaults' in a certain way and acts accordingly.
eeb-define
==========
Bounded functions like `eev-bounded' are defined by calling the
function `eeb-define' with the name of the function to define and
the five entries for the associated value for `eeb-defaults',
like this:
(eeb-define 'eev-bounded 'eev 'ee-delimiter-hash nil t t)
`eeb-define-try' provides a nice way to test how functions
defined by `eeb-define' would behave after they are defined.
`eeb-define-try' expects the same arguments as `eeb-define', but
it ignores the first one - EEB-FUN -, and instead of defining a
function EEB-FUN that would set `eeb-defaults' and run
`eeb-default', it sets `eeb-defaults' immediately (temporarily,
using `let') and runs `eeb-default' on that.
eeb-defaults and eeb-default
============================
The variable `eeb-defaults' always holds a list of this form:
(FUN SDELIM EDELIM FLASH-SPEC ADJUST)
where:
FUN is a function taking arguments \"s\" and \"e\", like `eev',
SDELIM is the starting delimiter (see `ee-edelim-adjust'),
EDELIM is the ending delimiter (default: same as sdelim),
FLASH-SPEC tells how to highlight the region (see `eeflash-new'),
ADJUST should usually be t; see `ee-edelim-adjust'.
The \"default action on a delimited region\" is always something
composed of two \"standard actions\": first, highlight the region
temporarily, as described below; second, and most important, run
\"(FUN s e)\" on the region. FLASH-SPEC and ADJUST are only used
for the highlighting part; FUN is only used for the \"run (FUN s
e)\" part.
A nil at EDELIM means to use EDELIM := SDELIM; after
replacing the possible nil at EDELIM both SDELIM and
EDELIM are \"expanded\" with `ee-symbol-value' if their
values are symbols, and the results must be strings. Those
resulting strings are used as region delimiters by
`ee-sdelim-to-s' and `ee-edelim-to-e' to produce the \"s\" and
\"e\" arguments for the \"(FUN s e)\" call; see the documentation
for `ee-edelim-adjust' for an example that also shows how
ADJUST affects the highlighting.
A t at FLASH-SPEC means to use `eeflash-default' as FLASH-SPEC;
after treating the `t' case the value of FLASH-SPEC is
\"expanded\" with `ee-symbol-value' if it's a symbol, and the
result - that should be either nil or a list of the form \"(face
duration)\" - becomes temporarily the value of `ee-flash-spec',
and we invoke `eeflash-new' to highlight the region.
Examples
========
Here are some demos:\n
#.
# (eeb-define-try nil 'list \"\\n#.\\n\" nil t t)
# (eeb-define-try nil 'ee-se-to-string \"\\n#.\\n\" nil t t)
# (eeb-define-try nil 'eeflash-new \"\\n#.\\n\" nil t t)
# (eeb-define-try nil 'eev \"\\n#.\\n\" nil t t)
echo $[1+2]
#.\n"
(let ((eeb-defaults (list fun sdelim edelim flash-spec adjust)))
(eeb-default-new)))
)
;; Local Variables:
;; coding: utf-8-unix
;; no-byte-compile: t
;; End: