 
 ;; Mode plumbing
 
-(defun tern-before-change (start end)
+(defun tern-after-change (start end prev-length)
+  "Track the dirty area of the buffer."
   (if tern-buffer-is-dirty
-      (setf (car tern-buffer-is-dirty) (min (car tern-buffer-is-dirty) start)
-            (cdr tern-buffer-is-dirty) (max (cdr tern-buffer-is-dirty) end))
-    (setf tern-buffer-is-dirty (cons start end)))
-  (when (> (- (cdr tern-buffer-is-dirty) (car tern-buffer-is-dirty)) 4000)
-    (run-at-time "200 millisec" nil
-                 (lambda (buf)
-                   (with-current-buffer buf
-                     (when tern-buffer-is-dirty
-                       (setf tern-buffer-is-dirty nil)
-                       (tern-send-buffer-to-server))))
-                 (current-buffer)))
-  (setf tern-last-point-pos nil)
-  (when (and tern-last-argument-hints (<= start (car tern-last-argument-hints)))
-    (setf tern-last-argument-hints nil))
-  (when (and tern-last-completions (<= start (cadr tern-last-completions)))
-    (setf tern-last-completions nil)))
+      (setf tern-buffer-is-dirty (cons (min start (car tern-buffer-is-dirty))
+                                       (max end   (cdr tern-buffer-is-dirty))))
+    (setf tern-buffer-is-dirty (cons start end))))
+
+(defvar tern-idle-time 1
+  "The time Emacs is allowed to idle before updating Tern's representation of the file.")
+(defvar tern-idle-timer nil
+  "The timer on which `tern-reparse-on-idle' runs.")
+(defun tern-reparse-on-idle ()
+  "Do some mode plumbing and refresh tern's representation of the buffer."
+  (when tern-mode
+    (setf tern-last-point-pos nil)
+    (when (and tern-last-argument-hints tern-buffer-is-dirty
+               (<= (car tern-buffer-is-dirty) (car tern-last-argument-hints)))
+      (setf tern-last-argument-hints nil))
+    (when (and tern-last-completions tern-buffer-is-dirty
+               (<= (car tern-buffer-is-dirty) (cadr tern-last-completions)))
+      (setf tern-last-completions nil))
+    (tern-send-buffer-to-server)))
 
 (defun tern-post-command ()
   (unless (eq (point) tern-last-point-pos)

;; URL: http://ternjs.net/
;; Version: 0.0.1
;; Package-Requires: ((json "1.2") (cl-lib "0.5") (emacs "24"))

(require 'cl-lib)
(require 'json)

  (set (make-local-variable 'tern-buffer-is-dirty) (and (buffer-modified-p) (cons (point-min) (point-max))))
  (make-local-variable 'completion-at-point-functions)
  (push 'tern-completion-at-point completion-at-point-functions)
  (add-hook 'after-change-functions 'tern-after-change nil t)
  (when (null tern-idle-timer)
    (setq tern-idle-timer
          (run-with-idle-timer tern-idle-time t #'tern-reparse-on-idle)))
  (add-hook 'post-command-hook 'tern-post-command nil t)
  (add-hook 'buffer-list-update-hook 'tern-left-buffer nil t)
  (tern-send-buffer-to-server))

(defun tern-mode-disable ()
  (setf completion-at-point-functions
        (remove 'tern-completion-at-point completion-at-point-functions))
  (unless (null tern-idle-timer)
    (cancel-timer tern-idle-timer)
    (setq tern-idle-timer nil))
  (remove-hook 'after-change-functions 'tern-after-change t)
  (remove-hook 'post-command-hook 'tern-post-command t)
  (remove-hook 'buffer-list-update-hook 'tern-left-buffer t))

