         (kill-buffer (current-buffer))
         (funcall c nil json)))))
 
+(defun tern-project-dir ()
+  (or tern-project-dir
+      (let ((project-dir (file-name-directory (buffer-file-name))))
+        (loop for cur = project-dir then (file-name-directory (substring cur 0 (1- (length cur))))
+              while cur do
+              (when (file-exists-p (concat cur ".tern-project"))
+                (return (setf project-dir cur))))
+        (setf tern-project-dir project-dir))))
+
 (defun tern-find-server (c &optional ignore-port-file)
   (block nil
     (when tern-known-port
       (return (funcall c tern-known-port)))
     (unless (buffer-file-name)
       (return (funcall c nil)))
-    (let ((dirs (split-string (buffer-file-name) "/" t))
-          my-dir
-          found)
-      ;; FIXME use built-in filename manipulation utils
-      (loop for i from (1- (length dirs)) downto 0 do
-            (let ((dir "/"))
-              (loop for j from 0 below i do
-                    (setf dir (concat dir (nth j dirs) "/")))
-              (unless my-dir (setf my-dir dir))
-              (if (or (file-exists-p (concat dir ".tern-project"))
-                      (file-exists-p (concat dir ".tern-port")))
-                  (progn (setf found dir) (return)))))
-      (setf tern-project-dir (or found my-dir))
-      (if (and found (not ignore-port-file) (file-exists-p (concat found ".tern-port")))
+    (let ((port-file (and (not ignore-port-file) (concat (tern-project-dir) ".tern-port"))))
+      (if (and port-file (file-exists-p port-file))
           (let ((port (string-to-number (with-temp-buffer
-                                          (insert-file-contents (concat found ".tern-port"))
+                                          (insert-file-contents port-file)
                                           (buffer-string)))))
             (setf tern-known-port port)
             (funcall c port))
-        (tern-start-server tern-project-dir c)))))
+        (tern-start-server c)))))
 
 (defvar tern-command '("tern"))
 
-(defun tern-start-server (dir c)
-  (let* ((default-directory dir)
+(defun tern-start-server (c)
+  (let* ((default-directory tern-project-dir)
          (proc (apply #'start-process "Tern" nil tern-command)))
     (set-process-query-on-exit-flag proc nil)
     (set-process-sentinel proc (lambda (_proc _event)

      (tern-go-to-position file pos))))

(defun tern-go-to-position (file pos)
  (find-file (concat tern-project-dir file))
  (goto-char (min pos (point-max))))

;; Mode plumbing

      (lambda ()
        (tern-run-request #'tern-do-complete
                          `((type . "completions")
                            (file . ,(tern-project-relative-file))
                            (end . ,(1- (point))))))))

(defun tern-do-complete (data)
