#!/usr/bin/env bb (require '[babashka.tasks :refer [shell]] '[babashka.fs :as fs] '[clojure.edn :as edn] '[clojure.string :as str]) (def default-config {:editor-command "nvim" :default-target "nvim:" :aliases []}) ;; configuration helpers (defn- deep-merge [v & vs] (letfn [(rec-merge [v1 v2] (if (and (map? v1) (map? v2)) (merge-with deep-merge v1 v2) v2))] (if (some identity vs) (reduce #(rec-merge %1 %2) v vs) (last vs)))) (defn- init-config [path] (when-not (fs/exists? path) (fs/create-dirs (fs/parent path)) (fs/create-file path) (spit path default-config)) path) ;;; global config (defn- global-config-path [] (let [env-vimnulti-config (System/getenv "VIMULTI_CONFIG") env-xdg-config-home (System/getenv "XDG_CONFIG_HOME") config-filename "config.edn"] (or env-vimnulti-config (if env-xdg-config-home (str env-xdg-config-home "/vimulti/" config-filename) config-filename)))) (def global-config (-> (global-config-path) init-config slurp edn/read-string)) ;;; load local config (def config (cond-> global-config (fs/exists? "vimulti.edn") (deep-merge (-> "vimulti.edn" slurp edn/read-string)))) ;; git helpers (defn- get-current-branch [dir] (-> (shell {:dir dir :out :string} "git branch --show-current") :out str/trim-newline)) ;; parser helpers (defn- use-alias [target] (if-let [alias-config (get (:aliases config) (keyword target))] alias-config (do (println "No such alias or invalid target.") (System/exit 1)))) (defn- use-branch-or-tag [target branch-style? tag-style?] (let [separator (if branch-style? #":" (if tag-style? #"@" #" ")) target-array (str/split target separator) app-name (if (= (first target-array) "") "nvim" (first target-array)) repo (fs/path (System/getProperty "user.home") ".config" app-name) no-mark (= (count target-array) 1)] (when (> (count target-array) 2) (println "Invalid target string.") (System/exit 1)) (cond-> {:app-name app-name} branch-style? (assoc :branch (when-not no-mark (last target-array))) tag-style? (assoc :tag (when-not no-mark (last target-array))) (fs/exists? repo) (assoc :repo repo)))) ;; TODO #_(defn- use-remote [target] #_(let [app-name (get-name-from-url target)] (shell {:dir (fs/path (System/getProperty "user.home") ".config" app-name)} "git clone" target))) ;; target should be a string like "app-name:branch" or "app-name@tag" ;; returns a map with keys :app-name :branch :tag... (defn- parse-target-string [target-string] (let [target (or target-string (:default-target config) "nvim:") branch-style? (str/includes? target ":") tag-style? (str/includes? target "@") alias-style? (and (not branch-style?) (not tag-style?))] (if alias-style? (use-alias target) (use-branch-or-tag target branch-style? tag-style?)))) ;; main ;; target should be a string like "app-name:branch" or "app-name@tag" (let [[target & args] *command-line-args* target-map (parse-target-string target) current-branch (get-current-branch (:repo target-map))] (when-let [switch-to (or (:branch target-map) (:tag target-map))] (let [tag? (boolean (:tag target-map))] (shell {:dir (:repo target-map)} (str "git switch " switch-to (if tag? "--detach" ""))))) (shell {:extra-env {"NVIM_APPNAME" (:app-name target-map)}} (:editor-command config) (apply str args)) (shell {:dir (:repo target-map)} (str "git switch " current-branch)))