Skip to content

Latest commit

 

History

History
1061 lines (822 loc) · 23.2 KB

README.org.tpl

File metadata and controls

1061 lines (822 loc) · 23.2 KB

f.el

https://github.com/rejeep/f.el/actions/workflows/workflow.yml/badge.svg https://img.shields.io/coveralls/rejeep/f.el.svg https://melpa.org/packages/f-badge.svg https://stable.melpa.org/packages/f-badge.svg

Much inspired by @magnarss excellent s.el and dash.el, f.el is a modern API for working with files and directories in Emacs.

Installation

It’s available on Melpa and Melpa Stable.

M-x package-install f

Or you can just dump f.el in your load path somewhere.

Table of Contents

Contributing

Check ./CONTRIBUTING.org

Documentation and examples

Paths

f-join

(f-join &rest args)

{{f-join}}
(f-join "path") ;; => "path"
(f-join "path" "to") ;; => "path/to"
(f-join "/" "path" "to" "heaven") ;; => "/path/to/heaven"
(f-join "path" "/to" "file") ;; => "/to/file"

f-split

(f-split path)

{{f-split}}
(f-split "path") ;; => '("path")
(f-split "path/to") ;; => '("path" "to")
(f-split "/path/to/heaven") ;; => '("/" "path" "to" "heaven")
(f-split "~/back/to/earth") ;; => '("~" "back" "to" "earth")

f-expand

(f-expand path &optional dir)

{{f-expand}}
(f-expand "name") ;; => "/default/directory/name"
(f-expand "name" "other/directory") ;; => "other/directory/name"

f-filename

(f-filename path)

{{f-filename}}
(f-filename "path/to/file.ext") ;; => "file.ext"
(f-filename "path/to/directory") ;; => "directory"

f-dirname

(f-dirname path)

{{f-dirname}}

Alias: f-parent

(f-dirname "path/to/file.ext") ;; => "path/to"
(f-dirname "path/to/directory") ;; => "path/to"
(f-dirname "/") ;; => nil

f-common-parent

(f-common-parent paths)

{{f-common-parent}}
(f-common-parent '("foo/bar/baz" "foo/bar/qux" "foo/bar/mux")) ;; => "foo/bar/"
(f-common-parent '("/foo/bar/baz" "/foo/bar/qux" "/foo/bax/mux")) ;; => "/foo/"
(f-common-parent '("foo/bar/baz" "quack/bar/qux" "lack/bar/mux")) ;; => ""

f-ext

(f-ext path)

Alias of file-name-extension

(f-ext "path/to/file") ;; => nil
(f-ext "path/to/file.txt") ;; => txt
(f-ext "path/to/file.txt.org") ;; => org

f-no-ext

(f-no-ext path)

Alias of file-name-sans-extension

(f-no-ext "path/to/file") ;; => path/to/file
(f-no-ext "path/to/file.txt") ;; => path/to/file
(f-no-ext "path/to/file.txt.org") ;; => path/to/file.txt

f-swap-ext

(f-swap-ext path ext)

{{f-swap-ext}}
(f-swap-ext "path/to/file.ext" "org") ;; => "path/to/file.org"
(f-swap-ext "path/to/file.ext" "") ;; => error

f-base

(f-base path)

{{f-base}}
(f-base "path/to/file.ext") ;; => "file"
(f-base "path/to/directory") ;; => nil

f-relative

(f-relative path &optional dir)

{{f-relative}}
(f-relative "/some/path/relative/to/my/file.txt" "/some/path/") ;; => relative/to/my/file.txt
(f-relative "/default/directory/my/file.txt") ;; => my/file.txt

f-short

(f-short path)

Alias of abbreviate-file-name

Alias: f-abbrev

(f-short "/Users/foo/Code/bar") ;; => ~/Code/bar
(f-short "/path/to/Code/bar") ;; => /path/to/Code/bar

f-long

(f-long path)

{{f-long}}
(f-long "~/Code/bar") ;; => /Users/foo/Code/bar
(f-long "/path/to/Code/bar") ;; => /path/to/Code/bar

f-canonical

(f-canonical path)

Alias of file-truename

(f-canonical "/path/to/real/file") ;; => /path/to/real/file
(f-canonical "/link/to/file") ;; => /path/to/real/file

f-slash

(f-slash path)

{{f-slash}}
(f-slash "/path/to/file") ;; => /path/to/file
(f-slash "/path/to/dir") ;; => /path/to/dir/
(f-slash "/path/to/dir/") ;; => /path/to/dir/

f-full

(f-full path)

{{f-full}}
(f-full "~/path/to/file") ;; => /home/foo/path/to/file
(f-full "~/path/to/dir") ;; => /home/foo/path/to/dir/
(f-full "~/path/to/dir/") ;; => /home/foo/path/to/dir/

f-uniquify

(f-uniquify paths)

{{f-uniquify}}
(f-uniquify '("/foo/bar" "/foo/baz" "/foo/quux")) ;; => '("bar" "baz" "quux")
(f-uniquify '("/foo/bar" "/www/bar" "/foo/quux")) ;; => '("foo/bar" "www/bar" "quux")
(f-uniquify '("/foo/bar" "/www/bar" "/www/bar/quux")) ;; => '("foo/bar" "www/bar" "quux")
(f-uniquify '("/foo/bar" "/foo/baz" "/home/www/bar" "/home/www/baz" "/var/foo" "/opt/foo/www/baz")) ;; => '("foo/bar" "www/bar" "foo/baz" "home/www/baz" "foo/www/baz" "foo")

f-uniquify-alist

(f-uniquify-alist paths)

{{f-uniquify-alist}}
(f-uniquify-alist '("/foo/bar" "/foo/baz" "/foo/quux")) ;; => '(("/foo/bar" . "bar") ("/foo/baz" . "baz") ("/foo/quux" . "quux"))
(f-uniquify-alist '("/foo/bar" "/www/bar" "/foo/quux")) ;; => '(("/foo/bar" . "foo/bar") ("/www/bar" . "www/bar") ("/foo/quux" . "quux"))
(f-uniquify-alist '("/foo/bar" "/www/bar" "/www/bar/quux")) ;; => '(("/foo/bar" . "foo/bar") ("/www/bar" . "www/bar") ("/www/bar/quux" . "quux"))
(f-uniquify-alist '("/foo/bar" "/foo/baz" "/home/www/bar" "/home/www/baz" "/var/foo" "/opt/foo/www/baz")) ;; => '(("/foo/bar" . "foo/bar") ("/home/www/bar" . "www/bar") ("/foo/baz" . "foo/baz") ("/home/www/baz" . "home/www/baz") ("/opt/foo/www/baz" . "foo/www/baz") ("/var/foo" . "foo"))

I/O

f-read-bytes

(f-read-bytes path)

{{f-read-bytes}}
(f-read-bytes "path/to/binary/data")

f-write-bytes

(f-write-bytes data path)

{{f-write-bytes}}
(f-write-bytes (unibyte-string 72 101 108 108 111 32 119 111 114 108 100) "path/to/binary/data")

f-append-bytes

(f-append-bytes text coding path)

{{f-append-bytes}}
(f-append-bytes "path/to/file" (unibyte-string 72 101 108 108 111 32 119 111 114 108 100))

f-read-text

(f-read-text path &optional coding)

{{f-read-text}}

Alias: f-read

(f-read-text "path/to/file.txt" 'utf-8)
(f-read "path/to/file.txt" 'utf-8)

f-write-text

(f-write-text text coding path)

{{f-write-text}}

Alias: f-write

(f-write-text "Hello world" 'utf-8 "path/to/file.txt")
(f-write "Hello world" 'utf-8 "path/to/file.txt")

f-append-text

(f-append-text text coding path)

{{f-append-text}}

Alias: f-append

(f-append-text "Hello world" 'utf-8 "path/to/file.txt")
(f-append "Hello world" 'utf-8 "path/to/file.txt")

Destructive

f-mkdir

(f-mkdir &rest dirs)

{{f-mkdir}}
(f-mkdir "dir") ;; creates /default/directory/dir
(f-mkdir "other" "dir") ;; creates /default/directory/other/dir
(f-mkdir "/" "some" "path") ;; creates /some/path
(f-mkdir "~" "yet" "another" "dir") ;; creates ~/yet/another/dir

f-mkdir-full-path

(f-mkdir-full-path dir)

{{f-mkdir-full-path}}
(f-mkdir-full-path "dir") ;; creates /default/directory/dir
(f-mkdir-full-path "other/dir") ;; creates /default/directory/other/dir
(f-mkdir-full-path "/some/path") ;; creates /some/path
(f-mkdir-full-path "~/yet/another/dir") ;; creates ~/yet/another/dir

f-delete

(f-delete path &optional force)

{{f-delete}}
(f-delete "dir")
(f-delete "other/dir" t)
(f-delete "path/to/file.txt")

f-symlink

(f-symlink source path)

{{f-symlink}}
(f-symlink "path/to/source" "path/to/link")

f-move

(f-move from to)

{{f-move}}
(f-move "path/to/file.txt" "new-file.txt")
(f-move "path/to/file.txt" "other/path")

f-copy

(f-copy from to)

{{f-copy}}
(f-copy "path/to/file.txt" "new-file.txt")
(f-copy "path/to/dir" "other/dir")

f-copy-contents

(f-copy-contents from to)

{{f-copy-contents}}
(f-copy-contents "path/to/dir" "path/to/other/dir")

f-touch

(f-touch path)

{{f-touch}}
(f-touch "path/to/existing/file.txt")
(f-touch "path/to/non/existing/file.txt")

Predicates

f-exists-p

(f-exists-p path)

Alias of file-exists-p

Alias: f-exists?

(f-exists-p "path/to/file.txt")
(f-exists-p "path/to/dir")

f-directory-p

(f-directory-p path)

Alias of file-directory-p

Aliases:

  • f-directory?
  • f-dir-p
  • f-dir?
(f-directory-p "path/to/file.txt") ;; => nil
(f-directory-p "path/to/dir") ;; => t

f-file-p

(f-file-p path)

Alias of file-regular-p

Alias: f-file?

(f-file-p "path/to/file.txt") ;; => t
(f-file-p "path/to/dir") ;; => nil

f-symlink-p

(f-symlink-p path)

{{f-symlink-p}}

Alias: f-symlink?

(f-symlink-p "path/to/file.txt") ;; => nil
(f-symlink-p "path/to/dir") ;; => nil
(f-symlink-p "path/to/link") ;; => t

f-readable-p

(f-readable-p path)

Alias of file-readable-p

Alias: f-readable?

(f-readable-p "path/to/file.txt")
(f-readable-p "path/to/dir")

f-writable-p

(f-writable-p path)

Alias of file-writable-p

Alias: f-writable?

(f-writable-p "path/to/file.txt")
(f-writable-p "path/to/dir")

f-executable-p

(f-executable-p path)

Alias of file-executable-p

Alias: f-executable?

(f-executable-p "path/to/file.txt")
(f-executable-p "path/to/dir")

f-absolute-p

(f-absolute-p path)

Alias of file-name-absolute-p

Alias: f-absolute?

(f-absolute-p "path/to/dir") ;; => nil
(f-absolute-p "/full/path/to/dir") ;; => t

f-relative-p

(f-relative-p path)

{{f-relative-p}}

Alias: f-relative?

(f-relative-p "path/to/dir") ;; => t
(f-relative-p "/full/path/to/dir") ;; => nil

f-root-p

(f-root-p path)

{{f-root-p}}

Alias: f-root?

(f-root-p "/") ;; => t
(f-root-p "/not/root") ;; => nil

f-ext-p

(f-ext-p path ext)

{{f-ext-p}}

Alias: f-ext?

(f-ext-p "path/to/file.el" "el") ;; => t
(f-ext-p "path/to/file.el" "txt") ;; => nil
(f-ext-p "path/to/file.el") ;; => t
(f-ext-p "path/to/file") ;; => nil

f-same-p

(f-same-p path-a path-b)

{{f-same-p}}

Aliases:

  • f-same?
  • f-equal-p
  • f-equal?
(f-same-p "foo.txt" "foo.txt") ;; => t
(f-same-p "/path/to/foo.txt" "/path/to/bar.txt") ;; => nil
(f-same-p "foo/bar/../baz" "foo/baz") ;; => t

f-parent-of-p

(f-parent-of-p path-a path-b)

{{f-parent-of-p}}

Alias: f-parent-of?

(f-parent-of-p "/path/to" "/path/to/dir") ;; => t
(f-parent-of-p "/path/to/dir" "/path/to") ;; => nil
(f-parent-of-p "/path/to" "/path/to") ;; => nil

f-child-of-p

(f-child-of-p path-a path-b)

{{f-child-of-p}}

Alias: f-child-of?

(f-child-of-p "/path/to" "/path/to/dir") ;; => nil
(f-child-of-p "/path/to/dir" "/path/to") ;; => t
(f-child-of-p "/path/to" "/path/to") ;; => nil

f-ancestor-of-p

(f-ancestor-of-p path-a path-b)

{{f-ancestor-of-p}}

Alias: f-ancestor-of?

(f-ancestor-of-p "/path/to" "/path/to/dir") ;; => t
(f-ancestor-of-p "/path" "/path/to/dir") ;; => t
(f-ancestor-of-p "/path/to/dir" "/path/to") ;; => nil
(f-ancestor-of-p "/path/to" "/path/to") ;; => nil

f-descendant-of-p

(f-descendant-of-p path-a path-b)

{{f-descendant-of-p}}

Alias: f-descendant-of?

(f-descendant-of-p "/path/to/dir" "/path/to") ;; => t
(f-descendant-of-p "/path/to/dir" "/path") ;; => t
(f-descendant-of-p "/path/to" "/path/to/dir") ;; => nil
(f-descendant-of-p "/path/to" "/path/to") ;; => nil

f-hidden-p

(f-hidden-p path)

{{f-hidden-p}}

Alias: f-hidden?

(f-hidden-p "path/to/foo") ;; => nil
(f-hidden-p ".path/to/foo") ;; => t
(f-hidden-p "path/.to/foo") ;; => nil
(f-hidden-p "path/to/.foo") ;; => nil
(f-hidden-p ".path/to/foo" 'any) ;; => t
(f-hidden-p "path/.to/foo" 'any) ;; => t
(f-hidden-p "path/to/.foo" 'any) ;; => t
(f-hidden-p ".path/to/foo" 'last) ;; => nil
(f-hidden-p "path/.to/foo" 'last) ;; => nil
(f-hidden-p "path/to/.foo" 'last) ;; => t

f-empty-p

(f-empty-p path)

{{f-empty-p}}

Alias: f-empty?

(f-empty-p "/path/to/empty-file") ;; => t
(f-empty-p "/path/to/file-with-contents") ;; => nil
(f-empty-p "/path/to/empty-dir/") ;; => t
(f-empty-p "/path/to/dir-with-contents/") ;; => nil

f-newer-p

(f-newer-p file other &optional method)

{{f-newer-p}}

Alias: f-newer?

(f-newer-p "newer.txt" "older.txt") ;; t
(f-newer-p "older.txt""newer.txt" ) ;; nil
(f-newer-p "same1.txt" "same2.txt") ;; nil

f-older-p

(f-older-p file other &optional method)

{{f-older-p}}

Alias: f-older?

(f-older-p "older.txt" "newer.txt") ;; t
(f-older-p "newer.txt""older.txt" ) ;; nil
(f-older-p "same1.txt" "same2.txt") ;; nil

f-same-time-p

(f-same-time-p file other &optional method)

{{f-same-time-p}}

Alias: f-same-time?

(f-same-time-p "same1.txt" "same2.txt") ;; t
(f-same-time-p "newer.txt" "older.txt") ;; nil
(f-same-time-p "older.txt" "newer.txt") ;; nil

Stats

f-size

(f-size path)

{{f-size}}
(f-size "path/to/file.txt")
(f-size "path/to/dir")

f-depth

(f-depth path)

{{f-depth}}
(f-depth "/") ;; 0
(f-depth "/var/") ;; 1
(f-depth "/usr/local/bin") ;; 3

f-change-time

(f-change-time path &optional timestamp-p)

{{f-change-time}}
(f-change-time "path/to/file.txt")         ;; (25517 48756 26337 111000)
(f-change-time "path/to/dir")              ;; (25517 57887 344657 210000)
(f-change-time "path/to/file.txt" t)       ;; (1672330868026337111 . 1000000000)
(f-change-time "path/to/dir" t)            ;; (1672339999344657210 . 1000000000)
(f-change-time "path/to/file.txt"'seconds) ;; 1672330868
(f-change-time "path/to/dir"'seconds)      ;; 1672339999

f-modification-time

(f-modification-time path &optional timestamp-p)

{{f-modification-time}}
(f-modification-time "path/to/file.txt")          ;; (25517 48756 26337 111000)
(f-modification-time "path/to/dir")               ;; (25517 57887 344657 210000)
(f-modification-time "path/to/file.txt" t)        ;; (1672330868026337111 . 1000000000)
(f-modification-time "path/to/dir" t)             ;; (1672339999344657210 . 1000000000)
(f-modification-time "path/to/file.txt" 'seconds) ;; 1672330868
(f-modification-time "path/to/dir" 'seconds)      ;; 1672339999

f-access-time

(f-access-time path &optional timestamp-p)

{{f-access-time}}
(f-access-time "path/to/file.txt")          ;; (25517 48756 26337 111000)
(f-access-time "path/to/dir")               ;; (25517 57887 344657 210000)
(f-access-time "path/to/file.txt" t)        ;; (1672330868026337111 . 1000000000)
(f-access-time "path/to/dir" t)             ;; (1672339999344657210 . 1000000000)
(f-access-time "path/to/file.txt" 'seconds) ;; 1672330868
(f-access-time "path/to/dir" 'seconds)      ;; 1672339999

Misc

f-this-file

(f-this-file)

{{f-this-file}}
(f-this-file) ;; => /path/to/this/file

f-path-separator

(f-path-separator)

{{f-path-separator}}
(f-path-separator) ;; => /

f-glob

(f-glob pattern &optional path)

{{f-glob}}
(f-glob "path/to/*.el")
(f-glob "*.el" "path/to")

f-entries

(f-entries path &optional fn recursive)

{{f-entries}}
(f-entries "path/to/dir")
(f-entries "path/to/dir" (lambda (file) (s-matches? "test" file)))
(f-entries "path/to/dir" nil t)
(f--entries "path/to/dir" (s-matches? "test" it))

f-directories

(f-directories path &optional fn recursive)

{{f-directories}}
(f-directories "path/to/dir")
(f-directories "path/to/dir" (lambda (dir) (equal (f-filename dir) "test")))
(f-directories "path/to/dir" nil t)
(f--directories "path/to/dir" (equal (f-filename it) "test"))

f-files

(f-files path &optional fn recursive)

{{f-files}}
(f-files "path/to/dir")
(f-files "path/to/dir" (lambda (file) (equal (f-ext file) "el")))
(f-files "path/to/dir" nil t)
(f--files "path/to/dir" (equal (f-ext it) "el"))

f-root

(f-root)

{{f-root}}
(f-root) ;; => "/"

f-traverse-upwards

(f-traverse-upwards fn &optional path)

{{f-traverse-upwards}}
(f-traverse-upwards
 (lambda (path)
   (f-exists? (f-expand ".git" path)))
 start-path)

(f--traverse-upwards (f-exists? (f-expand ".git" it)) start-path) ;; same as above

f-with-sandbox

(f-with-sandbox path-or-paths &rest body)

{{f-with-sandbox}}
(f-with-sandbox foo-path
  (f-touch (f-expand "foo" foo-path)))
(f-with-sandbox (list foo-path bar-path)
  (f-touch (f-expand "foo" foo-path))
  (f-touch (f-expand "bar" bar-path)))
(f-with-sandbox foo-path
  (f-touch (f-expand "bar" bar-path))) ;; "Destructive operation outside sandbox"

Example

Here’s an example of a function that finds the Git project root.

Using standard Emacs builtin functions

(defun find-git-root (&optional dir)
  (unless dir (setq dir (expand-file-name (file-name-directory (buffer-file-name)))))
  (let ((parent (expand-file-name ".." dir)))
    (unless (equal parent dir)
      (if (file-exists-p (expand-file-name ".git" dir))
          dir
        (find-git-root parent)))))

Using f.el

(defun find-git-root (&optional dir)
  (interactive)
  (unless dir (setq dir (f-dirname (buffer-file-name))))
  (let ((parent (f-parent dir)))
    (unless (f-root? parent)
      (if (f-exists? (f-expand ".git" dir))
          dir
        (find-git-root parent)))))

Now, try writing it even simpler yourself. Hint, check out f-traverse-upwards.