Function: abbreviate-file-name

abbreviate-file-name is a byte-compiled function defined in files.el.gz.

Signature

(abbreviate-file-name FILENAME)

Documentation

Return a version of FILENAME shortened using directory-abbrev-alist.

This also substitutes "~" for the user's home directory (unless the home directory is a root directory) and removes automounter prefixes
(see the variable automount-dir-prefix).

When this function is first called, it caches the user's home directory as a regexp in abbreviated-home-dir, and reuses it afterwards (so long as the home directory does not change; if you want to permanently change your home directory after having started Emacs, set abbreviated-home-dir to nil so it will be recalculated).

Other relevant functions are documented in the file-name group.

Probably introduced at or before Emacs version 22.1.

Shortdoc

;; file-name
(abbreviate-file-name "/home/some-user")
    e.g. => "~some-user"

Aliases

viper-abbreviate-file-name (obsolete since 27.1) f-abbrev f-short

Source Code

;; Defined in /usr/src/emacs/lisp/files.el.gz
(defun abbreviate-file-name (filename)
  "Return a version of FILENAME shortened using `directory-abbrev-alist'.
This also substitutes \"~\" for the user's home directory (unless the
home directory is a root directory) and removes automounter prefixes
\(see the variable `automount-dir-prefix').

When this function is first called, it caches the user's home
directory as a regexp in `abbreviated-home-dir', and reuses it
afterwards (so long as the home directory does not change;
if you want to permanently change your home directory after having
started Emacs, set `abbreviated-home-dir' to nil so it will be recalculated)."
  ;; Get rid of the prefixes added by the automounter.
  (save-match-data                      ;FIXME: Why?
    (if (and automount-dir-prefix
	     (string-match automount-dir-prefix filename)
	     (file-exists-p (file-name-directory
			     (substring filename (1- (match-end 0))))))
	(setq filename (substring filename (1- (match-end 0)))))
    ;; Avoid treating /home/foo as /home/Foo during `~' substitution.
    (let ((case-fold-search (file-name-case-insensitive-p filename)))
      ;; If any elt of directory-abbrev-alist matches this name,
      ;; abbreviate accordingly.
      (dolist (dir-abbrev directory-abbrev-alist)
	(if (string-match (car dir-abbrev) filename)
	    (setq filename
		  (concat (cdr dir-abbrev)
			  (substring filename (match-end 0))))))
      ;; Compute and save the abbreviated homedir name.
      ;; We defer computing this until the first time it's needed, to
      ;; give time for directory-abbrev-alist to be set properly.
      ;; We include a slash at the end, to avoid spurious matches
      ;; such as `/usr/foobar' when the home dir is `/usr/foo'.
      (unless abbreviated-home-dir
        (put 'abbreviated-home-dir 'home (expand-file-name "~"))
        (setq abbreviated-home-dir
              (let* ((abbreviated-home-dir "\\`\\'.") ;Impossible regexp.
                     (regexp
                      (concat "\\`"
                              (regexp-quote
                               (abbreviate-file-name
                                (get 'abbreviated-home-dir 'home)))
                              "\\(/\\|\\'\\)")))
                ;; Depending on whether default-directory does or
                ;; doesn't include non-ASCII characters, the value
                ;; of abbreviated-home-dir could be multibyte or
                ;; unibyte.  In the latter case, we need to decode
                ;; it.  Note that this function is called for the
                ;; first time (from startup.el) when
                ;; locale-coding-system is already set up.
                (if (multibyte-string-p regexp)
                    regexp
                  (decode-coding-string regexp
                                        (if (eq system-type 'windows-nt)
                                            'utf-8
                                          locale-coding-system))))))

      ;; If FILENAME starts with the abbreviated homedir,
      ;; and ~ hasn't changed since abbreviated-home-dir was set,
      ;; make it start with `~' instead.
      ;; If ~ has changed, we ignore abbreviated-home-dir rather than
      ;; invalidating it, on the assumption that a change in HOME
      ;; is likely temporary (eg for testing).
      ;; FIXME Is it even worth caching abbreviated-home-dir?
      ;; Ref: https://debbugs.gnu.org/19657#20
      (let (mb1)
        (if (and (string-match abbreviated-home-dir filename)
                 (setq mb1 (match-beginning 1))
                 ;; If the home dir is just /, don't change it.
                 (not (and (= (match-end 0) 1)
			   (= (aref filename 0) ?/)))
                 ;; MS-DOS root directories can come with a drive letter;
                 ;; Novell Netware allows drive letters beyond `Z:'.
                 (not (and (memq system-type '(ms-dos windows-nt cygwin))
			   (string-match "\\`[a-zA-`]:/\\'" filename)))
                 (equal (get 'abbreviated-home-dir 'home)
                        (expand-file-name "~")))
	    (setq filename
		  (concat "~"
			  (substring filename mb1))))
        filename))))