@seanmozeik/markdown-display 0.3.5 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (399) hide show
  1. package/README.md +41 -20
  2. package/dist/abap-9xbv043v.js +2 -0
  3. package/dist/actionscript-3-ffr5ydrs.js +2 -0
  4. package/dist/ada-jk2gn0pn.js +2 -0
  5. package/dist/andromeeda-24gktw4d.js +2 -0
  6. package/dist/angular-html-xg28445y.js +2 -0
  7. package/dist/angular-ts-1xq6mw7g.js +2 -0
  8. package/dist/apache-4b3b0eyy.js +2 -0
  9. package/dist/apex-a3awgdsm.js +2 -0
  10. package/dist/apl-f630k1vx.js +2 -0
  11. package/dist/applescript-qreypzb3.js +2 -0
  12. package/dist/ara-a0ghw0xy.js +2 -0
  13. package/dist/asciidoc-17amrzcg.js +2 -0
  14. package/dist/asm-1ybpdpc6.js +2 -0
  15. package/dist/astro-2vzy1qg5.js +2 -0
  16. package/dist/aurora-x-pb2h8m75.js +2 -0
  17. package/dist/awk-4g14sdfr.js +2 -0
  18. package/dist/ayu-dark-a6e49das.js +2 -0
  19. package/dist/ayu-light-ac787hyf.js +2 -0
  20. package/dist/ayu-mirage-zjtmb0bg.js +2 -0
  21. package/dist/ballerina-fd1yzyy8.js +2 -0
  22. package/dist/banner-ng06wc8g.js +12 -0
  23. package/dist/bat-x024z34k.js +2 -0
  24. package/dist/beancount-4aa1ce0k.js +2 -0
  25. package/dist/berry-1157ed3y.js +2 -0
  26. package/dist/bibtex-s0jadepe.js +2 -0
  27. package/dist/bicep-gx08m1nz.js +2 -0
  28. package/dist/bird2-3g0vanh0.js +2 -0
  29. package/dist/blade-22gzdntq.js +2 -0
  30. package/dist/bsl-r8cmv6pz.js +2 -0
  31. package/dist/c-g33d1744.js +2 -0
  32. package/dist/c3-02s6n09a.js +2 -0
  33. package/dist/cadence-b5x3mzqg.js +2 -0
  34. package/dist/cairo-4v5k49bw.js +2 -0
  35. package/dist/catppuccin-frappe-zze8rp4c.js +2 -0
  36. package/dist/catppuccin-latte-ebmyxk6e.js +2 -0
  37. package/dist/catppuccin-macchiato-8m9avkeq.js +2 -0
  38. package/dist/catppuccin-mocha-caq0gmr7.js +2 -0
  39. package/dist/clarity-x08cc58e.js +2 -0
  40. package/dist/cli-0y1zeg7v.js +3 -0
  41. package/dist/cli-1hj5h9f9.js +3 -0
  42. package/dist/cli-2h1yfjdw.js +3 -0
  43. package/dist/cli-30n24kzz.js +3 -0
  44. package/dist/cli-3fzyv189.js +3 -0
  45. package/dist/cli-3wvgjq8z.js +3 -0
  46. package/dist/cli-3z230jhh.js +3 -0
  47. package/dist/cli-48yac15g.js +3 -0
  48. package/dist/cli-58p99hkc.js +3 -0
  49. package/dist/cli-5jp9npt1.js +3 -0
  50. package/dist/cli-5v8q61ce.js +3 -0
  51. package/dist/cli-6jzqb50s.js +3 -0
  52. package/dist/cli-79y9hz07.js +3 -0
  53. package/dist/cli-81dmk4ts.js +3 -0
  54. package/dist/cli-81w52zkt.js +3 -0
  55. package/dist/cli-8nneg522.js +3 -0
  56. package/dist/cli-8qe0pqv6.js +3 -0
  57. package/dist/cli-a8250sbe.js +3 -0
  58. package/dist/cli-ac5hc1dt.js +3 -0
  59. package/dist/cli-app-6kzbj8e4.js +411 -0
  60. package/dist/cli-ayvxq7qa.js +3 -0
  61. package/dist/cli-banpa4vr.js +7 -0
  62. package/dist/cli-bt5bw9b4.js +3 -0
  63. package/dist/cli-c0mb9wq6.js +3 -0
  64. package/dist/cli-dg73jpjs.js +3 -0
  65. package/dist/cli-e21h859y.js +3 -0
  66. package/dist/cli-g0wwxff6.js +3 -0
  67. package/dist/cli-gtjpq1mb.js +3 -0
  68. package/dist/cli-ha8pqpt8.js +3 -0
  69. package/dist/cli-hsvv3jzh.js +3 -0
  70. package/dist/cli-hxsnf2x8.js +3 -0
  71. package/dist/cli-jewjtf3e.js +3 -0
  72. package/dist/cli-jkvh6m6e.js +3 -0
  73. package/dist/cli-jqdxtesj.js +3 -0
  74. package/dist/cli-k2dtsfh9.js +3 -0
  75. package/dist/cli-m8zynty7.js +3 -0
  76. package/dist/cli-n5czz7gz.js +3 -0
  77. package/dist/cli-r2h3ee8w.js +3 -0
  78. package/dist/cli-rkqs0vcv.js +3 -0
  79. package/dist/cli-ss2qwkcc.js +3 -0
  80. package/dist/cli-tse5g5yz.js +3 -0
  81. package/dist/cli-v04mbmxe.js +3 -0
  82. package/dist/cli-v37wd532.js +3 -0
  83. package/dist/cli-vbncttvd.js +3 -0
  84. package/dist/cli-vt93z537.js +3 -0
  85. package/dist/cli-w37ddf7r.js +3 -0
  86. package/dist/cli-yjt0k8jp.js +3 -0
  87. package/dist/cli-yxfvsvk9.js +3 -0
  88. package/dist/clojure-vzmv55wf.js +2 -0
  89. package/dist/cmake-7y22bc67.js +2 -0
  90. package/dist/cobol-kdnhdmjz.js +2 -0
  91. package/dist/codeowners-x6m7bhdc.js +2 -0
  92. package/dist/codeql-6rz9fzqw.js +2 -0
  93. package/dist/coffee-hdfzr8ps.js +2 -0
  94. package/dist/common-lisp-zmr06g7n.js +2 -0
  95. package/dist/coq-r8j5c36h.js +2 -0
  96. package/dist/cpp-cnh8n6p9.js +2 -0
  97. package/dist/crystal-mrgdvpq4.js +2 -0
  98. package/dist/csharp-q48m96qr.js +2 -0
  99. package/dist/css-bd0hqx8d.js +2 -0
  100. package/dist/csv-4m85ky3s.js +2 -0
  101. package/dist/cue-tkch0b5s.js +2 -0
  102. package/dist/cypher-9v66whj2.js +2 -0
  103. package/dist/d-h7frep7v.js +2 -0
  104. package/dist/dark-plus-3mz49csr.js +2 -0
  105. package/dist/dart-0ts3fbr7.js +2 -0
  106. package/dist/dax-epx6f5sr.js +2 -0
  107. package/dist/desktop-ga56hzcd.js +2 -0
  108. package/dist/diff-nj0camxe.js +2 -0
  109. package/dist/docker-ck9z05s1.js +2 -0
  110. package/dist/dotenv-n24rx33c.js +2 -0
  111. package/dist/dracula-rt7zm8kp.js +2 -0
  112. package/dist/dracula-soft-ny1w766n.js +2 -0
  113. package/dist/dream-maker-5bdhk1xw.js +2 -0
  114. package/dist/edge-nes62z5q.js +2 -0
  115. package/dist/elixir-t2dacwg4.js +2 -0
  116. package/dist/elm-efkwc9kb.js +2 -0
  117. package/dist/emacs-lisp-aeyrqndc.js +2 -0
  118. package/dist/erb-1jnjam5w.js +2 -0
  119. package/dist/erlang-q2nxsk7t.js +2 -0
  120. package/dist/everforest-dark-q5afr5gg.js +2 -0
  121. package/dist/everforest-light-gwf12vcx.js +2 -0
  122. package/dist/fennel-qcrnckrq.js +2 -0
  123. package/dist/fish-fybdeyvp.js +2 -0
  124. package/dist/fluent-71z72985.js +2 -0
  125. package/dist/fortran-fixed-form-1gqb01bw.js +2 -0
  126. package/dist/fortran-free-form-kxkmegqs.js +2 -0
  127. package/dist/fsharp-cgvxcgsx.js +2 -0
  128. package/dist/gdresource-46k5gmzt.js +2 -0
  129. package/dist/gdscript-68kq1xvg.js +2 -0
  130. package/dist/gdshader-b3674jka.js +2 -0
  131. package/dist/genie-jyymh6js.js +2 -0
  132. package/dist/gherkin-7e2sjv5d.js +2 -0
  133. package/dist/git-commit-9wk0r5sb.js +2 -0
  134. package/dist/git-rebase-prhzk4j5.js +2 -0
  135. package/dist/github-dark-default-0vxh5df6.js +2 -0
  136. package/dist/github-dark-dimmed-mrkg0dkj.js +2 -0
  137. package/dist/github-dark-high-contrast-dfjvzvs1.js +2 -0
  138. package/dist/github-dark-vmmv282e.js +2 -0
  139. package/dist/github-light-79sz9hnx.js +2 -0
  140. package/dist/github-light-default-1jr038w7.js +2 -0
  141. package/dist/github-light-high-contrast-r2s26c8v.js +2 -0
  142. package/dist/gleam-0915n1m3.js +2 -0
  143. package/dist/glimmer-js-k7czmdfm.js +2 -0
  144. package/dist/glimmer-ts-194ejtg4.js +2 -0
  145. package/dist/glsl-dj78d5j4.js +2 -0
  146. package/dist/gn-1hvwh71v.js +2 -0
  147. package/dist/gnuplot-3hmy4dt7.js +2 -0
  148. package/dist/go-33wfsnyk.js +2 -0
  149. package/dist/graphql-0aac9yec.js +2 -0
  150. package/dist/groovy-ja0xcaxz.js +2 -0
  151. package/dist/gruvbox-dark-hard-5s80mtba.js +2 -0
  152. package/dist/gruvbox-dark-medium-n4khhzte.js +2 -0
  153. package/dist/gruvbox-dark-soft-e71n00ep.js +2 -0
  154. package/dist/gruvbox-light-hard-pbvye0e8.js +2 -0
  155. package/dist/gruvbox-light-medium-ta1n6jez.js +2 -0
  156. package/dist/gruvbox-light-soft-ymh9etvc.js +2 -0
  157. package/dist/hack-wbm9q4mm.js +2 -0
  158. package/dist/haml-gx26k3n5.js +2 -0
  159. package/dist/handlebars-x15bnv4j.js +2 -0
  160. package/dist/haskell-gphr2mx4.js +2 -0
  161. package/dist/haxe-jjqygeb7.js +2 -0
  162. package/dist/hcl-cr0bx0fz.js +2 -0
  163. package/dist/hjson-f1xxjn7x.js +2 -0
  164. package/dist/hlsl-dx0egzxe.js +2 -0
  165. package/dist/horizon-bright-4xdqr7cd.js +2 -0
  166. package/dist/horizon-ztsnzjdn.js +2 -0
  167. package/dist/houston-61g9eh8r.js +2 -0
  168. package/dist/html-derivative-hvxv75a7.js +2 -0
  169. package/dist/html-wqddzypw.js +2 -0
  170. package/dist/http-kh76rh1s.js +2 -0
  171. package/dist/hurl-4c8qps7w.js +2 -0
  172. package/dist/hxml-3bkn4jp8.js +2 -0
  173. package/dist/hy-fxpg7aaw.js +2 -0
  174. package/dist/imba-q8na79n7.js +2 -0
  175. package/dist/index-pdw64t43.js +15 -0
  176. package/dist/ini-s6y2n2r0.js +2 -0
  177. package/dist/java-bcf5924q.js +2 -0
  178. package/dist/javascript-qmy7d5mk.js +2 -0
  179. package/dist/jinja-y1162pxj.js +2 -0
  180. package/dist/jison-444dx63z.js +2 -0
  181. package/dist/json-gwwdj89t.js +2 -0
  182. package/dist/json5-3100ynmc.js +2 -0
  183. package/dist/jsonc-v2rnz0h1.js +2 -0
  184. package/dist/jsonl-axvqz7sn.js +2 -0
  185. package/dist/jsonnet-zfn0ptb5.js +2 -0
  186. package/dist/jssm-gej4xq4j.js +2 -0
  187. package/dist/jsx-zc0j90dq.js +2 -0
  188. package/dist/julia-as91r849.js +2 -0
  189. package/dist/just-zmsqbkqy.js +2 -0
  190. package/dist/kanagawa-dragon-d76szdr9.js +2 -0
  191. package/dist/kanagawa-lotus-wd9eezwr.js +2 -0
  192. package/dist/kanagawa-wave-acc5532t.js +2 -0
  193. package/dist/kdl-0nd9fhgr.js +2 -0
  194. package/dist/kotlin-v71xk1rn.js +2 -0
  195. package/dist/kusto-9mpsj4vk.js +2 -0
  196. package/dist/laserwave-db8954kv.js +2 -0
  197. package/dist/latex-xs0c2nvw.js +2 -0
  198. package/dist/lean-vdhz6cqv.js +2 -0
  199. package/dist/less-312pw0ev.js +2 -0
  200. package/dist/light-plus-aq99ra4y.js +2 -0
  201. package/dist/liquid-dmnzg3ty.js +2 -0
  202. package/dist/llvm-t6bzgxkv.js +2 -0
  203. package/dist/log-ssjyybt8.js +2 -0
  204. package/dist/logo-qb8mz41r.js +2 -0
  205. package/dist/lua-kk3ewrfz.js +2 -0
  206. package/dist/luau-1332gd7k.js +2 -0
  207. package/dist/make-ym3y5he3.js +2 -0
  208. package/dist/markdown-yakp348x.js +2 -0
  209. package/dist/marko-t2xabqrz.js +2 -0
  210. package/dist/material-theme-darker-vyfbvm1v.js +2 -0
  211. package/dist/material-theme-e94sgaj2.js +2 -0
  212. package/dist/material-theme-lighter-12stms50.js +2 -0
  213. package/dist/material-theme-ocean-vbjhpav2.js +2 -0
  214. package/dist/material-theme-palenight-zvsby2j7.js +2 -0
  215. package/dist/matlab-7z9bsz8e.js +2 -0
  216. package/dist/md.js +4 -0
  217. package/dist/mdc-fnzmnxrv.js +2 -0
  218. package/dist/mdx-txks2jee.js +2 -0
  219. package/dist/mermaid-2geg9v5h.js +2 -0
  220. package/dist/min-dark-p6btg8dq.js +2 -0
  221. package/dist/min-light-v3br1wzp.js +2 -0
  222. package/dist/mipsasm-npsfhz7p.js +2 -0
  223. package/dist/mojo-53s8q8kz.js +2 -0
  224. package/dist/monokai-j1kkm1ja.js +2 -0
  225. package/dist/moonbit-gcr903w0.js +2 -0
  226. package/dist/move-4vm43y7r.js +2 -0
  227. package/dist/narrat-4dfafp1n.js +2 -0
  228. package/dist/nextflow-gen0wthn.js +2 -0
  229. package/dist/nextflow-groovy-rntv4ct1.js +2 -0
  230. package/dist/nginx-md97v71f.js +2 -0
  231. package/dist/night-owl-bgdmn1df.js +2 -0
  232. package/dist/night-owl-light-jka34m0q.js +2 -0
  233. package/dist/nim-fngvzh2t.js +2 -0
  234. package/dist/nix-x4emth0n.js +2 -0
  235. package/dist/nord-xscwecj8.js +2 -0
  236. package/dist/nushell-tjxswzet.js +2 -0
  237. package/dist/objective-c-nk9a9yrs.js +2 -0
  238. package/dist/objective-cpp-p6sapemd.js +2 -0
  239. package/dist/ocaml-bcy7sgka.js +2 -0
  240. package/dist/odin-5vrv5d1s.js +2 -0
  241. package/dist/one-dark-pro-r96tb03e.js +2 -0
  242. package/dist/one-light-bfcdemmg.js +2 -0
  243. package/dist/openscad-w36wsg83.js +2 -0
  244. package/dist/pascal-zje13224.js +2 -0
  245. package/dist/perl-jb96y2dw.js +2 -0
  246. package/dist/php-66y7zdam.js +2 -0
  247. package/dist/pkl-j08f73a2.js +2 -0
  248. package/dist/plastic-d95k0yjm.js +2 -0
  249. package/dist/plsql-a5tqv6r5.js +2 -0
  250. package/dist/po-z4zztbvf.js +2 -0
  251. package/dist/poimandres-ft3p00vk.js +2 -0
  252. package/dist/polar-45ka4fdw.js +2 -0
  253. package/dist/postcss-ak75ftnf.js +2 -0
  254. package/dist/powerquery-j6z2e9xw.js +2 -0
  255. package/dist/powershell-ca63wk2e.js +2 -0
  256. package/dist/prisma-b2y4avdt.js +2 -0
  257. package/dist/prolog-wktkj1zv.js +2 -0
  258. package/dist/proto-5pd1z1zv.js +2 -0
  259. package/dist/pug-80k5jz6p.js +2 -0
  260. package/dist/puppet-66683nhq.js +2 -0
  261. package/dist/purescript-cmqqet79.js +2 -0
  262. package/dist/python-jabyzx3d.js +2 -0
  263. package/dist/qml-d92cbtkt.js +2 -0
  264. package/dist/qmldir-za85z5zc.js +2 -0
  265. package/dist/qss-gh7cf1zk.js +2 -0
  266. package/dist/r-s39xqqt9.js +2 -0
  267. package/dist/racket-gbjk3es0.js +2 -0
  268. package/dist/raku-zqwbnxmq.js +2 -0
  269. package/dist/razor-zg3bck80.js +2 -0
  270. package/dist/red-k6970d1d.js +2 -0
  271. package/dist/reg-gserh519.js +2 -0
  272. package/dist/regexp-a95pq17y.js +2 -0
  273. package/dist/rel-gaefrfhc.js +2 -0
  274. package/dist/riscv-cszphkwv.js +2 -0
  275. package/dist/ron-yf5x21c5.js +2 -0
  276. package/dist/rose-pine-1zbcjg1b.js +2 -0
  277. package/dist/rose-pine-dawn-tmsqdesr.js +2 -0
  278. package/dist/rose-pine-moon-cmwgg41b.js +2 -0
  279. package/dist/rosmsg-8j5zf8wv.js +2 -0
  280. package/dist/rst-7trgmfaq.js +2 -0
  281. package/dist/ruby-2svq4615.js +2 -0
  282. package/dist/rust-q5spk848.js +2 -0
  283. package/dist/sas-qhcyyrbt.js +2 -0
  284. package/dist/sass-qwyex0n3.js +2 -0
  285. package/dist/scala-jmhd870s.js +2 -0
  286. package/dist/scheme-5dvkrg0d.js +2 -0
  287. package/dist/scss-7v9m0m7d.js +2 -0
  288. package/dist/sdbl-93kewz9d.js +2 -0
  289. package/dist/shaderlab-97e0480d.js +2 -0
  290. package/dist/shellscript-6mxk36va.js +2 -0
  291. package/dist/shellsession-c7mva2xt.js +2 -0
  292. package/dist/slack-dark-y62znhvd.js +2 -0
  293. package/dist/slack-ochin-esm65n7t.js +2 -0
  294. package/dist/smalltalk-fkw0jz97.js +2 -0
  295. package/dist/snazzy-light-gdz5rv1k.js +2 -0
  296. package/dist/solarized-dark-zgcy8wm4.js +2 -0
  297. package/dist/solarized-light-66pg8xzk.js +2 -0
  298. package/dist/solidity-q5d4ht8n.js +2 -0
  299. package/dist/soy-hhhx5cj0.js +2 -0
  300. package/dist/sparql-hm2pqpge.js +2 -0
  301. package/dist/splunk-w5h843nw.js +2 -0
  302. package/dist/sql-pas3x5ke.js +2 -0
  303. package/dist/ssh-config-n2kt2cym.js +2 -0
  304. package/dist/stata-9j4p5d8c.js +2 -0
  305. package/dist/stylus-9s01c3kp.js +2 -0
  306. package/dist/surrealql-gxntasn8.js +2 -0
  307. package/dist/svelte-nvgnrg0t.js +2 -0
  308. package/dist/swift-j07yna4k.js +2 -0
  309. package/dist/synthwave-84-d7yw2bf0.js +2 -0
  310. package/dist/system-verilog-30bs377q.js +2 -0
  311. package/dist/systemd-4252hbv8.js +2 -0
  312. package/dist/talonscript-qbxwesm0.js +2 -0
  313. package/dist/tasl-m18yj07w.js +2 -0
  314. package/dist/tcl-qfvbg90f.js +2 -0
  315. package/dist/templ-msv3jzfx.js +2 -0
  316. package/dist/terraform-w6q6kyy0.js +2 -0
  317. package/dist/tex-1h8385qh.js +2 -0
  318. package/dist/tokyo-night-11kv01fx.js +2 -0
  319. package/dist/toml-02rkjp4b.js +2 -0
  320. package/dist/ts-tags-zmwja4z5.js +2 -0
  321. package/dist/tsv-t7svepav.js +2 -0
  322. package/dist/tsx-5ck84m8p.js +2 -0
  323. package/dist/turtle-synzazfp.js +2 -0
  324. package/dist/twig-41166c5j.js +2 -0
  325. package/dist/typescript-cqey3bjn.js +2 -0
  326. package/dist/typespec-ddd8ynv9.js +2 -0
  327. package/dist/typst-ex558216.js +2 -0
  328. package/dist/v-1bn5h0en.js +2 -0
  329. package/dist/vala-078a3s0x.js +2 -0
  330. package/dist/vb-5sq26hr3.js +2 -0
  331. package/dist/verilog-ekh48e1e.js +2 -0
  332. package/dist/vesper-j18bqpbg.js +2 -0
  333. package/dist/vhdl-fhjza3xz.js +2 -0
  334. package/dist/viml-9jfzgmge.js +2 -0
  335. package/dist/vitesse-black-3b8qwvte.js +2 -0
  336. package/dist/vitesse-dark-bsvtvg1h.js +2 -0
  337. package/dist/vitesse-light-egp8j39z.js +2 -0
  338. package/dist/vue-6yd2mg34.js +2 -0
  339. package/dist/vue-html-y5mtwexa.js +2 -0
  340. package/dist/vue-vine-732a4732.js +2 -0
  341. package/dist/vyper-h4fr87vt.js +2 -0
  342. package/dist/wasm-c0hbsbpk.js +2 -0
  343. package/dist/wasm-xe5dxyky.js +2 -0
  344. package/dist/wenyan-pf79c6ns.js +2 -0
  345. package/dist/wgsl-20v05k5y.js +2 -0
  346. package/dist/wikitext-6vf691aw.js +2 -0
  347. package/dist/wit-gp0gbqxw.js +2 -0
  348. package/dist/wolfram-y1r4y7zp.js +2 -0
  349. package/dist/xml-9fqvyqnc.js +2 -0
  350. package/dist/xsl-xpzpqrmc.js +2 -0
  351. package/dist/yaml-885sffq4.js +2 -0
  352. package/dist/zenscript-0k3ar154.js +2 -0
  353. package/dist/zig-h5gys7p5.js +2 -0
  354. package/package.json +51 -23
  355. package/src/app/cli-info.ts +90 -0
  356. package/src/app/errors.ts +19 -0
  357. package/src/app/file-not-found-error.ts +6 -0
  358. package/src/app/format-error.ts +35 -0
  359. package/src/app/invalid-theme-error.ts +6 -0
  360. package/src/app/pager-error.ts +5 -0
  361. package/src/app/run-md.ts +197 -0
  362. package/src/app/stdin-read-error.ts +5 -0
  363. package/src/cli/options.ts +20 -0
  364. package/src/cli-app.ts +113 -0
  365. package/src/cli.ts +64 -0
  366. package/src/config/errors.ts +6 -0
  367. package/src/config/index.ts +183 -0
  368. package/src/config/read-error.ts +6 -0
  369. package/src/constants.ts +2 -0
  370. package/src/index.ts +51 -0
  371. package/src/lib/ansi.ts +24 -0
  372. package/src/lib/config.ts +2 -0
  373. package/src/lib/default-config.toml +25 -0
  374. package/src/lib/elements/blockquote.ts +34 -0
  375. package/src/lib/elements/code.ts +326 -0
  376. package/src/lib/elements/heading.ts +39 -0
  377. package/src/lib/elements/link.ts +33 -0
  378. package/src/lib/elements/list.ts +89 -0
  379. package/src/lib/elements/table.ts +65 -0
  380. package/src/lib/elements/text.ts +237 -0
  381. package/src/lib/languages.ts +123 -0
  382. package/src/lib/layout.ts +67 -0
  383. package/src/lib/pager.ts +121 -0
  384. package/src/lib/parser.ts +299 -0
  385. package/src/lib/render-code-blocks.ts +25 -0
  386. package/src/lib/render.ts +37 -0
  387. package/src/lib/shiki.ts +197 -0
  388. package/src/lib/width.ts +21 -0
  389. package/src/paths.ts +14 -0
  390. package/src/ui/banner.ts +23 -0
  391. package/src/ui/picker.ts +120 -0
  392. package/src/ui/themes/ansi.ts +161 -0
  393. package/src/ui/themes/color-support.ts +106 -0
  394. package/src/ui/themes/generated.ts +748 -0
  395. package/src/ui/themes/index.ts +58 -0
  396. package/src/ui/themes/overrides.ts +83 -0
  397. package/src/ui/themes/semantic.ts +125 -0
  398. package/src/ui/themes/types.ts +67 -0
  399. package/dist/index.js +0 -194
@@ -0,0 +1,299 @@
1
+ // Src/lib/parser.ts
2
+ import { Effect, Schema } from 'effect';
3
+ import { Marked, type RendererObject, type Token } from 'marked';
4
+
5
+ import { theme } from '../ui/themes';
6
+ import { getBoldStyle, getItalicStyle } from '../ui/themes/semantic';
7
+ import { renderBlockquote } from './elements/blockquote';
8
+ import { type CodeConfig, renderInlineCode } from './elements/code';
9
+ import { renderHeading } from './elements/heading';
10
+ import { renderLink } from './elements/link';
11
+ import { renderListItem } from './elements/list';
12
+ import { renderTable } from './elements/table';
13
+ import { renderText } from './elements/text';
14
+ import { renderCodeBlocksParallel } from './render-code-blocks';
15
+
16
+ interface ParseOptions {
17
+ width: number;
18
+ osc8?: boolean | 'auto';
19
+ wrap?: boolean;
20
+ hyphenation?: boolean;
21
+ nerdFonts?: boolean;
22
+ continuation?: string;
23
+ }
24
+
25
+ class MarkdownParseError extends Schema.TaggedErrorClass<MarkdownParseError>()(
26
+ 'MarkdownParseError',
27
+ { cause: Schema.Unknown },
28
+ ) {}
29
+
30
+ // Type for marked renderer context (this binding)
31
+ interface RendererThis {
32
+ parser: { parse(tokens: Token[]): string; parseInline(tokens: Token[]): string };
33
+ }
34
+
35
+ const RANDOM_ID_RADIX = 36;
36
+
37
+ interface ListItemToken {
38
+ tokens: Token[];
39
+ task?: boolean;
40
+ checked?: boolean;
41
+ }
42
+
43
+ interface NestedList {
44
+ items: ListItemToken[];
45
+ ordered: boolean;
46
+ start?: number;
47
+ }
48
+
49
+ interface CodeToken {
50
+ text: string;
51
+ lang?: string;
52
+ }
53
+
54
+ const isNestedListToken = (
55
+ token: Token,
56
+ ): token is Token & { items: ListItemToken[]; ordered: boolean; start?: number } =>
57
+ token.type === 'list' && 'items' in token && Array.isArray(token.items);
58
+
59
+ const isCodeToken = (token: Token): token is Token & CodeToken =>
60
+ token.type === 'code' && 'text' in token && typeof token.text === 'string';
61
+
62
+ const createRenderer = (
63
+ options: ParseOptions,
64
+ codeBlocks: Map<string, { code: string; lang: string }>,
65
+ ): RendererObject => {
66
+ const classifyListItemTokens = (
67
+ item: ListItemToken,
68
+ ): { inlineTokens: Token[]; nestedLists: NestedList[]; blockContent: Token[] } => {
69
+ const INLINE_TYPES = new Set([
70
+ 'text',
71
+ 'strong',
72
+ 'em',
73
+ 'codespan',
74
+ 'link',
75
+ 'image',
76
+ 'br',
77
+ 'del',
78
+ 'escape',
79
+ 'checkbox',
80
+ ]);
81
+
82
+ const inlineTokens: Token[] = [];
83
+ const nestedLists: NestedList[] = [];
84
+ const blockContent: Token[] = [];
85
+
86
+ for (const t of item.tokens) {
87
+ if (isNestedListToken(t)) {
88
+ nestedLists.push({
89
+ items: t.items.map((listItem) => ({
90
+ tokens: listItem.tokens,
91
+ ...(listItem.task === undefined ? {} : { task: listItem.task }),
92
+ ...(listItem.checked === undefined ? {} : { checked: listItem.checked }),
93
+ })),
94
+ ordered: t.ordered,
95
+ ...(typeof t.start === 'number' ? { start: t.start } : {}),
96
+ });
97
+ } else if (isCodeToken(t)) {
98
+ const id = `__CODE_${Date.now()}_${Math.random().toString(RANDOM_ID_RADIX)}__`;
99
+ codeBlocks.set(id, { code: t.text, lang: t.lang ?? '' });
100
+ blockContent.push({ raw: id, text: id, type: 'html' } as Token);
101
+ } else if (t.type === 'paragraph' && 'tokens' in t) {
102
+ inlineTokens.push(...t.tokens);
103
+ } else if (t.type === 'space') {
104
+ // Whitespace between block content - skip
105
+ } else if (t.type === 'html' && 'block' in t && t.block === false) {
106
+ inlineTokens.push(t);
107
+ } else if (INLINE_TYPES.has(t.type)) {
108
+ inlineTokens.push(t);
109
+ } else {
110
+ blockContent.push(t);
111
+ }
112
+ }
113
+
114
+ return { blockContent, inlineTokens, nestedLists };
115
+ };
116
+
117
+ const renderListWithDepth = (
118
+ parser: RendererThis['parser'],
119
+ items: ListItemToken[],
120
+ ordered: boolean,
121
+ start: number,
122
+ depth: number,
123
+ ): string => {
124
+ return items
125
+ .map((item, i) => {
126
+ const { inlineTokens, nestedLists, blockContent } = classifyListItemTokens(item);
127
+
128
+ const text = parser.parseInline(inlineTokens);
129
+ const renderedItem = renderListItem(text, ordered, depth, start + i, {
130
+ width: options.width,
131
+ ...(item.checked === undefined ? {} : { checked: item.checked }),
132
+ ...(item.task === undefined ? {} : { task: item.task }),
133
+ ...(options.hyphenation === undefined ? {} : { hyphenation: options.hyphenation }),
134
+ ...(options.nerdFonts === undefined ? {} : { nerdFonts: options.nerdFonts }),
135
+ });
136
+
137
+ // Render any block content (tables, blockquotes, code blocks, etc.)
138
+ const blockRendered = blockContent.length > 0 ? parser.parse(blockContent).trim() : '';
139
+
140
+ // Recursively render nested lists
141
+ const nestedRendered = nestedLists
142
+ .map((nested) =>
143
+ renderListWithDepth(parser, nested.items, nested.ordered, nested.start ?? 1, depth + 1),
144
+ )
145
+ .join('\n');
146
+
147
+ // Join: item text, then block content, then nested lists
148
+ const parts = [renderedItem];
149
+ if (blockRendered) {
150
+ parts.push(blockRendered);
151
+ }
152
+ if (nestedRendered) {
153
+ parts.push(nestedRendered);
154
+ }
155
+ return parts.join('\n');
156
+ })
157
+ .join('\n');
158
+ };
159
+
160
+ return {
161
+ blockquote(this: RendererThis, { tokens }: { tokens: Token[] }): string {
162
+ // Blockquotes contain block-level tokens (paragraphs, lists, etc.), not inline
163
+ const text = this.parser.parse(tokens);
164
+ const blockquoteConfig: { width: number; hyphenation?: boolean } = { width: options.width };
165
+ if (options.hyphenation !== undefined) {
166
+ blockquoteConfig.hyphenation = options.hyphenation;
167
+ }
168
+ return `${renderBlockquote(text.trim(), blockquoteConfig)}\n\n`;
169
+ },
170
+ br(): string {
171
+ return '\n';
172
+ },
173
+
174
+ checkbox(): string {
175
+ // Return empty - we render checkboxes in renderListItem based on task/checked flags
176
+ return '';
177
+ },
178
+
179
+ code({ text, lang }: { text: string; lang?: string }): string {
180
+ const id = `__CODE_${Date.now()}_${Math.random().toString(RANDOM_ID_RADIX)}__`;
181
+ codeBlocks.set(id, { code: text, lang: lang ?? '' });
182
+ return id;
183
+ },
184
+
185
+ codespan({ text }: { text: string }): string {
186
+ return renderInlineCode(text);
187
+ },
188
+
189
+ em(this: RendererThis, { tokens }: { tokens: Token[] }): string {
190
+ const text = this.parser.parseInline(tokens);
191
+ return getItalicStyle()(text);
192
+ },
193
+
194
+ heading(this: RendererThis, { tokens, depth }: { tokens: Token[]; depth: number }): string {
195
+ const text = this.parser.parseInline(tokens);
196
+ return renderHeading(text, depth, options.width);
197
+ },
198
+
199
+ hr(): string {
200
+ return `\n${'─'.repeat(options.width)}\n\n`;
201
+ },
202
+
203
+ html({ text }: { text: string }): string {
204
+ if (/^<br\s*\/?>$/iu.test(text.trim())) {
205
+ return '\n';
206
+ }
207
+ return text;
208
+ },
209
+
210
+ link(this: RendererThis, { href, tokens }: { href: string; tokens: Token[] }): string {
211
+ const text = this.parser.parseInline(tokens);
212
+ return renderLink(text, href, { osc8: options.osc8 ?? 'auto', show_urls: false });
213
+ },
214
+
215
+ list(
216
+ this: RendererThis,
217
+ { items, ordered, start }: { items: ListItemToken[]; ordered: boolean; start: number | '' },
218
+ ): string {
219
+ return `${renderListWithDepth(this.parser, items, ordered, typeof start === 'number' ? start : 1, 0)}\n`;
220
+ },
221
+
222
+ listitem(this: RendererThis, { tokens }: { tokens: Token[] }): string {
223
+ return this.parser.parseInline(tokens);
224
+ },
225
+
226
+ paragraph(this: RendererThis, { tokens }: { tokens: Token[] }): string {
227
+ const text = this.parser.parseInline(tokens);
228
+ return `${renderText(text, { hyphenation: options.hyphenation ?? true, width: options.width })}\n`;
229
+ },
230
+
231
+ strong(this: RendererThis, { tokens }: { tokens: Token[] }): string {
232
+ const text = this.parser.parseInline(tokens);
233
+ return getBoldStyle()(text);
234
+ },
235
+
236
+ table({ header, rows }: { header: { text: string }[]; rows: { text: string }[][] }): string {
237
+ return `${renderTable(
238
+ header.map((h) => h.text),
239
+ rows.map((row) => row.map((c) => c.text)),
240
+ { width: options.width },
241
+ )}\n`;
242
+ },
243
+ };
244
+ };
245
+
246
+ // Decode HTML entities that marked escapes (we're outputting to terminal, not HTML)
247
+ const HTML_ENTITIES: Record<string, string> = {
248
+ '&#39;': "'",
249
+ '&amp;': '&',
250
+ '&gt;': '>',
251
+ '&lt;': '<',
252
+ '&quot;': '"',
253
+ };
254
+
255
+ const decodeHtmlEntities = (text: string): string =>
256
+ text.replaceAll(/&#?\w+;/gu, (entity) => HTML_ENTITIES[entity] ?? entity);
257
+
258
+ const parseMarkdown = Effect.fn('md.parse-markdown')(function* parseMarkdownGen(
259
+ markdown: string,
260
+ options: ParseOptions,
261
+ ) {
262
+ const codeBlocks = new Map<string, { code: string; lang: string }>();
263
+
264
+ const marked = new Marked();
265
+ marked.use({ renderer: createRenderer(options, codeBlocks) });
266
+
267
+ const parsed = marked.parse(markdown);
268
+ let result =
269
+ typeof parsed === 'string'
270
+ ? parsed
271
+ : yield* Effect.tryPromise({
272
+ catch: (cause) => new MarkdownParseError({ cause }),
273
+ try: () => parsed,
274
+ });
275
+
276
+ result = decodeHtmlEntities(result);
277
+
278
+ if (codeBlocks.size > 0) {
279
+ const codeConfig: CodeConfig = {
280
+ continuation: options.continuation ?? '→',
281
+ theme: theme().shikiTheme,
282
+ width: options.width,
283
+ wrap: options.wrap ?? true,
284
+ ...(options.nerdFonts === undefined ? {} : { useNerdFonts: options.nerdFonts }),
285
+ };
286
+
287
+ const refs = [...codeBlocks.entries()].map(([id, { code, lang }]) => ({ code, id, lang }));
288
+
289
+ const renderedById = yield* renderCodeBlocksParallel(refs, codeConfig, theme().shikiTheme);
290
+
291
+ for (const [id, rendered] of renderedById) {
292
+ result = result.replace(id, rendered);
293
+ }
294
+ }
295
+
296
+ return result;
297
+ });
298
+
299
+ export { createRenderer, MarkdownParseError, parseMarkdown };
@@ -0,0 +1,25 @@
1
+ import { Effect } from 'effect';
2
+
3
+ import { type CodeConfig, formatCodeBlockBox, highlightCodeBlockSource } from './elements/code';
4
+
5
+ /** Parallel Shiki passes for documents with many fences (claudewatch-style bounded concurrency). */
6
+ export const CODE_BLOCK_HIGHLIGHT_CONCURRENCY = 8;
7
+
8
+ export interface CodeBlockRef {
9
+ readonly id: string;
10
+ readonly code: string;
11
+ readonly lang: string;
12
+ }
13
+
14
+ export const renderCodeBlocksParallel = Effect.fn('md.render-code-blocks')(
15
+ (blocks: readonly CodeBlockRef[], config: CodeConfig, themeId: string) =>
16
+ Effect.forEach(
17
+ blocks,
18
+ (block) =>
19
+ Effect.gen(function* renderCodeBlockEntryGen() {
20
+ const highlighted = yield* highlightCodeBlockSource(block.code, block.lang, themeId);
21
+ return { id: block.id, rendered: formatCodeBlockBox(highlighted, block.lang, config) };
22
+ }),
23
+ { concurrency: CODE_BLOCK_HIGHLIGHT_CONCURRENCY },
24
+ ).pipe(Effect.map((items) => new Map(items.map((item) => [item.id, item.rendered] as const)))),
25
+ );
@@ -0,0 +1,37 @@
1
+ // Src/lib/render.ts
2
+
3
+ import { Effect } from 'effect';
4
+
5
+ import type { Config } from './config';
6
+ import { resolveNerdFonts } from './languages';
7
+ import { applyPadding, calculateLayout } from './layout';
8
+ import { parseMarkdown } from './parser';
9
+ import { getRawTerminalWidth, getTerminalWidth } from './width';
10
+
11
+ export const render = Effect.fn('md.render')(function* renderGen(markdown: string, config: Config) {
12
+ if (!markdown.trim()) {
13
+ return '';
14
+ }
15
+
16
+ const contentWidth =
17
+ config.width === 'auto' ? getTerminalWidth() : getTerminalWidth(config.width);
18
+
19
+ // Use raw terminal width for centering (not capped), but capped width for content
20
+ const rawTerminalWidth = getRawTerminalWidth();
21
+
22
+ const layout = calculateLayout(rawTerminalWidth, contentWidth, {
23
+ maxWidth: config.display.maxWidth,
24
+ padding: config.display.padding,
25
+ });
26
+
27
+ const content = yield* parseMarkdown(markdown, {
28
+ continuation: config.code.continuation,
29
+ hyphenation: config.text.hyphenation,
30
+ nerdFonts: resolveNerdFonts(config.nerd_fonts),
31
+ osc8: config.links.osc8,
32
+ width: layout.contentWidth,
33
+ wrap: config.code.wrap,
34
+ });
35
+
36
+ return applyPadding(content, layout.sidePadding);
37
+ });
@@ -0,0 +1,197 @@
1
+ /**
2
+ * Shiki ANSI highlighting — lazy module load, LRU cache, safe fallbacks.
3
+ * Patterns from claudewatch/src/render/shiki.ts.
4
+ */
5
+ import type { codeToANSI as CodeToANSI } from '@shikijs/cli';
6
+ import { Effect, Schema } from 'effect';
7
+ import type { BundledLanguage, BundledTheme } from 'shiki';
8
+
9
+ import { themes } from '../ui/themes/generated';
10
+ import { normalizeLang } from './languages';
11
+
12
+ const BYTES_PER_KIB = 1024;
13
+ const MAX_CODE_SIZE = 16 * BYTES_PER_KIB;
14
+ const MAX_HIGHLIGHT_CACHE_ENTRIES = 128;
15
+ const START_INDEX = 0;
16
+ const TRAILING_NEWLINE_OFFSET = -1;
17
+ const EMPTY_LENGTH = 0;
18
+ const ANSI_SGR_PREFIX = '\u001B[';
19
+ const ANSI_SGR_SUFFIX = 'm';
20
+ const ITALIC_ON = '3';
21
+ const ITALIC_OFF = '23';
22
+
23
+ const makeGlobalPattern = (source: string): RegExp => new RegExp(source, 'gu');
24
+ const ANSI_SGR_PATTERN = makeGlobalPattern(String.raw`\u001B\[([0-9;]*)m`);
25
+
26
+ interface ShikiModule {
27
+ codeToANSI: typeof CodeToANSI;
28
+ }
29
+
30
+ class ShikiHighlightError extends Schema.TaggedErrorClass<ShikiHighlightError>()(
31
+ 'ShikiHighlightError',
32
+ { cause: Schema.Unknown },
33
+ ) {}
34
+
35
+ /** Languages passed to Shiki's codeToANSI (superset of icon map keys). */
36
+ const SHIKI_SUPPORTED_LANGS = new Set<string>([
37
+ 'apache',
38
+ 'bash',
39
+ 'c',
40
+ 'clojure',
41
+ 'cmake',
42
+ 'cpp',
43
+ 'csharp',
44
+ 'css',
45
+ 'csv',
46
+ 'diff',
47
+ 'dockerfile',
48
+ 'elixir',
49
+ 'env',
50
+ 'erlang',
51
+ 'fsharp',
52
+ 'git-commit',
53
+ 'git-rebase',
54
+ 'go',
55
+ 'graphql',
56
+ 'haskell',
57
+ 'html',
58
+ 'http',
59
+ 'ini',
60
+ 'java',
61
+ 'javascript',
62
+ 'json',
63
+ 'jsonc',
64
+ 'jsonl',
65
+ 'julia',
66
+ 'kotlin',
67
+ 'latex',
68
+ 'less',
69
+ 'lisp',
70
+ 'lua',
71
+ 'makefile',
72
+ 'markdown',
73
+ 'matlab',
74
+ 'nginx',
75
+ 'nim',
76
+ 'ocaml',
77
+ 'perl',
78
+ 'php',
79
+ 'plsql',
80
+ 'powershell',
81
+ 'prisma',
82
+ 'python',
83
+ 'r',
84
+ 'regex',
85
+ 'ruby',
86
+ 'rust',
87
+ 'sass',
88
+ 'scala',
89
+ 'scheme',
90
+ 'scss',
91
+ 'shell',
92
+ 'sql',
93
+ 'svelte',
94
+ 'swift',
95
+ 'tex',
96
+ 'toml',
97
+ 'tsx',
98
+ 'typescript',
99
+ 'vim',
100
+ 'vue',
101
+ 'wasm',
102
+ 'xml',
103
+ 'yaml',
104
+ 'zig',
105
+ 'zsh',
106
+ 'fish',
107
+ 'jsx',
108
+ ]);
109
+
110
+ let cachedShiki: ShikiModule | null = null;
111
+ const highlightedCodeCache = new Map<string, string>();
112
+
113
+ const isBundledLanguage = (value: string): value is BundledLanguage =>
114
+ SHIKI_SUPPORTED_LANGS.has(value);
115
+ const isBundledTheme = (value: string): value is BundledTheme => value in themes;
116
+
117
+ const stripItalicAnsi = (code: string): string =>
118
+ code.replaceAll(ANSI_SGR_PATTERN, (_full, params: string) => {
119
+ const filtered = params
120
+ .split(';')
121
+ .filter((part) => part.length > EMPTY_LENGTH && part !== ITALIC_ON && part !== ITALIC_OFF);
122
+ if (filtered.length === EMPTY_LENGTH) {
123
+ return '';
124
+ }
125
+ return `${ANSI_SGR_PREFIX}${filtered.join(';')}${ANSI_SGR_SUFFIX}`;
126
+ });
127
+
128
+ const loadShiki = Effect.fn('md.load-shiki')(function* loadShikiGen() {
129
+ cachedShiki ??= yield* Effect.tryPromise({
130
+ catch: (cause) => new ShikiHighlightError({ cause }),
131
+ try: () => import('@shikijs/cli'),
132
+ });
133
+ return cachedShiki;
134
+ });
135
+
136
+ const makeHighlightCacheKey = (code: string, lang: string, themeId: string): string =>
137
+ `${themeId}\u0000${lang}\u0000${code}`;
138
+
139
+ const rememberHighlightedCode = (key: string, code: string): void => {
140
+ if (highlightedCodeCache.size >= MAX_HIGHLIGHT_CACHE_ENTRIES) {
141
+ const oldestKey = highlightedCodeCache.keys().next().value;
142
+ if (oldestKey !== undefined) {
143
+ highlightedCodeCache.delete(oldestKey);
144
+ }
145
+ }
146
+ highlightedCodeCache.set(key, code);
147
+ };
148
+
149
+ const clearHighlightCache = (): void => {
150
+ highlightedCodeCache.clear();
151
+ };
152
+
153
+ /**
154
+ * Highlight code using Shiki; returns plain code on unsupported lang/theme, size limit, or errors.
155
+ */
156
+ const highlightCode = Effect.fn('md.highlight-code')(function* highlightCodeEffect(
157
+ code: string,
158
+ lang: string,
159
+ themeId: string,
160
+ ) {
161
+ if (code.length > MAX_CODE_SIZE) {
162
+ return code;
163
+ }
164
+
165
+ const langId = normalizeLang(lang);
166
+ if (!isBundledLanguage(langId) || !isBundledTheme(themeId)) {
167
+ return code;
168
+ }
169
+
170
+ const cacheKey = makeHighlightCacheKey(code, langId, themeId);
171
+ const cached = highlightedCodeCache.get(cacheKey);
172
+ if (cached !== undefined) {
173
+ return cached;
174
+ }
175
+
176
+ return yield* Effect.gen(function* highlightCodeInner() {
177
+ const shiki = yield* loadShiki();
178
+ const highlighted = yield* Effect.tryPromise({
179
+ catch: (cause) => new ShikiHighlightError({ cause }),
180
+ try: () => shiki.codeToANSI(code, langId, themeId),
181
+ });
182
+ const normalized = highlighted.endsWith('\n')
183
+ ? highlighted.slice(START_INDEX, TRAILING_NEWLINE_OFFSET)
184
+ : highlighted;
185
+ const output = stripItalicAnsi(normalized);
186
+ rememberHighlightedCode(cacheKey, output);
187
+ return output;
188
+ }).pipe(Effect.catch(() => Effect.succeed(code)));
189
+ });
190
+
191
+ export {
192
+ clearHighlightCache,
193
+ highlightCode,
194
+ SHIKI_SUPPORTED_LANGS,
195
+ ShikiHighlightError,
196
+ stripItalicAnsi,
197
+ };
@@ -0,0 +1,21 @@
1
+ // Src/lib/width.ts
2
+ const MIN_WIDTH = 40;
3
+ const MAX_AUTO_WIDTH = 120;
4
+ const DEFAULT_WIDTH = 80;
5
+ const DEFAULT_TERMINAL_ROWS = 24;
6
+
7
+ export const getTerminalWidth = (override?: number): number => {
8
+ if (override !== undefined) {
9
+ return Math.max(MIN_WIDTH, override);
10
+ }
11
+
12
+ const detected = process.stdout.columns;
13
+ const columns = detected > 0 ? detected : DEFAULT_WIDTH;
14
+ return Math.max(MIN_WIDTH, Math.min(MAX_AUTO_WIDTH, columns));
15
+ };
16
+
17
+ export const getRawTerminalWidth = (): number =>
18
+ process.stdout.columns > 0 ? process.stdout.columns : DEFAULT_WIDTH;
19
+
20
+ export const getTerminalHeight = (): number =>
21
+ process.stdout.rows > 0 ? process.stdout.rows : DEFAULT_TERMINAL_ROWS;
package/src/paths.ts ADDED
@@ -0,0 +1,14 @@
1
+ import { join } from 'node:path';
2
+
3
+ import { CONFIG_DIR_NAME } from './constants';
4
+
5
+ export const expandHome = (pathStr: string): string =>
6
+ pathStr === '~' || pathStr.startsWith('~/')
7
+ ? `${process.env['HOME'] ?? ''}${pathStr.slice(1)}`
8
+ : pathStr;
9
+
10
+ export const configRoot = (): string =>
11
+ process.env['MD_CONFIG_HOME'] ??
12
+ `${process.env['XDG_CONFIG_HOME'] ?? `${process.env['HOME'] ?? '.'}/.config`}/${CONFIG_DIR_NAME}`;
13
+
14
+ export const configTomlPath = (): string => join(configRoot(), 'config.toml');
@@ -0,0 +1,23 @@
1
+ import gradient from 'gradient-string';
2
+
3
+ import { getGradientColors } from './themes/semantic';
4
+
5
+ // Create gradient lazily to pick up theme changes
6
+ const getBannerGradient = (): ReturnType<typeof gradient> =>
7
+ gradient([...getGradientColors().banner]);
8
+
9
+ /**
10
+ * Display the ASCII art banner with gradient colors
11
+ */
12
+ export const showBanner = (): void => {
13
+ const banner = `\n __
14
+ ____ ___ ____/ /
15
+ / __ \`__ \\/ __ /
16
+ / / / / / / /_/ /
17
+ /_/ /_/ /_/\\__,_/
18
+
19
+ `;
20
+
21
+ console.log(`\n${getBannerGradient()(banner)}`);
22
+ console.log();
23
+ };