diff options
Diffstat (limited to 'nvim/script')
| m--------- | nvim | 0 | ||||
| -rw-r--r-- | nvim/script/fennel.bb | 147 |
2 files changed, 147 insertions, 0 deletions
diff --git a/nvim b/nvim deleted file mode 160000 -Subproject d2e1e6a0d60cf427a8a56c0caf57c8ec60a8e36 diff --git a/nvim/script/fennel.bb b/nvim/script/fennel.bb new file mode 100644 index 0000000..7e4c578 --- /dev/null +++ b/nvim/script/fennel.bb @@ -0,0 +1,147 @@ +#!/usr/bin/env bb +;; vi: ft=clojure + +(ns script.fennel + (:require [clojure.string :as str] + [clojure.set :as set] + [babashka.cli :as cli] + [babashka.fs :as fs] + [babashka.process :as proc])) + +(def cli-opts + {:help {:alias :h + :desc "Prints this help"} + :compile {:alias :c + :desc "Compile all changed Fennel files into their Lua counterparts (\"changed\" means newer modified time than their Lua counterpart)"} + :dry {:alias :d + :desc "When true, it won't actually modify any files"} + :notify {:alias :n + :desc "Use notify-send to display errors alongside printing to stderr"} + :files {:alias :f + :desc "Prints the Fennel files it would operate on and exits, useful for piping into entr for \"compile on change\" support"} + :root {:alias :r + :desc "Root directory to perform all operations under" + :default "."} + :prune {:alias :p + :desc "Delete Lua files that lack a Fennel counterpart, prevents orphan Lua files from hanging around after a Fennel file deletion or rename, takes a list of globs that should not be included in the pruning (like `vendor/**.lua,my-cool.lua`)"}}) + +(defn compile-fennel-file + "Compiles the given Fennel file into a Lua file. Can return an anomaly." + [{:keys [src-path]}] + (try + (if src-path + (let [{:keys [exit out err]} + (proc/shell + {:out :string + :err :string + :continue true} + "lua" "script/fennel.lua" "--compile" src-path)] + (if (zero? exit) + out + {:cognitect.anomalies/category :cognitect.anomalies/fault + :cognitect.anomalies/message "Fennel process exited with a non-zero status code" + ::exit exit + ::err err})) + {:cognitect.anomalies/category :cognitect.anomalies/incorrect + :cognitect.anomalies/message "src-path must be a string"}) + (catch Exception e + {:cognitect.anomalies/category :cognitect.anomalies/fault + :cognitect.anomalies/message "Uncaught exception" + ::exeption-map (Throwable->map e)}))) + +(comment + (compile-fennel-file {:src-path "init.fnl"})) + +(defn display-help! [] + (let [file-name (fs/relativize (fs/cwd) *file*)] + (println (str "Usage: " file-name " [FLAG]")) + (println) + (println "Compile changed Fennel files into Lua, intended for use with Neovim configuration.") + (println) + (println "To run whenever you change a file you can combine this tool with entr https://eradman.com/entrproject/") + (println) + (println (str "Example: " file-name " --files | entr " file-name " --compile")) + (println) + (println (cli/format-opts {:spec cli-opts})))) + +(comment + (display-help!)) + +(defn notify! [summary msg] + (proc/shell "notify-send" summary msg)) + +(defn last-modified-time-ms-safe + "Will ALWAYS return a number. If there's an error it'll return a negative number." + [path] + (try + (.toMillis (fs/last-modified-time path)) + (catch Exception _e + -1))) + +(defn fnl->lua-path [fnl-path] + (str/replace (str (fs/strip-ext fnl-path) ".lua") #"^fnl/" "lua/")) + +(defn compile-changed-fennel-files! + "Find changed Fennel files that are newer than their Lua counterpart and compile them." + [{:keys [root prune dry notify] :or {root "."}}] + (let [glob #(map str (fs/glob root %)) + fnl-paths (glob "**.fnl") + lua-paths (glob "**.lua")] + + (when prune + (run! + (fn [lua-path] + (println "[delete]" lua-path) + (when (not dry) + (fs/delete lua-path))) + (set/difference + (set lua-paths) + (set (map fnl->lua-path fnl-paths)) + (set (mapcat glob prune))))) + + (run! + (fn [fnl-path] + (let [lua-path (fnl->lua-path fnl-path)] + (when (> (last-modified-time-ms-safe fnl-path) + (last-modified-time-ms-safe lua-path)) + (println "[compile]" fnl-path) + (let [lua (compile-fennel-file {:src-path fnl-path})] + (if-let [category (:cognitect.anomalies/category lua)] + (binding [*out* *err*] + (if (= :cognitect.anomalies/fault category) + (do + (println (::err lua)) + (when notify + (notify! (str fnl-path " compilation failed") (::err lua)))) + (println "[error]" lua))) + (when (not dry) + (spit lua-path (str "-- [nfnl] " fnl-path "\n" lua)))))))) + fnl-paths))) + +(defn print-fennel-file-paths! [{:keys [root] :or {root "."}}] + (run! + println + (map str (fs/glob root "**.fnl")))) + +(defn main + "Parse the input args and work out what to do." + [args] + (let [opts (update (cli/parse-opts args cli-opts) :prune + (fn [prune] + (cond + (string? prune) (str/split prune #",") + (true? prune) [] + (false? prune) nil + :else prune)))] + (cond + (:help opts) (display-help!) + (:files opts) (print-fennel-file-paths! opts) + (:compile opts) (compile-changed-fennel-files! opts) + :else (display-help!)))) + +(comment + ;; Intended to be invoked through your editor REPL during development. + (main ["--help"])) + +;; Default entrypoint of the script. +(main *command-line-args*) |
