                   concat (if (eq idx len) "\"};" "\",\n")))
         'xpm t :ascent 'center)))))
 
-(defun +modeline-file-path (&optional path)
-  (let ((buffer-file-name (or path buffer-file-name))
-        (root (doom-project-root)))
-    (cond ((null root)
-           (propertize "%b" 'face 'doom-modeline-buffer-file))
-          ((or (null buffer-file-name)
-               (directory-name-p buffer-file-name))
-           (propertize (abbreviate-file-name (or buffer-file-name default-directory))
-                       'face 'doom-modeline-buffer-path))
-          ((let* ((true-filename (file-truename buffer-file-name))
-                  (relative-dirs (file-relative-name (file-name-directory true-filename)
-                                                     root)))
-             (if (equal "./" relative-dirs) (setq relative-dirs ""))
-             (concat (propertize (concat (doom-project-name) "/")
-                                 'face 'doom-modeline-buffer-project-root)
-                     (propertize relative-dirs
-                                 'face 'doom-modeline-buffer-path)
-                     (propertize (file-name-nondirectory true-filename)
-                                 'face 'doom-modeline-buffer-file)))))))
-
-;; TODO Add shrink-path alternatives
+(defun +modeline-build-path (&optional path)
+  "Construct the file path for the `+modeline-buffer-id' segment using
+`+mdoeline-buffer-path-function'. If the buffer has no `buffer-file-name', just
+use `buffer-name'."
+  (let ((buffer-file-name (or path buffer-file-name)))
+    (if (or (eq major-mode 'dired-mode)
+            (null buffer-file-name))
+        (propertize "%s" 'face 'doom-modeline-buffer-path)
+      (cl-loop for spec in (funcall +modeline-buffer-path-function)
+               if (stringp spec) concat spec
+               else concat (propertize (car spec) 'face (cdr spec))))))
+
+
+;;
+;; Buffer file path styles
+;;
+
+(defun +modeline-file-path-with-project ()
+  "Returns the unaltered buffer file path relative to the project root's
+parent.
+
+e.g. project/src/lib/file.c"
+  (let* ((project-root (doom-project-root))
+         (true-filename (file-truename buffer-file-name))
+         (relative-dirs (file-relative-name (file-name-directory true-filename)
+                                            project-root)))
+    (list (cons (concat (doom-project-name) "/")
+                'doom-modeline-buffer-project-root)
+          (cons (if (equal "./" relative-dirs) "" relative-dirs)
+                'doom-modeline-buffer-path)
+          (cons (file-name-nondirectory true-filename)
+                'doom-modeline-buffer-file))))
+
+(defun +modeline-file-path-from-project ()
+  "Returns file path relative to the project root.
+
+e.g. src/lib/file.c
+
+Meant for `+modeline-buffer-path-function'."
+  (cdr (+modeline-file-path-with-project)))
+
+(defun +modeline-file-path-truncated-with-project ()
+  "Returns file path relative to (and including) project root, with descendent
+folders truncated.
+
+e.g. project/s/l/file.c
+
+Meant for `+modeline-buffer-path-function'."
+  (let* ((parts (+modeline-file-path-with-project))
+         (dirs (car (nth 1 parts))))
+    (setcar (nth 1 parts)
+            (shrink-path--dirs-internal dirs t))
+    parts))
+
+(defun +modeline-file-path-truncated-upto-project ()
+  "Returns file path, truncating segments prior to the project.
+
+e.g. ~/w/project/src/lib/file.c
+
+Meant for `+modeline-buffer-path-function'."
+  (pcase-let
+      ((`(,root-parent ,root ,dir, file)
+        (shrink-path-file-mixed (doom-project-root)
+                                (file-name-directory buffer-file-name)
+                                buffer-file-name)))
+    (list (cons root-parent 'font-lock-comment-face)
+          (cons root 'doom-modeline-buffer-project-root)
+          (cons (concat "/" dir) 'doom-modeline-buffer-path)
+          (cons file 'doom-modeline-buffer-file))))
+
+(defun +modeline-file-path-truncated-upto-project-root ()
+  "Return file path, truncating segemnts prior to (and including) the project
+root.
+
+e.g. ~/w/p/src/lib/file.c
+
+Meant for `+modeline-buffer-path-function'."
+  (let* ((parts (+modeline-file-path-truncated-upto-project))
+         (root (car (nth 1 parts))))
+    (setcar (nth 1 parts)
+            (let ((first (substring root 0 1)))
+              (if (equal first ".")
+                  (substring root 0 2)
+                first)))
+    parts))
+
+(defun +modeline-file-path-truncated ()
+  "Return absolute file path with all directories truncated.
+
+e.g. ~/w/p/s/l/file.c
+
+Meant for `+modeline-buffer-path-function'."
+  (pcase-let ((`(,dir . ,file) (shrink-path-prompt buffer-file-name)))
+    (list (cons dir 'doom-modeline-buffer-path)
+          (cons file 'doom-modeline-buffer-file))))
+
+(defun +modeline-file-name ()
+  "Return buffer name.
+
+e.g. file.c
+
+Meant for `+modeline-buffer-path-function'."
+  (list (cons "%b" 'doom-modeline-buffer-path)))
 
 
 ;;

  :init "%b"
  :faces t
  (if buffer-file-name
      (funcall +modeline-buffer-path-function buffer-file-name)
    "%b"))

(def-modeline-segment! +modeline-buffer-directory

  "If non-nil, the bar is transparent, and only used to police the height of the
mode-line.")

(defvar +modeline-buffer-path-function #'+modeline-file-path-with-project
  "A function that returns, in list form, components of the buffer file name
display in the mode-line.

Each item should either be a string or a a cons cell whose CAR is the path
component and CDR is the name of a face.

Currently available functions:

+ `+modeline-file-path-with-project': project/src/lib/file.c
+ `+modeline-file-path-from-project': src/lib/file.c
+ `+modeline-file-path-truncated-with-project': project/s/l/file.c
+ `+modeline-file-path-truncated-upto-project': ~/w/project/src/lib/file.c
+ `+modeline-file-path-truncated-upto-project-root': ~/w/p/s/lib/file.c
+ `+modeline-file-path-truncated': ~/w/p/s/l/file.c
+ `+modeline-file-name': file.c")

;; Convenience aliases
(defvaralias 'mode-line-format-left '+modeline-format-left)
