; GPL'ed as under the GNU license..
; -- Deepak Goel ([email protected])
;9/5/00
; This helps me do automated actions everytime a particular file gets updated..
; Most of the functions here are oriented towards a display-ed screen..

; O GENERAL USER: PLEASE CHANGE THE LOADED-PROFILE FILE TO
; generalprofile.el  below. You will need to download this
; generalprofile.el, edit it to your needs, and also download
; timerfunctions.el. Please have an emacs installed on your system,
; pref. emacs20.



;;;====================================================
(defmacro bind (a &optional value)
  "Like setq but only If a not already bound.
Copied from .emacs.macros. Basically, is like defvar."
  (list 'if (list 'not (list 'boundp (list 'quote a)))
      (list 'setq a value))
  )

;USER OPTIONS BEGIN
;;;====================================================

(require 'cl)
(load-file "timerfunctions.el")
; *file* ==> file without extension
; *ext* ==> extension of file, default: .tex.e
; there are also defaults for *view-command* and *command*

;PROFILES ARE SET HERE:
(load "deegoprofile.el")


(setq *overrule-error* nil)

(bind *overrule-error* nil)
(bind *ext* ".tex.e")
(bind *view-command* (concat "gv -scale 2 " *file*  ".ps &"))
; FOR ME:
(bind  *command* (concat "elat " *file*))

(bind *directory* "~/more/tex")
(bind *file* "myarticle")


;;;====================================================
;;;====================================================

(setq *repeattime* 4)
(setq *initialtime* 4)
(setq *viewp* t)
(setq *includeruntime* nil)
;;;====================================================
;USER OPTIONS END
; overrule-error => show gv even if error-found..

;;;====================================================


(setq *begintime* (cadr (current-time)))

(defun last-modified-time-my (file)
 "Gets file's last modified-time."
 (sixth (file-attributes file)))

; this ensures initial processing..
(setq *last-modified-time* nil)
;(setq *last-modified-time* (ignore-errors (last-modified-time-my *file*)))

; (defun elatstart ()
;  "Automatically elatexes *file* whenever needed. The main function
; here.. Does so by running elatrun whenever it finds it idle.. Does not
; work for more than a day continuously.
; "
;   (interactive)
;   (cd *directory*)
;   (run-with-idle-timer *initialtime* "repeat" 'elatrestartrun)
; )

; ;;;====================================================
; (defun elatrestartrun ()
;   "Internal."
;  (setq *begintime* (cadr (current-time)))
;  (elatrun)
; )
; ;;;====================================================
; (defun elatrun ()
; "Whenever emacs is idle for *initialtime* sec., this function is
; called by elatstart. This function then runs elat on the file.  Then,
; sets a one-time-timer to run itself for time + repeat seconds in case
; emacs remains idle.... which
; will do the same and so on.., so that as long as emacs is idle,
; elatrun will run every repeat seconds. Does not work for more than a
; day continuosly because i am using \(cadr \(current-time\)\).
; WHEN I SAY IT WILL REPEAT EVERY *repeattime* SECONDS, I MEAN THAT THE
; TIME TO RUN ELAT IS *NOT* COUNTED TOWARDS THAT. IN FACT, I GO TO GREAT
; LENGTHS TO ENSURE THAT---SEE KEEPTRACK BELOW..
; "
; (let ((keeptrack (cadr (current-time))))
;  (cd *directory*)
;  (elat)
;  (setq *begintime* (+ *begintime* (- (cadr (current-time)) keeptrack)))
;  (run-with-idle-timer (+ *repeattime* (- (cadr (current-time))
;                                        *begintime*))


; ; the one below is no good---doesn't even respect the users' options.
; ; (run-at-time nil *repeattime* 'elat)
; ; (run-at-time nil *repeattime* 'elatwhenidle)

; )


;;;###autoload
(defun elatstart ()
 (tf-run-with-idle-timer *initialtime*  t *repeattime* t
                         *includeruntime* 'elat)
)

;;;====================================================
(global-set-key "\C-cv" 'elatview)
(defun elatview ()
 "Ghostview command."
 (interactive)
 (shell-command (concat "cd " *directory*))
 (shell-command *view-command*))

(global-set-key "\C-ce" 'elat)

(defun elatwhenidle ()
 (run-with-idle-timer 5 nil 'elat))

(defun elat ()
"One instance of processing. Bound to C-cC-e.
This command elats the file if the file has been modified. It shows
the processing-results, searching for errors, if any. The last time's
precessing results are backuped into a buffer called Previous Shell
Command Output."
 (interactive)
 (cd *directory*)
 (let*
     ((newtime (last-modified-time-my (concat *file* *ext*)))
      (modifiedp (not (equal *last-modified-time* newtime))))
   (setq *last-modified-time* newtime)
   (if modifiedp
       (progn
         (get-buffer-create "*Shell Command Output*")
         (get-buffer-create "*Previous Shell Command Output*")
         (kill-region (point-min) (point-max))
         (insert-buffer "*Shell Command Output*")
         (switch-to-buffer "*Shell Command Output*")
         (kill-region (point-min) (point-max))
         (shell-command "echo Running elat now.")
         (shell-command (concat "cd " *directory*))
         (shell-command *command*)
         (switch-to-buffer "*Shell Command Output*")
         (goto-char (point-min))
         (search-forward "about the first error" nil t)
         (let (error-found)
           (if
               (or
                (search-forward "Error" nil "go-to-end-otherwise")
                (progn
                  (goto-char (point-min))
                  (search-forward "Undefined control sequence" nil "go-to-end-otherwise"))
                (progn
                  (goto-char (point-min))
                  (search-forward "Emergency stop" nil "go-to-end-otherwise")))
                                       ; (ignore-errors (bold-region
                                       ;               (- (point) 7)
                                       ;               (point))))
               (setq error-found t))
           (if error-found
               (progn
                 (insert "[[[<---**ERROR**DETECTED**DURING**RUN**!!***]]]")
                 (ding t)
                 (ding t)
                 (ding t)
                 (ding t)
                 (ding t)

                 ))                    ; else gv..
           (if *viewp*
               (if (or *overrule-error*  (not error-found))
                   (progn
                     (ignore-errors (delete-process
                                     "*Async Shell Command*"))

                     (elatview
                      )))))

         (switch-to-buffer "*Shell Command Output*")
         (insert (current-time-my))
         (line-to-top-of-window)
                                       ;         (shell-command "echo Done")
         )))
 )



;;;====================================================
;;;====================================================
; The following might be useful in a batch mode..

; (defun do-upon-revert (file sittime action &optional skip-initial)
;   "NOT CURRENTLY IN USE.
; If a file exists and has been modified, perform action.
; The action is performed by default the first time this function is
; launched, unless skip-initial is non-nil. Any action is
; performed only if the file exists. Is basically a generalization of
; auto-revert-buffer, and helps me auto-process my latex documents. This
; process is more suited for background batch type jobs, and will not be
; used here any more. The problem with background jobs, however, is that
; the sit-for won't work, so I had better comment it out.. But that
; would mean continuous CPU wastage.."
;   (let ((aatime (last-modified-time-my file)) bbtime modifiedp)
;     (if (and aatime (not skip-initial)) (eval action))
;     (while (> 1 0)
;       (sit-for sittime)
;       (setq bbtime (last-modified-time-my file))
;       (setq modifiedp (equal aatime bbtime))
;       (setq aatime bbtime)
;       (if (and modifiedp aatime)
;         (eval action)))))



; LocalWords:  timerfunctions