SiteMap Search ElispArea HowTo Glossary RecentChanges News Problems Suggestions

save-and-dwim.el

Last edit

Summary: provide correct feature

Added:

> (provide 'save-and-dwim)


Download

;;; save-and-dwim.el --- save, then do something after saving.
(defconst sdwim-version "0.1a")
;; Copyright (c) 2008 Jonathan Arkell. (by)(nc)(sa)  Some rights reserved.
;; Author: Jonathan Arkell <jonnay@jonnay.net>

;; This file is not part of GNU Emacs.

;; This program 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 version 2.

;; This program 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.

;; For a copy of the GNU General Public License, search the Internet,
;; or write to the Free Software Foundation, Inc., 59 Temple Place,
;; Suite 330, Boston, MA 02111-1307 USA



;; The canonical version of this file lives on emacswiki.


;;; Commentary:
;; This file is currently in a beta state.  It needs some testing.

;; Frequently after saving a file, I will want to do something with it,
;; like compile, install and test on an emulator; send to a moz-repl;
;; load the elisp file and execute an interactive command.
;;
;; This elisp library will help automate these kinds of tasks.
;;
;; the theory is, that you have a discreet set of tasks when you save a
;; file based on mode (i.e. for a .el: save and load the file, for a .c
;; file: save then compile the file).  And then a set of tasks depending
;; on the file itself (execute the emacs command foo-bar-baz, load the
;; emulator and test, whatever.)
;; 
;; Per-mode sdwim tasks are set up on the mode setup hook.  Sometimes
;; you will have more tasks to do after a save (such as install
;; a compiled and linked file to a location, and run an emulator).
;; You can either write an elisp function to do that, or you can
;; use the kbdmacro facility provided.
;;
;; To use the kbdmacro facility, all you do is save your file, turn
;; on macro recording, and do your post-save-task once.  Finish
;; recording, and call `sdwim-set-last-kbdmacro-as-sdwim-action'.
;; It will save the current kmacro as a sdwim action.
;;
;; For instance, you could go to the top of the file, search for
;; the string ";;--run-tests--", go down a line, forward a sexp
;; and then eval the expression.  Assuming you had your unit
;; testing code all in one place, it would launch it all right
;; after save.
;;
;; If you need to, you can always record new macros, and use
;; `sdwim-set-last-kbdmacro-as-sdwim-action' again.  Each
;; macro is named before it is applied to the save hook for
;; sdwim.
;;
;;; Commands:
;;
;; Below are complete command list:
;;
;;  `sdwim-save'
;;    This saves the file and then runs the registered SDWIM hooks.
;;  `sdwim-set-last-kbdmacro-as-sdwim-action'
;;    Gets the current keyboard macro, and turns it into a sdwim action that gets executed.
;;  `sdwim-set-kbdmacro-as-sdwim-action'
;;    Sets the named keyboard macro as a sdwim action to be executed.
;;
;;; Customizable Options:
;;
;; Below are customizable option list:
;;
;;  `sdwim-install-defaults'
;;    Install the default SDWIM hooks.
;;    default = nil
;;  `sdwim-override-save-keycommand'
;;    Override the C-x C-s command to run save-dwim instead.
;;    default = nil


;;; Installation:
;; put this file on your load-path somewhere, and load it in your .emacs
;; i.e. (require 'sdwim)


;;; TODO:
;; Look at the save hook to hook in sdwim

;; build in some really basic intelligence.  Start by looking at what
;; the user does after hitting save, if they execute the same task more
;; then x times in a row, offer that as a potential buffer-local-post-save
;; option.
;;
;; Allow some kind of project support so that tasks can be set up on a
;; per project basis, as well as a per file basis.
;;

;;; CHANGELOG:
;;; v 0.1 - First release.

;;; BUGS:

(defgroup sdwim nil
  "Group for Save and Do What I mean.") 

;;* custom 
(defcustom sdwim-install-defaults nil
   "Install the default SDWIM hooks.

This will install some typical good hooks for a few programming modes on startup.
See the function `sdwim-install-default-hooks' for an example of how to set things up.

This only gets executed once SDWIM is loaded."
   :type 'boolean
   :group 'sdwim)

;;* custom
(defcustom sdwim-override-save-keycommand nil
   "Override the C-x C-s command to run save-dwim instead.

This only gets executed once SDWIM is loaded."   
   :type 'boolean
   :group 'sdwim)

;;* var hooks
(defvar sdwim-hooks '()
  "List of functions to run after a save.")

(make-variable-buffer-local 'sdwim-hooks)

;; var save flag
(defvar sdwim-saving nil
  "Flag to protect ourselves from running into an infinite loop.

For instance, with moz mode, you can only `moz-save-buffer-and-send',
you can't just send the file, so we need to be sure that we don't
run into an infinite loop, because sdwim calls a funciton that
saves the file.

This is mostly a protection for if save has been advised.  Not that
it has been really heavily tested yet.")

;;* save interactive
(defun sdwim-save ()
  "This saves the file and then runs the registered SDWIM hooks."
  (interactive)
  (when (not sdwim-saving)
    (setq sdwim-saving 't)
	(unwind-protect
	 (progn
	  (save-buffer)
	  (run-hooks 'sdwim-hooks))
	 (setq sdwim-saving nil))))

;;* macro interactive
(defun sdwim-set-last-kbdmacro-as-sdwim-action ()
  "Gets the current keyboard macro, and turns it into a sdwim action that gets executed.

Warning, this will not persist beyond the current editing session."
  (interactive)
  (let ((kmacro-name (intern (concat "sdwim-*" buffer-file-name "*"))))
	(name-last-kbd-macro kmacro-name)
	(add-hook 'sdwim-hooks `(lambda () (execute-kbd-macro (quote ,kmacro-name))) t)))

;;* macro interactive
(defun sdwim-set-kbdmacro-as-sdwim-action (kmacro-name)
  "Sets the named keyboard macro as a sdwim action to be executed.

Warning, this will not persist beyond the current editing session."
  (interactive "SKeyboard Macro: ")
  (add-hook 'sdwim-hooks `(lambda () (execute-kbd-macro (quote ,kmacro-name))) t))

;;* init helper example
(defun sdwim-install-default-hooks ()
   "Install the default hooks for sdwim.

This also serves as an example as to how to add your own default SDWIM hooks"
   (add-hook 'emacs-lisp-mode-hook '(lambda () (add-hook 'sdwim-hooks 'eval-buffer)))
   (add-hook 'c-mode-hook '(lambda () (add-hook 'sdwim-hooks 'compile)))
   (add-hook 'c++-mode-hook '(lambda () (add-hook 'sdwim-hooks 'compile)))
   (add-hook 'php-mode-hook '(lambda () (add-hook 'sdwim-hooks 'php-check-syntax)))
   (when (featurep 'moz) (add-hook 'emacs-lisp-mode-hook '(lambda () (add-hook 'sdwim-hooks 'moz-save-buffer-and-send)))))

;;* init 
(when sdwim-install-defaults
	  (sdwim-install-default-hooks))

;;* init
(when sdwim-override-save-keycommand
	  (global-set-key "C-x C-s" 'save-dwim))

(provide 'sdwim)
(provide 'save-and-dwim)

;;* test
(defun sdwim-test ()
   "A simple test function to see if SDWIM works."
   (todochiku-message "Works!" "SDWIM works!" (todochiku-icon 'star)))

(when nil
  (add-hook 'sdwim-hooks 'sdwim-test)
  (todochiku-message "SDWIM-macro" "SDWIM macro test works!" (todochiku-icon 'star))
  )