(defgroup expand nil
"Make abbreviations more usable."
:group 'abbrev)
(defcustom expand-load-hook nil
"Hooks run when `expand.el' is loaded."
:type 'hook
:group 'expand)
(defcustom expand-expand-hook nil
"Hooks run when an abbrev made by `expand-add-abbrevs' is expanded."
:type 'hook
:group 'expand)
(defcustom expand-jump-hook nil
"Hooks run by `expand-jump-to-previous-slot' and `expand-jump-to-next-slot'."
:type 'hook
:group 'expand)
(define-skeleton expand-c-for-skeleton "For loop skeleton"
"Loop var: "
"for(" str _ @ "=0; " str @ "; " str @ ") {" \n
@ _ \n
"}" > \n)
(defconst expand-c-sample-expand-list
'(("if" "if () {\n \n} else {\n \n}" (5 10 21))
("ifn" "if () {}" (5 8))
("uns" "unsigned ")
("for" expand-c-for-skeleton)
("switch" "switch () {\n\n}" (9 13))
("case" "case :\n\nbreak;\n" (6 8 16))
("do" "do {\n\n} while ();" (6 16))
("while" "while () {\n\n}" (8 12))
("default" "default:\n\nbreak;" 10)
("main" "int\nmain(int argc, char * argv[])\n{\n\n}\n" 37))
"Expansions for C mode. See `expand-add-abbrevs'.")
(defconst expand-sample-lisp-mode-expand-list
(list
(list
"defu"
(concat
"(defun ()\n"
" \"\"\n"
" (interactive)\n"
" (let* (\n"
" )\n"
" \n"
" ))")
(list 8 11 16 32 43 59))
(list
"defs"
(concat
"(defsubst ()\n"
" \"\"\n"
" (interactive)\n"
" )")
(list 11 14 19 23 39))
(list
"defm"
(concat
"(defmacro ()\n"
" \"\"\n"
" `( \n"
" ))")
(list 11 13 18 25))
(list
"defa"
(concat
"(defadvice (around act)\n"
" \"\"\n"
" \n"
" )")
(list 12 22 32 36))
(list
"defc"
"(defconst nil\n \"\")\n"
(list 11 13 20))
(list
"defv"
"(defvar nil\n \"\")\n"
(list 9 11 18))
(list
"let"
"(let* (\n)\n "
(list 8 13))
(list
"sav"
"(save-excursion\n \n)"
(list 18))
(list
"aut"
"(autoload ' \"\" t t)\n"
(list 12 14))
)
"Expansions for Lisp mode. See `expand-add-abbrevs'.")
(defconst expand-sample-perl-mode-expand-list
(list
(list
"sub"
(concat
"#" (make-string 70 ?-) "\n"
"sub {\n"
" # DESCRIPTION\n"
" # \n"
" # \n"
" # INPUT\n"
" # \n"
" # \n"
" # RETURN\n"
" # \n"
"\n"
" local( $f ) = \"$lib.\";\n" " local() = @_;\n" " \n"
" \n}\n"
)
(list 77 88 120 146 159 176))
(list
"for" (concat
"for ( )\n"
"{\n\n\}"
)
(list 7 12))
(list
"whi" (concat
"while ( )\n"
"{\n\n\}"
)
(list 9 15))
(list
"iff"
(concat
"if ( )\n"
"{\n\n\}"
)
(list 6 12))
(list "loc" "local( $ );" (list 9))
(list "my" "my( $ );" (list 6))
(list "ope" "open(,\"\")\t|| die \"$f: Can't open [$]\";" (list 6 8 36))
(list "clo" "close ;" 7)
(list "def" "defined " (list 9))
(list "und" "undef ;" (list 7))
(list "pr" "print " 7)
(list "pf" "printf " 8)
(list "gre" "grep( //, );" (list 8 11))
(list "pus" "push( , );" (list 7 9))
(list "joi" "join( '', );" (list 7 11))
(list "rtu" "return ;" (list 8))
)
"Expansions for Perl mode. See `expand-add-abbrevs'.")
(defun expand-add-abbrevs (table abbrevs)
"Add a list of abbrev to abbrev table TABLE.
ABBREVS is a list of abbrev definitions; each abbrev description entry
has the form (ABBREV EXPANSION ARG).
ABBREV is the abbreviation to replace.
EXPANSION is the replacement string or a function which will make the
expansion. For example you, could use the DMacros or skeleton packages
to generate such functions.
ARG is an optional argument which can be a number or a list of
numbers. If ARG is a number, point is placed ARG chars from the
beginning of the expanded text.
If ARG is a list of numbers, point is placed according to the first
member of the list, but you can visit the other specified positions
cyclicaly with the functions `expand-jump-to-previous-slot' and
`expand-jump-to-next-slot'.
If ARG is omitted, point is placed at the end of the expanded text."
(if (null abbrevs)
table
(expand-add-abbrev table (nth 0 (car abbrevs)) (nth 1 (car abbrevs))
(nth 2 (car abbrevs)))
(expand-add-abbrevs table (cdr abbrevs))))
(defvar expand-list nil "Temporary variable used by the Expand package.")
(defvar expand-pos nil
"If non-nil, stores a vector containing markers to positions defined by the last expansion.
This variable is local to a buffer.")
(make-variable-buffer-local 'expand-pos)
(defvar expand-index 0
"Index of the last marker used in `expand-pos'.
This variable is local to a buffer.")
(make-variable-buffer-local 'expand-index)
(defvar expand-point nil
"End of the expanded region.
This variable is local to a buffer.")
(make-variable-buffer-local 'expand-point)
(defun expand-add-abbrev (table abbrev expansion arg)
"Add one abbreviation and provide the hook to move to the specified positions."
(let* ((string-exp (if (and (symbolp expansion) (fboundp expansion))
nil
expansion))
(position (if (and arg string-exp)
(if (listp arg)
(- (length expansion) (1- (car arg)))
(- (length expansion) (1- arg)))
0)))
(define-abbrev
table
abbrev
(vector string-exp
position
(if (and (listp arg)
(not (null arg)))
(cons (length string-exp) arg)
nil)
(if (and (symbolp expansion) (fboundp expansion))
expansion
nil)
)
'expand-abbrev-hook)))
(put 'expand-abbrev-hook 'no-self-insert t)
(defun expand-abbrev-hook ()
"Abbrev hook used to do the expansion job of expand abbrevs.
See `expand-add-abbrevs'. Value is non-nil if expansion was done."
(if (and (eolp)
(not (expand-in-literal)))
(let ((p (point)))
(setq expand-point nil)
(if (and (eq (char-syntax (preceding-char))
?w)
(expand-do-expansion))
(progn
(if expand-point
(progn
(if (vectorp expand-list)
(expand-build-marks expand-point))
(indent-region p expand-point nil))
(if (listp expand-list)
(setq expand-index 0
expand-pos (expand-list-to-markers expand-list)
expand-list nil)))
(run-hooks 'expand-expand-hook)
t)
nil))
nil))
(defun expand-do-expansion ()
(delete-backward-char (length last-abbrev-text))
(let* ((vect (symbol-value last-abbrev))
(text (aref vect 0))
(position (aref vect 1))
(jump-args (aref vect 2))
(hook (aref vect 3)))
(cond (text
(insert text)
(setq expand-point (point))))
(if jump-args
(funcall 'expand-build-list (car jump-args) (cdr jump-args)))
(if position
(backward-char position))
(if hook
(funcall hook))
t)
)
(defun expand-abbrev-from-expand (word)
"Test if an abbrev has a hook."
(or
(and (intern-soft word local-abbrev-table)
(symbol-function (intern-soft word local-abbrev-table)))
(and (intern-soft word global-abbrev-table)
(symbol-function (intern-soft word global-abbrev-table)))))
(defun expand-previous-word ()
"Return the previous word."
(save-excursion
(let ((p (point)))
(backward-word 1)
(buffer-substring p (point)))))
(defun expand-jump-to-previous-slot ()
"Move the cursor to the previous slot in the last abbrev expansion.
This is used only in conjunction with `expand-add-abbrevs'."
(interactive)
(if expand-pos
(progn
(setq expand-index (1- expand-index))
(if (< expand-index 0)
(setq expand-index (1- (length expand-pos))))
(goto-char (aref expand-pos expand-index))
(run-hooks 'expand-jump-hook))))
(defun expand-jump-to-next-slot ()
"Move the cursor to the next slot in the last abbrev expansion.
This is used only in conjunction with `expand-add-abbrevs'."
(interactive)
(if expand-pos
(progn
(setq expand-index (1+ expand-index))
(if (>= expand-index (length expand-pos))
(setq expand-index 0))
(goto-char (aref expand-pos expand-index))
(run-hooks 'expand-jump-hook))))
(defun expand-build-list (len l)
"Build a vector of offset positions from the list of positions."
(expand-clear-markers)
(setq expand-list (vconcat l))
(let ((i 0)
(lenlist (length expand-list)))
(while (< i lenlist)
(aset expand-list i (- len (1- (aref expand-list i))))
(setq i (1+ i))))
)
(defun expand-build-marks (p)
"Transform the offsets vector into a marker vector."
(if expand-list
(progn
(setq expand-index 0)
(setq expand-pos (make-vector (length expand-list) nil))
(let ((i (1- (length expand-list))))
(while (>= i 0)
(aset expand-pos i (copy-marker (- p (aref expand-list i))))
(setq i (1- i))))
(setq expand-list nil))))
(defun expand-clear-markers ()
"Make the markers point nowhere."
(if expand-pos
(progn
(let ((i (1- (length expand-pos))))
(while (>= i 0)
(set-marker (aref expand-pos i) nil)
(setq i (1- i))))
(setq expand-pos nil))))
(defun expand-in-literal ()
"Test if we are in a comment or in a string."
(save-excursion
(let* ((lim (or (save-excursion
(beginning-of-defun)
(point))
(point-min)))
(here (point))
(state (parse-partial-sexp lim (point))))
(cond
((nth 3 state) 'string)
((nth 4 state) 'comment)
(t nil)))))
(defun expand-list-to-markers (l)
"Transform a list of markers in reverse order into a vector in the correct order."
(let* ((len (1- (length l)))
(loop len)
(v (make-vector (+ len 1) nil)))
(while (>= loop 0)
(aset v loop (if (markerp (car l)) (car l) (copy-marker (car l))))
(setq l (cdr l)
loop (1- loop)))
v))
(defun expand-skeleton-end-hook ()
(if skeleton-positions
(setq expand-list skeleton-positions)))
(add-hook 'skeleton-end-hook (function expand-skeleton-end-hook))
(provide 'expand)
(run-hooks 'expand-load-hook)