<commit_before>(ns fugue.ide.state
  (:require [fugue.ide.layout :as layout]
            [clojure.set :refer [rename-keys]]))

(defn init-state [init-files]
  {::layout '(1)
   ::active 1
   ::prev nil
   ::windows {1 "fugue.user"}
   ::key-seq nil
   ::shortcuts {}
   ::actions {}
   ::minibuffer nil
   ::toggles {:vim true
              :line-numbers false}
   ::files (merge init-files {"fugue.user" "(ns fugue.user)\n\n(+ 1 2)"})})

(defn next-window-id [state]
  (first (filter #(not (contains? (::windows state) %)) (range 1 10))))

(defn in-popup? [state]
  (::key-seq state))

(defn in-minibuffer? [state]
  (::minibuffer state))

(defn in-shortcuts? [state]
  (and (in-popup? state) (not (in-minibuffer? state))))

(defn open-popup [state]
  (assoc state ::key-seq []))

(defn close-popup [state]
  (-> state
      (assoc ::key-seq nil)
      (assoc ::minibuffer nil)))

(defn get-toggle [state name]
  (get-in state [::toggles name]))

(defn flip-toggle [state name]
  (-> state
      (close-popup)
      (update-in [::toggles name] not)))

(defn activate [state id]
  (-> state
      (assoc ::prev (::active state))
      (assoc ::active (if (contains? (::windows state) id)
                        id
                        (::active state)))
      (close-popup)))

(defn go-back [state]
  (activate state (::prev state)))

(defn active-file-name [state]
  (get-in state [::windows (::active state)]))

(defn rename-active-file [state new-name]
  (-> state
      (assoc-in [::windows (::active state)] new-name)
      (update ::files rename-keys {(active-file-name state) new-name})))

(defn file-contents [state name]
  (get-in state [::files name]))

(defn active-file [state]
  (file-contents state (active-file-name state)))

(defn open-file-in-active-window [state name]
  (-> state
      (assoc-in [::windows (::active state)] name)
      (close-popup)))

(defn open-file [state name direction]
  (let [id (next-window-id state)]
    (-> state
        (assoc-in [::windows id] name)
        (update ::layout layout/insert-node direction (::active state) id)
        (activate id))))

(defn split [state direction]
  (open-file state (active-file-name state) direction))

(defn write-file [state name value]
  (assoc-in state [::files name] value))

(defn kill-window [state id]
  (-> state
      (update ::layout layout/remove-node id)
      (update ::windows dissoc id)))

(defn kill-active-window [state]
  (-> state
      (kill-window (::active state))
      (activate (::prev state))))

(defn popup-menu [state]
  (->> (get-in (::shortcuts state) (::key-seq state))
       (filter (comp string? first))
       (map #(vector (first %) (or (::group-name (second %))
                                   (clj->js (::action-name (second %))))))))

(defn add-action [state name & arg-types]
  (assoc-in state [::actions (keyword name)] {::action-name name
                                              ::arg-types arg-types}))

(defn add-shortcut-group [state path name]
  (assoc-in state (cons ::shortcuts (conj path ::group-name)) name))

(defn add-shortcut [state path action-name & args]
  (assoc-in state (cons ::shortcuts path) {::action-name action-name
                                           ::args args}))

(defn minibuffer-options [state]
  (let [{::keys [action-name args]} (::minibuffer state)
        arg-types (get-in state [::actions action-name ::arg-types])
        arg-type (drop (count args) arg-types)]
    (case arg-type
      :action (map clj->js (keys (::actions state)))
      :file (keys (::files state))
      [])))

(defn on-minibuffer-submit [state value cb perform-action]
  (let [{::keys [action-name args]} (::minibuffer state)
        arg-types (get-in state [::actions action-name ::arg-types])
        all-args (conj args value)]
    (if (= (count all-args) (count arg-types))
      (apply perform-action action-name all-args)
      (cb update-in [::minibuffer ::args] conj value))))

(defn on-key [state key cb perform-action]
  (let [new-seq (conj (::key-seq state) key)
        shortcut (get-in (::shortcuts state) new-seq)]
    (cond
      ;; open popup
      (and (= [" "] new-seq) (not (in-popup? state)))
      (cb open-popup)
      ;; another menu
      (::group-name shortcut)
      (cb update-in [::key-seq] conj key)
      ;; no action, close popup
      (nil? shortcut)
      (cb close-popup)
      :else
      (let [{::keys [action-name args]} shortcut
            action (get-in state [::actions action-name])
            arg-types (::arg-types action)]
        (if (= (count args) (count arg-types))
          (apply perform-action action-name args)
          (cb assoc ::minibuffer shortcut))))))

(defn layout [state window-fn]
  [layout/container
   (layout/map-values
     (fn [id]
       (let [filename (get-in state [::windows id])
             value (get-in state [::files filename])
             active (and (= id (::active state))
                         (not (in-popup? state)))]
         (window-fn id filename value active)))
     (::layout state))])

(defn on-upload [state name file]
  (-> state
      (write-file name file)
      (open-file name :after)))<commit_msg>fix minibuffer options<commit_after>(ns fugue.ide.state
  (:require [fugue.ide.layout :as layout]
            [clojure.set :refer [rename-keys]]))

(defn init-state [init-files]
  {::layout '(1)
   ::active 1
   ::prev nil
   ::windows {1 "fugue.user"}
   ::key-seq nil
   ::shortcuts {}
   ::actions {}
   ::minibuffer nil
   ::toggles {:vim true
              :line-numbers false}
   ::files (merge init-files {"fugue.user" "(ns fugue.user)\n\n(+ 1 2)"})})

(defn next-window-id [state]
  (first (filter #(not (contains? (::windows state) %)) (range 1 10))))

(defn in-popup? [state]
  (::key-seq state))

(defn in-minibuffer? [state]
  (::minibuffer state))

(defn in-shortcuts? [state]
  (and (in-popup? state) (not (in-minibuffer? state))))

(defn open-popup [state]
  (assoc state ::key-seq []))

(defn close-popup [state]
  (-> state
      (assoc ::key-seq nil)
      (assoc ::minibuffer nil)))

(defn get-toggle [state name]
  (get-in state [::toggles name]))

(defn flip-toggle [state name]
  (-> state
      (close-popup)
      (update-in [::toggles name] not)))

(defn activate [state id]
  (-> state
      (assoc ::prev (::active state))
      (assoc ::active (if (contains? (::windows state) id)
                        id
                        (::active state)))
      (close-popup)))

(defn go-back [state]
  (activate state (::prev state)))

(defn active-file-name [state]
  (get-in state [::windows (::active state)]))

(defn rename-active-file [state new-name]
  (-> state
      (assoc-in [::windows (::active state)] new-name)
      (update ::files rename-keys {(active-file-name state) new-name})))

(defn file-contents [state name]
  (get-in state [::files name]))

(defn active-file [state]
  (file-contents state (active-file-name state)))

(defn open-file-in-active-window [state name]
  (-> state
      (assoc-in [::windows (::active state)] name)
      (close-popup)))

(defn open-file [state name direction]
  (let [id (next-window-id state)]
    (-> state
        (assoc-in [::windows id] name)
        (update ::layout layout/insert-node direction (::active state) id)
        (activate id))))

(defn split [state direction]
  (open-file state (active-file-name state) direction))

(defn write-file [state name value]
  (assoc-in state [::files name] value))

(defn kill-window [state id]
  (-> state
      (update ::layout layout/remove-node id)
      (update ::windows dissoc id)))

(defn kill-active-window [state]
  (-> state
      (kill-window (::active state))
      (activate (::prev state))))

(defn popup-menu [state]
  (->> (get-in (::shortcuts state) (::key-seq state))
       (filter (comp string? first))
       (map #(vector (first %) (or (::group-name (second %))
                                   (clj->js (::action-name (second %))))))))

(defn add-action [state name & arg-types]
  (assoc-in state [::actions (keyword name)] {::action-name name
                                              ::arg-types arg-types}))

(defn add-shortcut-group [state path name]
  (assoc-in state (cons ::shortcuts (conj path ::group-name)) name))

(defn add-shortcut [state path action-name & args]
  (assoc-in state (cons ::shortcuts path) {::action-name action-name
                                           ::args args}))

(defn minibuffer-options [state]
  (let [{::keys [action-name args]} (::minibuffer state)
        arg-types (get-in state [::actions action-name ::arg-types])
        arg-type (first (drop (count args) arg-types))]
    (case arg-type
      :action (map clj->js (keys (::actions state)))
      :file (keys (::files state))
      [])))

(defn on-minibuffer-submit [state value cb perform-action]
  (let [{::keys [action-name args]} (::minibuffer state)
        arg-types (get-in state [::actions action-name ::arg-types])
        all-args (conj args value)]
    (if (= (count all-args) (count arg-types))
      (apply perform-action action-name all-args)
      (cb update-in [::minibuffer ::args] conj value))))

(defn on-key [state key cb perform-action]
  (let [new-seq (conj (::key-seq state) key)
        shortcut (get-in (::shortcuts state) new-seq)]
    (cond
      ;; open popup
      (and (= [" "] new-seq) (not (in-popup? state)))
      (cb open-popup)
      ;; another menu
      (::group-name shortcut)
      (cb update-in [::key-seq] conj key)
      ;; no action, close popup
      (nil? shortcut)
      (cb close-popup)
      :else
      (let [{::keys [action-name args]} shortcut
            action (get-in state [::actions action-name])
            arg-types (::arg-types action)]
        (if (= (count args) (count arg-types))
          (apply perform-action action-name args)
          (cb assoc ::minibuffer shortcut))))))

(defn layout [state window-fn]
  [layout/container
   (layout/map-values
     (fn [id]
       (let [filename (get-in state [::windows id])
             value (get-in state [::files filename])
             active (and (= id (::active state))
                         (not (in-popup? state)))]
         (window-fn id filename value active)))
     (::layout state))])

(defn on-upload [state name file]
  (-> state
      (write-file name file)
      (open-file name :after)))
{'fraction_non_alphanumeric': 0.1731719128329298, 'fraction_numerical': 0.001549636803874092, 'mean_word_length': 2.607966457023061, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1040985', 'n_tokens_mistral': 3488, 'n_tokens_neox': 3409, 'n_words': 994}