1
0
mirror of https://github.com/janet-lang/janet synced 2024-11-28 19:19:53 +00:00
janet/auxlib/path.janet
2019-06-02 14:10:12 -04:00

150 lines
3.1 KiB
Clojure

### path.janet
###
### A library for path manipulation.
###
### Copyright 2019 © Calvin Rose
#
# Common
#
(def- ext-peg
(peg/compile ~{:back (> -1 (+ (* ($) (set "\\/.")) :back))
:main :back}))
(defn ext
"Get the file extension for a path."
[path]
(if-let [m (peg/match ext-peg path (length path))]
(let [i (m 0)]
(if (= (path i) 46)
(string/slice path (m 0) -1)))))
(defn- redef
"Redef a value, keeping all metadata."
[from to]
(setdyn (symbol to) (dyn (symbol from))))
#
# Generating Macros
#
(defmacro- decl-sep [pre sep] ~(def ,(symbol pre "/sep") ,sep))
(defmacro- decl-delim [pre d] ~(def ,(symbol pre "/delim") ,d))
(defmacro- decl-last-sep
[pre sep]
~(def- ,(symbol pre "/last-sep-peg")
(peg/compile ~{:back (> -1 (+ (* ,sep ($)) :back))
:main :back})))
(defmacro- decl-basename
[pre]
~(defn ,(symbol pre "/basename")
"Gets the base file name of a path."
[path]
(if-let [m (peg/match
,(symbol pre "/last-sep-peg")
path
(length path))]
(let [[p] m]
(string/slice path p -1))
path)))
(defmacro- decl-parts
[pre sep]
~(defn ,(symbol pre "/parts")
"Split a path into its parts."
[path]
(string/split ,sep path)))
(defmacro- decl-normalize
[pre sep lead]
~(defn ,(symbol pre "/normalize")
"Normalize a path. This removes . and .. in the
path, as well as empty path elements."
[path]
(def els (string/split ,sep path))
(def newparts @[])
(if (,(symbol pre "/abspath?") path) (array/push newparts ,lead))
(each part els
(case part
"" nil
"." nil
".." (array/pop newparts)
(array/push newparts part)))
(string/join newparts ,sep)))
(defmacro- decl-join
[pre sep]
~(defn ,(symbol pre "/join")
"Join path elements together."
[& els]
(,(symbol pre "/normalize") (string/join els ,sep))))
(defmacro- decl-abspath
[pre]
~(defn ,(symbol pre "/abspath")
"Coerce a path to be absolute."
[path]
(if (,(symbol pre "/abspath?") path)
path
(,(symbol pre "/join") (os/cwd) path))))
#
# Posix
#
(defn posix/abspath?
"Check if a path is absolute."
[path]
(string/has-prefix? "/" path))
(redef "ext" "posix/ext")
(decl-sep "posix" "/")
(decl-delim "posix" ":")
(decl-last-sep "posix" "/")
(decl-basename "posix")
(decl-parts "posix" "/")
(decl-normalize "posix" "/" "")
(decl-join "posix" "/")
(decl-abspath "posix")
#
# Windows
#
(def- abs-peg (peg/compile '(* (range "AZ") ":\\")))
(defn win32/abspath?
"Check if a path is absolute."
[path]
(peg/match abs-peg path))
(redef "ext" "win32/ext")
(decl-sep "win32" "\\")
(decl-delim "win32" ";")
(decl-last-sep "win32" "\\")
(decl-basename "win32")
(decl-parts "win32" "\\")
(decl-normalize "win32" "\\" "C:")
(decl-join "win32" "\\")
(decl-abspath "win32")
#
# Specialize for current OS
#
(def- syms
["ext"
"sep"
"delim"
"basename"
"abspath?"
"abspath"
"parts"
"normalize"
"join"])
(let [pre (if (= :windows (os/which)) "win32" "posix")]
(each sym syms
(redef (string pre "/" sym) sym)))