mirror of
https://github.com/tonsky/FiraCode.git
synced 2024-09-11 13:06:27 +03:00
136 lines
4.0 KiB
Clojure
Executable File
136 lines
4.0 KiB
Clojure
Executable File
#^:shebang '[
|
|
exec java -cp "$HOME/.m2/repository/org/clojure/clojure/1.7.0/clojure-1.7.0.jar" clojure.main "$0" "$@"]
|
|
|
|
|
|
(require '[clojure.string :as str])
|
|
|
|
(def file "FiraCode.glyphs")
|
|
|
|
(println "Looking for ligatures in" file "...\n")
|
|
|
|
;; [ ["dash" "greater" "greater"] ... ]
|
|
(def ligas (->> (slurp file)
|
|
(re-seq #"glyphname = ([a-z_]+)\.liga;")
|
|
(map second)
|
|
set
|
|
(mapv #(vec (str/split % #"_")))))
|
|
|
|
|
|
; (def ligas
|
|
; [ ["hyphen" "greater"]
|
|
; ["greater" "equal"]
|
|
; ["equal" "greater"]
|
|
; ["hyphen" "hyphen" "greater"]
|
|
; ["equal" "equal" "greater"]
|
|
; ["greater" "hyphen"]])
|
|
|
|
; (def ligas
|
|
; [ ["slash" "asterisk"]
|
|
; ["slash" "asterisk" "asterisk"]
|
|
; ["asterisk" "asterisk"]
|
|
; ["asterisk" "asterisk" "asterisk"]])
|
|
|
|
|
|
(defn liga->rules
|
|
"[f f i] => { [CR CR i] f_f_i.liga
|
|
[CR f i] CR
|
|
[ f f i] CR }"
|
|
[liga CR]
|
|
(case (count liga)
|
|
2 (let [[a b] liga]
|
|
{ [CR b] (str a "_" b ".liga")
|
|
[ a b] CR})
|
|
3 (let [[a b c] liga]
|
|
{ [CR CR c] (str a "_" b "_" c ".liga")
|
|
[CR b c] CR
|
|
[ a b c] CR})
|
|
4 (let [[a b c d] liga]
|
|
{ [CR CR CR d] (str a "_" b "_" c "_" d ".liga")
|
|
[CR CR c d] CR
|
|
[CR b c d] CR
|
|
[ a b c d] CR})))
|
|
|
|
|
|
(defn any? [p & colls]
|
|
(if colls
|
|
(let [[coll & cs] colls]
|
|
(some #(apply any? (partial p %) cs) coll))
|
|
(p)))
|
|
|
|
|
|
(defn conflicts? [r1 r2]
|
|
(when (.startsWith (first r2) "CR.") ;; we accept that higher-len ligatures can override lower-length
|
|
;; but once replacement has started (first glyph in rule is CR.*)
|
|
;; there should be no possibility for conflits
|
|
(let [l1 (count r1)
|
|
l2 (count r2)
|
|
prefix1 (subvec r1 0 l2)]
|
|
(= r2 prefix1))))
|
|
|
|
|
|
(def all-rules
|
|
(reduce
|
|
(fn [generated liga]
|
|
(merge generated
|
|
;; looking for smallest i that does not conflict
|
|
;; with any of previous rules
|
|
(some (fn [i]
|
|
(let [CR (str "CR." (String/format "%02d" (to-array [i])))
|
|
rs (liga->rules liga CR)]
|
|
; (println (keys generated) (keys rs))
|
|
(when-not (any? conflicts? (keys generated) (keys rs))
|
|
rs)))
|
|
(range))))
|
|
{}
|
|
(->> ligas (sort-by count) reverse)))
|
|
|
|
|
|
(defn priority-fn [[from to]]
|
|
[;; first compare how many CRs are there (more is better)
|
|
(- (count (filter #(re-matches #"CR\.\d+" %) from)))
|
|
;; then overal length (more is better)
|
|
(- (count from))
|
|
;; then alphabetical sort with coercing each vector to the same length
|
|
(into from (repeat (- 4 (count from)) "z"))])
|
|
|
|
|
|
(def table (->> all-rules
|
|
(sort-by priority-fn)))
|
|
|
|
|
|
(defn rule->str [[from to]]
|
|
(loop [res "sub"
|
|
seen-non-empty? false
|
|
tokens from]
|
|
(if-let [token (first tokens)]
|
|
(let [class? (.startsWith token "@")
|
|
CR? (.startsWith token "CR.")
|
|
escaped-token (cond
|
|
class? token
|
|
CR? (str "\\" token)
|
|
seen-non-empty? (str "\\" token)
|
|
:else (str "\\" token "'"))]
|
|
(recur (str res " " escaped-token) (not CR?) (next tokens)))
|
|
(str res " by \\" to ";"))))
|
|
|
|
|
|
(println "feature calt {")
|
|
(println " " (->> table (map rule->str) (str/join "\n ")))
|
|
(println "}\n")
|
|
|
|
|
|
|
|
(apply println "Placeholders:\n " (->> table (mapcat first) (filter #(.startsWith % "CR.")) distinct sort))
|
|
(println)
|
|
|
|
|
|
(println "Total ligatures count:" (count ligas))
|
|
(println " " (->> ligas
|
|
(group-by count)
|
|
(sort-by first)
|
|
(map (fn [[k v]] (str (count v) (case k 2 " pairs", 3 " triples", 4 " quadruples"))))
|
|
(str/join ", ")))
|
|
(println)
|
|
|
|
(println "Total rules count:" (count table))
|