Created
November 16, 2022 02:13
-
-
Save Techcable/d572c4cff9cdec9022f6e70f8967e911 to your computer and use it in GitHub Desktop.
A Janet script to wrap fend and format units [WIP]
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(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