summaryrefslogtreecommitdiff
path: root/vimulti.clj
blob: 6c59807e3edcb3b7618dd025566c6264ee5dcd3b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#!/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"))

;; 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?
      ;; if use alias style
      (if-let [alias-config (get (:aliases config) target)]
        alias-config
        (do (println "No such alias or invalid target.")
            (System/exit 1)))
      ;; if not alias 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))))))

;; 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)))