|
56 | 56 |
|
57 | 57 | (def ^:private font-terms
|
58 | 58 | (reduce merge
|
59 |
| - {:bold [:bold "1"] |
60 |
| - :plain [:bold "22"] |
61 |
| - :faint [:bold "2"] |
| 59 | + {:bold [:bold "1"] |
| 60 | + :plain [:bold "22"] |
| 61 | + :faint [:bold "2"] |
62 | 62 |
|
63 |
| - :italic [:italic "3"] |
64 |
| - :roman [:italic "23"] |
| 63 | + :italic [:italic "3"] |
| 64 | + :roman [:italic "23"] |
65 | 65 |
|
66 |
| - :inverse [:inverse "7"] |
67 |
| - :normal [:inverse "27"] |
| 66 | + :inverse [:inverse "7"] |
| 67 | + :normal [:inverse "27"] |
68 | 68 |
|
69 |
| - :underlined [:underlined "4"] |
| 69 | + :underlined [:underlined "4"] |
70 | 70 | :not-underlined [:underlined "24"]}
|
71 | 71 | (map-indexed
|
72 | 72 | (fn [index color-name]
|
73 |
| - {(keyword color-name) [:foreground (str (+ 30 index))] |
74 |
| - (keyword (str "bright-" color-name)) [:foreground (str (+ 90 index))] |
75 |
| - (keyword (str color-name "-bg")) [:background (str (+ 40 index))] |
| 73 | + {(keyword color-name) [:foreground (str (+ 30 index))] |
| 74 | + (keyword (str "bright-" color-name)) [:foreground (str (+ 90 index))] |
| 75 | + (keyword (str color-name "-bg")) [:background (str (+ 40 index))] |
76 | 76 | (keyword (str "bright-" color-name "-bg")) [:background (str (+ 100 index))]})
|
77 | 77 | ["black" "red" "green" "yellow" "blue" "magenta" "cyan" "white"])))
|
78 | 78 |
|
|
94 | 94 | (assert (simple-keyword? font-def) "expected a simple keyword to define the font characteristics")
|
95 | 95 | (mapv keyword (str/split (name font-def) #"\.")))
|
96 | 96 |
|
97 |
| -(def ^:private split-font-def (memoize split-font-def*)) |
| 97 | +(def ^:private memoized-split-font-def* (memoize split-font-def*)) |
| 98 | + |
| 99 | +(defn ^:private split-font-def |
| 100 | + [font-def] |
| 101 | + (if (vector? font-def) |
| 102 | + font-def |
| 103 | + (memoized-split-font-def* font-def))) |
98 | 104 |
|
99 | 105 | (defn- update-font-data-from-font-def
|
100 | 106 | [font-data font-def]
|
101 | 107 | (if (some? font-def)
|
102 | 108 | (let [ks (split-font-def font-def)
|
103 | 109 | f (fn [font-data term]
|
104 |
| - (let [[font-k font-value] (or (get font-terms term) |
105 |
| - (throw (ex-info (str "unexpected font term: " term) |
106 |
| - {:font-term term |
107 |
| - :font-def font-def |
108 |
| - :available-terms (->> font-terms keys sort vec)})))] |
109 |
| - (assoc! font-data font-k font-value)))] |
| 110 | + ;; nils are allowed in the vector form of a font def |
| 111 | + (if (nil? term) |
| 112 | + font-data |
| 113 | + (let [[font-k font-value] (or (get font-terms term) |
| 114 | + (throw (ex-info (str "unexpected font term: " term) |
| 115 | + {:font-term term |
| 116 | + :font-def font-def |
| 117 | + :available-terms (->> font-terms keys sort vec)})))] |
| 118 | + (assoc! font-data font-k font-value))))] |
110 | 119 | (persistent! (reduce f (transient font-data) ks)))
|
111 | 120 | font-data))
|
112 | 121 |
|
|
116 | 125 | (nil? value)
|
117 | 126 | nil
|
118 | 127 |
|
119 |
| - (keyword? value) |
| 128 | + ;; It would be tempting to split the keyword here, but that would obscure an error if the keyword |
| 129 | + ;; contains a substring that isn't an expected font term. |
| 130 | + (or (keyword? value) |
| 131 | + (vector? value)) |
120 | 132 | {:font value}
|
121 | 133 |
|
122 | 134 | (map? value)
|
|
173 | 185 | ;; If at or over desired width, don't need to pad
|
174 | 186 | (if (<= width actual-width)
|
175 | 187 | {:width actual-width
|
176 |
| - :span inputs'}) |
| 188 | + :span inputs'}) |
177 | 189 | ;; Add the padding in the desired position(s); this ensures that the logic that generates
|
178 | 190 | ;; ANSI escape codes occurs correctly, with the added spaces getting the font for this span.
|
179 | 191 | {:width width
|
180 |
| - :span (apply-padding inputs' pad width actual-width)})) |
| 192 | + :span (apply-padding inputs' pad width actual-width)})) |
181 | 193 |
|
182 | 194 |
|
183 | 195 | (defn- normalize-markup
|
|
252 | 264 | [inputs]
|
253 | 265 | (let [initial-font {:foreground "39"
|
254 | 266 | :background "49"
|
255 |
| - :bold "22" |
256 |
| - :italic "23" |
257 |
| - :inverse "27" |
| 267 | + :bold "22" |
| 268 | + :italic "23" |
| 269 | + :inverse "27" |
258 | 270 | :underlined "24"}
|
259 | 271 | buffer (StringBuilder. 100)
|
260 |
| - {:keys [dirty?]} (collect-markup {:stack [] |
261 |
| - :active initial-font |
| 272 | + {:keys [dirty?]} (collect-markup {:stack [] |
| 273 | + :active initial-font |
262 | 274 | :current initial-font
|
263 |
| - :buffer buffer} |
| 275 | + :buffer buffer} |
264 | 276 | inputs)]
|
265 | 277 | (when dirty?
|
266 | 278 | (.append buffer reset-font))
|
|
310 | 322 | Font defs apply on top of the font def of the enclosing span, and the outer span's font def
|
311 | 323 | is restored at the end of the inner span, e.g. `[:red \" RED \" [:bold \"RED/BOLD\"] \" RED \"]`.
|
312 | 324 |
|
| 325 | + Alternately, a font def may be a vector of individual keyword, e.g., `[[:bold :red] ...]` rather than |
| 326 | + `[:bold.red ...]`. This works better when the exact font characteristics are determined |
| 327 | + dynamically. |
| 328 | +
|
313 | 329 | A font def may also be nil, to indicate no change in font.
|
314 | 330 |
|
315 | 331 | `compose` presumes that on entry the current font is plain (default foreground and background, not bold,
|
|
323 | 339 |
|
324 | 340 | The span's font declaration may also be a map with the following keys:
|
325 | 341 |
|
326 |
| - Key | Type | Description |
327 |
| - --- |--- |--- |
328 |
| - :font | keyword | The font declaration |
329 |
| - :width | number | The visual width of the span |
330 |
| - :pad | keyword | Where to pad the span, :left, :right, or :both; default is :left |
| 342 | + Key | Type | Description |
| 343 | + --- |--- |--- |
| 344 | + :font | keyword or vector of keywords | The font declaration |
| 345 | + :width | number | The desired width of the span |
| 346 | + :pad | :left, :right, :both | Where to pad the span if :width specified, default is :left |
331 | 347 |
|
332 | 348 | The map form of the font declaration is typically only used when a span width is specified.
|
333 | 349 | The span will be padded with spaces to ensure that it is the specified width. `compose` tracks the number
|
|
0 commit comments