Submodule hustle.
This commit is contained in:
		
							
								
								
									
										265
									
								
								init/FiraCode/clojure/fira_code/calt.clj
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										265
									
								
								init/FiraCode/clojure/fira_code/calt.clj
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,265 @@ | ||||
| (ns fira-code.calt | ||||
|   (:require | ||||
|    [clojure.string :as str] | ||||
|    [fira-code.coll :as coll] | ||||
|    [fira-code.glyphs :as glyphs] | ||||
|    [fira-code.time :as time] | ||||
|    [flatland.ordered.map :refer [ordered-map]])) | ||||
|  | ||||
|  | ||||
| ;; No ligature should follow those sequences | ||||
| (def ignore-prefixes | ||||
|   [["parenleft" "question" "colon"] | ||||
|    ;; #578 #624 Regexp lookahead/lookbehind | ||||
|    ["parenleft" "question" "equal"] | ||||
|    ["parenleft" "question" "less" "equal"] | ||||
|    ["parenleft" "question" "exclam"] | ||||
|    ["parenleft" "question" "less" "exclam"] | ||||
|    ;; #850 PHP <?= | ||||
|    ["less" "question" "equal"] | ||||
|   ]) | ||||
|  | ||||
|  | ||||
| (defn gen-ignore-prefixes [liga] | ||||
|   (str/join | ||||
|     (for [prefix ignore-prefixes | ||||
|           ;; try to match last N glyphs in `prefix` with N first in `liga` | ||||
|           N (range (count liga) 0 -1) | ||||
|           :when (= (take-last N prefix) (take N liga))] | ||||
|       (str "  ignore sub" | ||||
|         " " (str/join " " (drop-last N prefix)) | ||||
|         " " (first liga) "'" | ||||
|         " " (str/join " " (drop 1 liga)) | ||||
|         ";\n")))) | ||||
|  | ||||
|  | ||||
| (def ignores | ||||
|   { ["slash" "asterisk"] | ||||
|     (str | ||||
|       "  ignore sub slash' asterisk slash;\n" | ||||
|       "  ignore sub asterisk slash' asterisk;\n") | ||||
|  | ||||
|     ["asterisk" "slash"] | ||||
|     (str | ||||
|       "  ignore sub slash asterisk' slash;\n" | ||||
|       "  ignore sub asterisk' slash asterisk;\n") | ||||
|  | ||||
|     ["asterisk" "asterisk"] | ||||
|     (str | ||||
|       "  ignore sub slash asterisk' asterisk;\n" | ||||
|       "  ignore sub asterisk' asterisk slash;\n") | ||||
|  | ||||
|     ["asterisk" "asterisk" "asterisk"] | ||||
|     (str | ||||
|       "  ignore sub slash asterisk' asterisk asterisk;\n" | ||||
|       "  ignore sub asterisk' asterisk asterisk slash;\n") | ||||
|      | ||||
|     ;; #621 <||> | ||||
|     ["less" "bar" "bar"] | ||||
|     "  ignore sub less' bar bar greater;\n" | ||||
|  | ||||
|     ["bar" "bar" "greater"] | ||||
|     "  ignore sub less bar' bar greater;\n" | ||||
|  | ||||
|     ;; #574 :>= | ||||
|     ["colon" "greater"] | ||||
|     "  ignore sub colon' greater equal;\n" | ||||
|  | ||||
|     ;; #548 >=< | ||||
|     ["greater" "equal"] | ||||
|     "  ignore sub greater' equal less;\n" | ||||
|  | ||||
|     ["equal" "less"] | ||||
|     "  ignore sub greater equal' less;\n" | ||||
|  | ||||
|     ;; #593 {|} | ||||
|     ["braceleft" "bar"] | ||||
|     "  ignore sub braceleft' bar braceright;\n" | ||||
|  | ||||
|     ["bar" "braceright"] | ||||
|     "  ignore sub braceleft bar' braceright;\n" | ||||
|  | ||||
|     ;; #593 [|] | ||||
|     ["bracketleft" "bar"] | ||||
|     "  ignore sub bracketleft' bar bracketright;\n" | ||||
|  | ||||
|     ["bar" "bracketright"] | ||||
|     "  ignore sub bracketleft bar' bracketright;\n" | ||||
|  | ||||
|     ;; #410 <*>> <+>> <$>> | ||||
|     ["greater" "greater"] | ||||
|     (str "  ignore sub asterisk greater' greater;\n" | ||||
|          "  ignore sub plus greater' greater;\n" | ||||
|          "  ignore sub dollar greater' greater;\n") | ||||
|  | ||||
|     ;; #410 <*>>> <+>>> <$>>> | ||||
|     ["greater" "greater" "greater"] | ||||
|     (str "  ignore sub asterisk greater' greater greater;\n" | ||||
|          "  ignore sub plus greater' greater greater;\n"     | ||||
|          "  ignore sub dollar greater' greater greater;\n") | ||||
|  | ||||
|     ;; #410 <<*> <<+> <<$> | ||||
|     ["less" "less"] | ||||
|     (str "  ignore sub less' less asterisk;\n" | ||||
|          "  ignore sub less' less plus;\n" | ||||
|          "  ignore sub less' less dollar;\n") | ||||
|  | ||||
|     ;; #410 <<<*> <<<+> <<<$> | ||||
|     ["less" "less" "less"] | ||||
|     (str "  ignore sub less' less less asterisk;\n" | ||||
|          "  ignore sub less' less less plus;\n" | ||||
|          "  ignore sub less' less less dollar;\n") | ||||
|  | ||||
|     ;; #713 |-| | ||||
|     ["bar" "hyphen"] | ||||
|     "  ignore sub bar' hyphen bar;\n" | ||||
|  | ||||
|     ["hyphen" "bar"] | ||||
|     "  ignore sub bar hyphen' bar;\n" | ||||
|  | ||||
|     ;; #968 [-> [--> [==> [=> | ||||
|     ["equal" "greater"] | ||||
|     "  ignore sub bracketleft equal' greater;\n" | ||||
|  | ||||
|     ["equal" "equal" "greater"] | ||||
|     "  ignore sub bracketleft equal' equal greater;\n" | ||||
|  | ||||
|     ["equal" "equal"] | ||||
|     "  ignore sub bracketleft equal' equal;\n" | ||||
|  | ||||
|     ["equal" "equal" "equal"] | ||||
|     "  ignore sub bracketleft equal' equal equal;\n" | ||||
|  | ||||
|     ["hyphen" "greater"] | ||||
|     "  ignore sub bracketleft hyphen' greater;\n" | ||||
|  | ||||
|     ["hyphen" "hyphen" "greater"] | ||||
|     "  ignore sub bracketleft hyphen' hyphen greater;\n" | ||||
|  | ||||
|     ["hyphen" "hyphen"] | ||||
|     "  ignore sub bracketleft hyphen' hyphen;\n" | ||||
|  | ||||
|     ["hyphen" "hyphen" "hyphen"] | ||||
|     "  ignore sub bracketleft hyphen' hyphen hyphen;\n" | ||||
| }) | ||||
|  | ||||
|  | ||||
| ;; DO NOT generate ignores at all | ||||
| (def skip-ignores? #{ | ||||
|   ;; #410 <<*>> <<+>> <<$>> | ||||
|   ["less" "asterisk" "greater"] | ||||
|   ["less" "plus" "greater"] | ||||
|   ["less" "dollar" "greater"] | ||||
|   ;; #795 | ||||
|   ["f" "l"] ["F" "l"] ["T" "l"] | ||||
| }) | ||||
|  | ||||
|  | ||||
| ;; DO NOT generate ligature | ||||
| (def manual? #{ | ||||
|   ;; /\ \/ | ||||
|   ["slash" "backslash"] | ||||
|   ["backslash" "slash"] | ||||
| }) | ||||
|  | ||||
|  | ||||
| (defn liga->rule | ||||
|   "[f f i] => { [LIG LIG i] f_f_i.liga | ||||
|                 [LIG   f i] LIG | ||||
|                 [ f    f i] LIG }" | ||||
|   [liga] | ||||
|   (case (count liga) | ||||
|     2 (let [[a b] liga] | ||||
|         (str/replace | ||||
|           (str | ||||
|             "lookup 1_2 {\n" | ||||
|             (when-not (skip-ignores? liga) | ||||
|               (str "  ignore sub 1 1' 2;\n" | ||||
|                    "  ignore sub 1' 2 2;\n")) | ||||
|             (gen-ignore-prefixes liga) | ||||
|             (get ignores liga) | ||||
|             "  sub 1.spacer 2' by 1_2.liga;\n" | ||||
|             "  sub 1'       2  by 1.spacer;\n" | ||||
|             ; "sub 1 2 by 1_2.liga;" | ||||
|             "} 1_2;") | ||||
|           #"\d" {"1" a "2" b})) | ||||
|     3 (let [[a b c] liga] | ||||
|         (str/replace | ||||
|           (str | ||||
|             "lookup 1_2_3 {\n" | ||||
|             (when-not (skip-ignores? liga) | ||||
|              (str "  ignore sub 1 1' 2 3;\n" | ||||
|                   "  ignore sub 1' 2 3 3;\n")) | ||||
|             (gen-ignore-prefixes liga) | ||||
|             (get ignores liga) | ||||
|             "  sub 1.spacer 2.spacer 3' by 1_2_3.liga;\n" | ||||
|             "  sub 1.spacer 2'       3  by 2.spacer;\n" | ||||
|             "  sub 1'       2        3  by 1.spacer;\n" | ||||
|             ; "sub 1 2 3 by 1_2_3.liga;" | ||||
|             "} 1_2_3;") | ||||
|           #"\d" {"1" a "2" b "3" c})) | ||||
|     4 (let [[a b c d] liga] | ||||
|         (str/replace | ||||
|           (str | ||||
|             "lookup 1_2_3_4 {\n" | ||||
|             (when-not (skip-ignores? liga) | ||||
|               (str "  ignore sub 1 1' 2 3 4;\n" | ||||
|                    "  ignore sub 1' 2 3 4 4;\n")) | ||||
|             (gen-ignore-prefixes liga) | ||||
|             (get ignores liga) | ||||
|             "  sub 1.spacer 2.spacer 3.spacer 4' by 1_2_3_4.liga;\n" | ||||
|             "  sub 1.spacer 2.spacer 3'       4  by 3.spacer;\n" | ||||
|             "  sub 1.spacer 2'       3        4  by 2.spacer;\n" | ||||
|             "  sub 1'       2        3        4  by 1.spacer;\n" | ||||
|             ; "sub 1 2 3 4 by 1_2_3_4.liga;" | ||||
|             "} 1_2_3_4;") | ||||
|           #"\d" {"1" a "2" b "3" c "4" d})) | ||||
|     5 (let [[a b c d e] liga] | ||||
|         (str/replace | ||||
|           (str | ||||
|             "lookup 1_2_3_4_5 {\n" | ||||
|             (when-not (skip-ignores? liga) | ||||
|               (str "  ignore sub 1 1' 2 3 4 5;\n" | ||||
|                    "  ignore sub 1' 2 3 4 4 5;\n")) | ||||
|             (gen-ignore-prefixes liga) | ||||
|             (get ignores liga) | ||||
|             "  sub 1.spacer 2.spacer 3.spacer 4.spacer 5' by 1_2_3_4_5.liga;\n" | ||||
|             "  sub 1.spacer 2.spacer 3.spacer 4'       5  by 4.spacer;\n" | ||||
|             "  sub 1.spacer 2.spacer 3'       4        5  by 3.spacer;\n" | ||||
|             "  sub 1.spacer 2'       3        4        5  by 2.spacer;\n" | ||||
|             "  sub 1'       2        3        4        5  by 1.spacer;\n" | ||||
|             ; "sub 1 2 3 4 5 by 1_2_3_4_5.liga;" | ||||
|             "} 1_2_3_4_5;") | ||||
|           #"\d" {"1" a "2" b "3" c "4" d "5" e})) | ||||
| )) | ||||
|  | ||||
|  | ||||
| (defn compare-ligas [l1 l2] | ||||
|   (cond | ||||
|     (> (count l1) (count l2)) -1 | ||||
|     (< (count l1) (count l2)) 1 | ||||
|     :else (compare l1 l2))) | ||||
|  | ||||
|  | ||||
| (defn replace-calt [font ligas] | ||||
|   (let [ligas' (->> ligas | ||||
|                  (remove manual?)  | ||||
|                  (sort compare-ligas)) | ||||
|         calt   (->> ligas' | ||||
|                  (map liga->rule) | ||||
|                  (str/join "\n\n")) | ||||
|         glyphs (map #(str (str/join "_" %) ".liga") ligas') | ||||
|         counts (coll/group-by-to count count ligas')] | ||||
|  | ||||
|     (println "  generated calt:"  | ||||
|       ; (str/join " " glyphs) | ||||
|       (str | ||||
|         #_"(" (get counts 2) " pairs, " | ||||
|         (get counts 3) " triples, " | ||||
|         (get counts 4) " quadruples, " | ||||
|         (count ligas') " total" #_")")) | ||||
|  | ||||
|     (glyphs/update-code font :features "calt" | ||||
|       #(str/replace % | ||||
|          #"### start of generated calt\n[^#]+\n### end of generated calt\n" | ||||
|          (str "### start of generated calt\n" calt "\n### end of generated calt\n"))))) | ||||
							
								
								
									
										26
									
								
								init/FiraCode/clojure/fira_code/checks.clj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								init/FiraCode/clojure/fira_code/checks.clj
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| (ns fira-code.checks | ||||
|   (:require | ||||
|    [clojure.string :as str] | ||||
|    [fira-code.coll :as coll] | ||||
|    [fira-code.glyphs :as glyphs])) | ||||
|  | ||||
|  | ||||
| (defn width-ok? [w] | ||||
|   (#{"0" 0 1200 2400} w)) | ||||
|  | ||||
|  | ||||
| (defn widths [font] | ||||
|   (doseq [g     (:glyphs font) | ||||
|           :when (not= "0" (:export g)) | ||||
|           l     (:layers g) | ||||
|           :let  [w (:width l)] | ||||
|           :when (not (width-ok? w))] | ||||
|     (println (str "WARN glyph '" (:glyphname g) "' layer '" (:id (glyphs/layer l)) "' has width=" (pr-str w)))) | ||||
|   font) | ||||
|  | ||||
|  | ||||
| (defn -main [& args] | ||||
|   (let [path (or (first args) "FiraCode.glyphs") | ||||
|         font (glyphs/load path)] | ||||
|     (widths font))) | ||||
|  | ||||
							
								
								
									
										15
									
								
								init/FiraCode/clojure/fira_code/coll.clj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								init/FiraCode/clojure/fira_code/coll.clj
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| (ns fira-code.coll) | ||||
|  | ||||
|  | ||||
| (defn index-of [pred xs] | ||||
|   (let [res (reduce (fn [i x] (if (pred x) (reduced i) (inc i))) 0 xs)] | ||||
|     (assert (< res (count xs)) "Nothing found") | ||||
|     res)) | ||||
|  | ||||
|  | ||||
| (defn group-by-to [key-fn value-fn xs] | ||||
|   (reduce-kv | ||||
|     (fn [m k vs] | ||||
|       (assoc m k (value-fn vs))) | ||||
|     {} | ||||
|     (group-by key-fn xs))) | ||||
							
								
								
									
										192
									
								
								init/FiraCode/clojure/fira_code/glyphs.clj
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										192
									
								
								init/FiraCode/clojure/fira_code/glyphs.clj
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,192 @@ | ||||
| (ns fira-code.glyphs | ||||
|   (:refer-clojure :exclude [load]) | ||||
|   (:require | ||||
|     [clojure.java.io :as io] | ||||
|     [clojure.string :as str] | ||||
|     [fipp.edn :as fipp] | ||||
|     [fira-code.coll :as coll] | ||||
|     [flatland.ordered.map :refer [ordered-map]])) | ||||
|  | ||||
| (def ^:dynamic *str) | ||||
| (def ^:dynamic *pos) | ||||
|  | ||||
| (defn current-char [] (nth @*str @*pos)) | ||||
|  | ||||
| (defn advance! [] (swap! *pos inc)) | ||||
|  | ||||
| (declare parse-anything!) | ||||
|  | ||||
| (defn skip-ws! [] | ||||
|   (loop [] | ||||
|     (case (current-char) | ||||
|       \space   (do (advance!) (recur)) | ||||
|       \newline (do (advance!) (recur)) | ||||
|       nil))) | ||||
|  | ||||
| (defn parse-escaped-string! [] | ||||
|   (skip-ws!) | ||||
|   (when (= \" (current-char)) | ||||
|     (let [sb (StringBuilder.)] | ||||
|       (-> | ||||
|         (loop [] | ||||
|           (advance!) | ||||
|           (let [ch (current-char)] | ||||
|             (cond | ||||
|               (= ch \\) (do (.append sb \\) (advance!) (.append sb (current-char)) (recur)) | ||||
|               (= ch \") (do (advance!) (str sb)) | ||||
|               :else     (do (.append sb ch) (recur))))) | ||||
|         (str/replace "\\012" "\n") | ||||
|         (str/replace "\\\"" "\"") | ||||
|         (str/replace "\\\\" "\\"))))) | ||||
|  | ||||
| (defn parse-string! [] | ||||
|   (skip-ws!) | ||||
|   (let [sb (StringBuilder.)] | ||||
|     (loop [] | ||||
|       (let [ch (current-char)] | ||||
|         (cond | ||||
|           (#{\space \newline \{ \} \( \) \; \, \" \=} ch) sb | ||||
|           :else (do (.append sb ch) (advance!) (recur))))) | ||||
|     (let [res (str sb)] | ||||
|       (cond | ||||
|         (re-matches #"-?[1-9][0-9]*" res)          (Integer/parseInt res) | ||||
|         (re-matches #"-?[0-9]+\.[0-9]+" res)       (Double/parseDouble res) | ||||
|         (re-matches #"[a-zA-Z][a-zA-Z\.0-9]*" res) (keyword res) | ||||
|         :else res)))) | ||||
|  | ||||
| (defn expect [c] | ||||
|   (assert (= c (current-char)) | ||||
|     (str "Expected '" c | ||||
|       "', found " (current-char) | ||||
|       " at " @*pos | ||||
|       " around here:\n" (subs @*str (max 0 (- @*pos 100)) (min (count @*str) (+ @*pos 100)))))) | ||||
|  | ||||
| (defn parse-map! [] | ||||
|   (skip-ws!) | ||||
|   (when (= \{ (current-char)) | ||||
|     (advance!) | ||||
|     (loop [m (ordered-map)] | ||||
|       (skip-ws!) | ||||
|       (if (= \} (current-char)) | ||||
|         (do (advance!) m) | ||||
|         (let [k (or (parse-escaped-string!) (parse-string!)) | ||||
|               _ (do (skip-ws!) (expect \=) (advance!)) | ||||
|               v (parse-anything!) | ||||
|               v (if (keyword? v) (name v) v) | ||||
|               _ (do (skip-ws!) (expect \;) (advance!))] | ||||
|           (recur (assoc m k v))))))) | ||||
|  | ||||
| (defn parse-list! [] | ||||
|   (skip-ws!) | ||||
|   (when (= \( (current-char)) | ||||
|     (advance!) | ||||
|     (loop [l []] | ||||
|       (skip-ws!) | ||||
|       (if (= \) (current-char)) | ||||
|         (do (advance!) l) | ||||
|         (let [v (parse-anything!) | ||||
|               _ (skip-ws!) | ||||
|               _ (when (not= \) (current-char)) | ||||
|                   (expect \,) | ||||
|                   (advance!))] | ||||
|           (recur (conj l v))))))) | ||||
|  | ||||
| (defn parse-anything! [] | ||||
|   (skip-ws!) | ||||
|   (or | ||||
|     (parse-map!) | ||||
|     (parse-list!) | ||||
|     (parse-escaped-string!) | ||||
|     (parse-string!))) | ||||
|  | ||||
| (defn parse [s] | ||||
|   (binding [*str (atom s) | ||||
|             *pos (atom 0)] | ||||
|     (parse-anything!))) | ||||
|  | ||||
| (def escapes {"\n" "\\012" | ||||
|               "\"" "\\\"" | ||||
|               "\\" "\\\\"}) | ||||
|  | ||||
| (def escape-re #"[\n\"\\]") | ||||
|  | ||||
| (defn- serialize-impl [form] | ||||
|   (cond | ||||
|     (string? form)     (if (re-matches #"[a-zA-Z0-9._/]+" form) | ||||
|                          form  | ||||
|                          (str \" (str/replace form escape-re escapes) \")) | ||||
|     (keyword? form)    (name form) | ||||
|     (number? form)     (str form) | ||||
|     (instance? clojure.lang.MapEntry form) | ||||
|                        (str | ||||
|                          (serialize-impl (key form)) | ||||
|                          " = " | ||||
|                          (if (= ".appVersion" (key form)) ;; https://github.com/googlefonts/glyphsLib/issues/209 | ||||
|                            (str \" (val form) \") | ||||
|                            (serialize-impl (val form))) | ||||
|                          ";") | ||||
|     (sequential? form) (if (empty? form) | ||||
|                          "(\n)" | ||||
|                          (str "(\n" (str/join ",\n" (map serialize-impl form)) "\n)")) | ||||
|     (map? form)        (if (empty? form) | ||||
|                          "{\n}" | ||||
|                          (str "{\n" (str/join "\n" (map serialize-impl form)) "\n}")))) | ||||
|  | ||||
| (defn serialize [font] | ||||
|   (str (serialize-impl font) "\n")) | ||||
|  | ||||
| ; (-> (slurp "FiraCode.glyphs") parse serialize (->> (spit "FiraCode_saved.glyphs"))) | ||||
|  | ||||
| (defn load [path] | ||||
|   (println (str "Parsing '" path "'...")) | ||||
|   (parse (slurp path))) | ||||
|  | ||||
| (defn save! [path font] | ||||
|   (println (str "Saving '" path "'...")) | ||||
|   (spit path (serialize font))) | ||||
|  | ||||
| (defn -main [& args] | ||||
|   (let [font (-> (slurp "FiraCode.glyphs") parse)] | ||||
|     (with-open [os (io/writer "clojure/FiraCode.edn")] | ||||
|       (binding [*out* os] | ||||
|         (fipp/pprint font {:width 200}))))) | ||||
|  | ||||
|  | ||||
| (defn update-code [font key name f & args] | ||||
|   (let [idx (coll/index-of #(= (:name %) name) (get font key))] | ||||
|     (apply update-in font [key idx :code] f args))) | ||||
|  | ||||
|  | ||||
| (def weights | ||||
|   {:Light   "B67F0F2D-EC95-4CB8-966E-23AE86958A69" | ||||
|    :Regular "UUID0" | ||||
|    :Bold    "4B7A3BAF-EAD8-4024-9BEA-BB1DE86CFCFA"}) | ||||
|  | ||||
|  | ||||
| (defn layer [l] | ||||
|   { :id (condp = (:layerId l) | ||||
|           (:Light weights)   "Light" | ||||
|           (:Regular weights) "Regular" | ||||
|           (:Bold weights)    "Bold" | ||||
|           (:layerId l)) | ||||
|     :width (:width l) }) | ||||
|  | ||||
| (defn save-not600 [] | ||||
|   (let [font (-> (slurp "FiraCode.glyphs") parse)] | ||||
|     (with-open [os (io/writer "clojure/FiraCode_not600.edn")] | ||||
|       (binding [*out* os] | ||||
|         (let [glyphs (for [glyph (:glyphs font) | ||||
|                            :when (->> (:layers glyph) | ||||
|                                       (filter #(contains? (set (vals weights)) (:layerId %))) | ||||
|                                       (every? #(= 600 (:width %))) | ||||
|                                       (not))] | ||||
|                        {:glyphname (:glyphname glyph) | ||||
|                         :layers    (mapv layer (:layers glyph))})] | ||||
|           (doseq [glyph glyphs] | ||||
|             (fipp/pprint glyph {:width 200})) | ||||
|           (count glyphs)))))) | ||||
|  | ||||
| ;; (-main) | ||||
| ;; (save-not600) | ||||
| ;; (-> (slurp "FiraCode.glyphs") parse keys) | ||||
| ;;  | ||||
							
								
								
									
										29
									
								
								init/FiraCode/clojure/fira_code/main.clj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								init/FiraCode/clojure/fira_code/main.clj
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| (ns fira-code.main | ||||
|   (:require | ||||
|    [clojure.string :as str] | ||||
|    [fira-code.calt :as calt] | ||||
|    [fira-code.coll :as coll] | ||||
|    [fira-code.checks :as checks] | ||||
|    [fira-code.glyphs :as glyphs] | ||||
|    [fira-code.not-space :as not-space] | ||||
|    [fira-code.spacers :as spacers] | ||||
|    [fira-code.time :as time] | ||||
|    [flatland.ordered.map :refer [ordered-map]])) | ||||
|  | ||||
|  | ||||
| (defn -main [& args] | ||||
|   (let [path   (or (first args) "FiraCode.glyphs") | ||||
|         font   (glyphs/load path) | ||||
|         ligas  (for [g (:glyphs font) | ||||
|                      :let [name (:glyphname g)] | ||||
|                      :when (str/ends-with? name ".liga") | ||||
|                      :when (not= "0" (:export g)) | ||||
|                      :let [[_ liga] (re-matches #"([A-Za-z_]+)\.liga" name)]] | ||||
|                  (str/split liga #"_")) ;; [ ["dash" "greater" "greater"] ... ] | ||||
|         font'  (-> font | ||||
|                  (calt/replace-calt ligas) | ||||
|                  (spacers/add-spacers ligas) | ||||
|                  (not-space/regen-not-space) | ||||
|                  (checks/widths))] | ||||
|     (glyphs/save! path font') | ||||
|     (println))) | ||||
							
								
								
									
										14
									
								
								init/FiraCode/clojure/fira_code/not_space.clj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								init/FiraCode/clojure/fira_code/not_space.clj
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| (ns fira-code.not-space | ||||
|   (:require | ||||
|    [clojure.string :as str] | ||||
|    [fira-code.glyphs :as glyphs])) | ||||
|  | ||||
|  | ||||
| (defn regen-not-space [font] | ||||
|   (let [not-spaces (->> (:glyphs font) | ||||
|                      (remove #(re-find #"^\.|space$|space\." (:glyphname %))) | ||||
|                      (remove #(= "0" (:export %))) | ||||
|                      (map :glyphname) | ||||
|                      (sort))] | ||||
|     (println "  regenerated NotSpace:" (count not-spaces) "glyphs") | ||||
|     (glyphs/update-code font :classes "NotSpace" (constantly (str/join " " not-spaces))))) | ||||
							
								
								
									
										31
									
								
								init/FiraCode/clojure/fira_code/spacers.clj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								init/FiraCode/clojure/fira_code/spacers.clj
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| (ns fira-code.spacers | ||||
|   (:require | ||||
|    [clojure.string :as str] | ||||
|    [fira-code.glyphs :as glyphs] | ||||
|    [fira-code.time :as time] | ||||
|    [flatland.ordered.map :refer [ordered-map]])) | ||||
|  | ||||
|  | ||||
| (defn spacer [name] | ||||
|   (ordered-map | ||||
|     :color 3, | ||||
|     :glyphname name, | ||||
|     :lastChange (time/now-str), | ||||
|     :layers | ||||
|     [(ordered-map :layerId (:Light glyphs/weights), :width 1200) | ||||
|      (ordered-map :layerId (:Bold glyphs/weights), :width 1200)])) | ||||
|  | ||||
|  | ||||
| (defn add-spacers [font ligas] | ||||
|   (let [needed   (->> (into #{} cat ligas) | ||||
|                    (map #(str % ".spacer"))) | ||||
|         existing (->> (:glyphs font) | ||||
|                    (map :glyphname) | ||||
|                    (filter #(str/ends-with? % ".spacer"))) | ||||
|         new      (->> (remove (set existing) needed) | ||||
|                    (sort-by str/lower-case))] | ||||
|     (if-not (empty? new) | ||||
|       (do | ||||
|         (println "  added glyphs: " (str/join " " new)) | ||||
|         (update font :glyphs #(into % (map spacer new)))) | ||||
|       font))) | ||||
							
								
								
									
										13
									
								
								init/FiraCode/clojure/fira_code/time.clj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								init/FiraCode/clojure/fira_code/time.clj
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| (ns fira-code.time | ||||
|   (:import | ||||
|    [java.time LocalDateTime ZoneId] | ||||
|    [java.time.format DateTimeFormatter])) | ||||
|  | ||||
|  | ||||
| (def ^ZoneId UTC (ZoneId/of "UTC")) | ||||
|  | ||||
|  | ||||
| (defn now-str [] | ||||
|   (.format | ||||
|     (DateTimeFormatter/ofPattern "yyyy-MM-dd HH:mm:ss +0000") | ||||
|     (LocalDateTime/now UTC))) | ||||
		Reference in New Issue
	
	Block a user