Skip to content

Instantly share code, notes, and snippets.

@jordonbiondo
Last active December 19, 2015 14:29
Show Gist options
  • Save jordonbiondo/5970019 to your computer and use it in GitHub Desktop.
Save jordonbiondo/5970019 to your computer and use it in GitHub Desktop.
Temp-latte-mode
;;---------------------------------------------------------------------------
;; Temp-Lattes:
;; abbrev-mode replacement
;;---------------------------------------------------------------------------
;;---------------------------------------------------------------------------
;; Recipe Examples
;;---------------------------------------------------------------------------
(tl/define-recipe "lm" emacs-lisp-mode
(backward-delete-char (length tl/key))
(insert "(lambda ())")
(backward-char 2)
(indent-according-to-mode))
(tl/define-recipe "df" emacs-lisp-mode
(let ((sp (point-at-bol)))
(backward-delete-char (length tl/key))
(insert "(defun ()\n\"\"\n)")
(indent-region sp (point))
(search-backward "(")))
;;---------------------------------------------------------------------------
;; Temp-latte-mode
;;---------------------------------------------------------------------------
(defvar tl/keymap (let ((tl-km (make-sparse-keymap)))
(define-key tl-km (kbd "M-SPC") 'tl/brew)
tl-km)
"Keymap for temp-latte-mode.")
(define-minor-mode temp-latte-mode
"A minor mode for very similar to abbrev-mode, but offers a little more control
over expansion. see `tl/define-recipe' for useage information.
Default Bindings:
\tM-SPC:\t tl/brew"
:init-value nil
:lighter " latte"
:global t
:keymap tl/keymap)
(defvar tl/recipe-book (make-hash-table :test 'equal)
"Temp-latte recipe table.
A recipe is a string/lambda pair.")
(defvar tl/recipe-modes (make-hash-table :test 'equal)
"Temp-latte mode table.
A recipe-mode is a string/major-mode pair specifying the major mode in which
the recipe will be active.")
(defmacro tl/define-recipe (str mode &rest body)
"Define a new template recipe that will expand from the key STR when in MODE.
MODE is an unquoted name of a major mode in which the recipe will be active, if nil,
the recipe will be active in all major modes.
BODY may be a function body that will be executed when the key is expanded or a
string that will replace the key at brew time.
Example:
The following creates a recipe for lm in emacs-lisp-mode. when expanded
lm becomes (lambda()) and the cursor is moved into the argument parenthesis.
In the definition, the variable tl/key will be set to the recipe key, in this case tl/key
is \"lm\"
(tl/define-recipe \"lm\" emacs-lisp-mode
(backward-delete-char (length tl/key))
(insert \"(lambda ())\")
(backward-char 2)
(indent-according-to-mode))"
(declare (indent defun))
(if (not (stringp str)) (signal 'wrong-type-argument str))
(if (and (= (length body) 1) (stringp (first body)))
`(progn (puthash ,str (lambda (tl/key)
(delete-char ,(- (length str)))
(insert ,(first body))) ,(quote tl/recipe-book))
(puthash ,str (quote ,mode) ,(quote tl/recipe-modes)))
`(progn (puthash ,str (lambda (tl/key) ,@body) ,(quote tl/recipe-book))
(puthash ,str (quote ,mode) ,(quote tl/recipe-modes)))))
(defun tl/dump-recipe (str)
"Remove the recipe definition from `tl/recipe-book' with a key of STR."
(remhash str tl/recipe-modes)
(remhash str tl/recipe-book))
(defun tl/craft-recipe (key)
"Attempt to brew a latte with a recipe key of WORD.
If there is no such recipe, print an message saying so."
(let ((action (gethash key tl/recipe-book))
(action-mode (gethash key tl/recipe-modes)))
(if (and action (or (not action-mode) (equal action-mode major-mode)))
(apply action (list key))
(tl/no-recipe (current-word)))))
(defun tl/brew ()
"Brew a latte from the recipe key at point.
The point needs to be at the end of the key text"
(interactive)
(if (looking-at "\\>") (tl/craft-recipe (current-word))
(tl/no-key)))
(defun tl/no-recipe(key)
"Prints a no recipe found error message for KEY."
(princ (format "no recipe found for \"%s\"" key)))
(defun tl/no-key()
"Prints a no recipe key message.."
(princ "no recipe key at point, must be at the end of a recipe key"))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment