                                                                (region-end)))
               :dynamic-collection t
               :history 'ar/counsel-find--history
-              :action (lambda (file)
+              :action (lambda (fpath)
                         (with-ivy-window
-                          (when file
-                            (find-file file))))
+                          (when fpath
+                            (find-file (f-join (ar/counsel-find--common-parent)
+                                               fpath)))))
               :unwind #'counsel-delete-process
               :keymap kmap
               :caller 'ar/counsel-find)))
+
+(defun ar/counsel-find--common-parent ()
+  (assert (> (length ar/counsel-find--paths)
+             0))
+  (f-common-parent ar/counsel-find--paths))
 
 (defun ar/counsel-find--command ()
   (format "find %s %s "
           (s-join " " ar/counsel-find--paths)
           ar/counsel-find--args))
+
+;; Mostly copied from counsel.el.
+(defun ar/counsel-find--async-sentinel (process _msg)
+  "Sentinel function for an asynchronous counsel PROCESS.
+Mostly copied from counsel.el, but makes find command results relative to common parent."
+  (when (eq (process-status process) 'exit)
+    (if (zerop (process-exit-status process))
+        (progn
+          (ivy--set-candidates
+           (ivy--sort-maybe
+            (with-current-buffer (process-buffer process)
+              (mapcar (lambda (path)
+                        (f-relative path
+                                    (ar/counsel-find--common-parent)))
+                      (split-string (buffer-string)
+                                    counsel-async-split-string-re
+                                    t)))))
+          (setq counsel-grep-last-line nil)
+          (when counsel--async-start
+            (setq counsel--async-duration
+                  (time-to-seconds (time-since counsel--async-start))))
+          (let ((re (ivy-re-to-str (funcall ivy--regex-function ivy-text))))
+            (if ivy--old-cands
+                (if (eq (ivy-alist-setting ivy-index-functions-alist) 'ivy-recompute-index-zero)
+                    (ivy-set-index 0)
+                  (ivy--recompute-index ivy-text re ivy--all-candidates))
+              (unless (ivy-set-index
+                       (ivy--preselect-index
+                        (ivy-state-preselect ivy-last)
+                        ivy--all-candidates))
+                (ivy--recompute-index ivy-text re ivy--all-candidates))))
+          (setq ivy--old-cands ivy--all-candidates)
+          (if ivy--all-candidates
+              (ivy--exhibit)
+            (ivy--insert-minibuffer "")))
+      (setq ivy--all-candidates
+            (let ((status (process-exit-status process))
+                  (plist (plist-get counsel--async-exit-code-plist
+                                    (ivy-state-caller ivy-last))))
+              (list (or (plist-get plist status)
+                        (format "error code %d" status)))))
+      (setq ivy--old-cands ivy--all-candidates)
+      (ivy--exhibit))))
+
+;; Mostly copied from counsel.el.
+(defun ar/counsel-find--async-filter (process str)
+  "Receive from PROCESS the output STR.
+Mostly copied from counsel.el, but makes find command results relative to common parent."
+  (with-current-buffer (process-buffer process)
+    (insert str))
+  (when (time-less-p (list 0 0 counsel-async-filter-update-time)
+                     (time-since counsel--async-time))
+    (let (numlines)
+      (with-current-buffer (process-buffer process)
+        (setq numlines (count-lines (point-min) (point-max)))
+        (ivy--set-candidates
+         (mapcar (lambda (path)
+                   (f-relative path (ar/counsel-find--common-parent)))
+                 (split-string (buffer-string)
+                               counsel-async-split-string-re
+                               t))))
+      (let ((ivy--prompt (format "%d++ %s" numlines (ivy-state-prompt ivy-last))))
+        (ivy--insert-minibuffer (ivy--format ivy--all-candidates)))
+      (setq counsel--async-time (current-time)))))
 
 (defun ar/counsel-find--function (pattern)
   "Find files ivy function matching PATTERN."

;;; ar-counsel-find.el --- Counsel find support. -*- lexical-binding: t; -*-

;;; Commentary:
;; Counsel find helpers.


;;; Code:

  (or
   (ivy-more-chars)
   (progn
     (counsel--async-command (ar/counsel-find--command)
                             #'ar/counsel-find--async-sentinel
                             #'ar/counsel-find--async-filter)
     '("" "working..."))))

;; Like `find-dired' but taking a list of directories.
;; Mostly copied from find-dired.el.
(defun ar/counsel-find--dired (dpaths args)
  "Run `find' and go into Dired mode on a buffer of the output.
The command run is essentially: find DPATHS \\( ARGS \\) -ls"
  (assert (> (length dpaths) 0) nil "Needs at least one directory path to find from")
  (let ((dired-buffers dired-buffers)
        (command))
    (pop-to-buffer-same-window (get-buffer-create "*Find*"))
    (setq default-directory (file-name-as-directory
                             (expand-file-name (if (= (length dpaths) 1)
                                                   (nth 0 dpaths)
                                                 (f-common-parent dpaths)))))
    ;; Kill exsiting `find' process.
    (when (and (get-buffer-process (current-buffer))
               (eq (process-status (get-buffer-process (current-buffer)))
