Skip to content

Instantly share code, notes, and snippets.

@Techcable
Created November 16, 2022 02:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Techcable/d572c4cff9cdec9022f6e70f8967e911 to your computer and use it in GitHub Desktop.
Save Techcable/d572c4cff9cdec9022f6e70f8967e911 to your computer and use it in GitHub Desktop.
A Janet script to wrap fend and format units [WIP]
(import sh)
(import spork)
(def- metric-prefixes ["K" "M" "G" "T" "P" "E"])
(defn- makeunit [&named name base-prefix binary]
(default binary false)
(assert (keyword? name))
(assert (not (empty? (string name))))
(assert (string? base-prefix))
(assert (not (empty? base-prefix)))
{
:name name
:powers (tuple base-prefix ;(map |(string $ (if binary "i" "") base-prefix) metric-prefixes))
:base-prefix base-prefix
})
(def- unit-table (struct ;(mapcat |(tuple (keyword ($ :name)) $) [
(makeunit
:name :bytes
:base-prefix "B"
:binary true)
(makeunit
:name :kilograms
:base-prefix "k")
])))
(defn resolve-unit [unit-name]
(if-let [unit (get unit-table unit-name)]
unit
(errorf "Unknown unit name %q" unit-name)))
(defn resolve-power [unit power-name]
(def {:powers unit-powers :name unit-name :binary binary} unit)
(def index
(cond
(= power-name unit-name) (unit-powers 0)
(index-of unit-powers power-name)))
(unless (int? index)
(errorf "Invalid power %q for unit %q" power-name unit-name))
(* (if binary 10 3) index))
(defn- convert-direct [unit-name amount desired-power &opt info]
(def unit (resolve-unit unit-name))
(def {:base-prefix base-prefix} unit)
(default info {})
(default desired-power base-prefix)
(assert (number? amount))
(assert (string? desired-power))
(def {:prec prec} info)
(def desired-power-value (resolve-power unit desired-power))
(def res
(if (= desired-power-value 0)
{:whole (math/trunc amount)
:value amount
:power desired-power}
#
(do
(def parts (map string [amount base-unit "to" desired-power]))
(cond
(int? prec) (array/concat parts "to" (string prec) "dp")
(= prec :exact) (array/concat parts "to" "exact")
(nil? prec) (do) # Just ignore
(errorf "Unexpected value for prec: %q" prec))
(def result-text (sh/$< fend ;parts))
# The match (named 'm' for brevity)
(def m (peg/match
~(* (? "approx. ")
'(* ':d+ (? (* "." :d+)))
(+ :s+ (error (/ '1 ,|(string/format "bad ws: %q" $))))
':w+)
result-text))
(when (nil? m)
(errorf "Unable to parse %q (for %q)" result-text parts))
{:whole (spork/misc/string->int (in res 0))
:value (scan-number (in res 1)) # Full value
:power (get res 2 base-unit)})))
(assert (= (res :power) desired-power))
(let [val (get res :value)]
(unless (int? val)) (errorf "Unexpected value: %q" val))
(if (info :detailed)
res
(res :value))
(defn convert [unit-name amount &opt info]
(default info {})
(def {:desired-power start-desired-power}
(def res (convert-direct unit-name amount start-desired-power info))
(if (and (nil? start-desired-power) )
(printf "foo: %q" (fend-convert :bytes 15888 "KiB" {:prec 2}))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment