@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,2 @@
1
+ // @bun
2
+ import{I as a}from"./cli-vt93z537.js";import"./cli-yjt0k8jp.js";import"./cli-vbncttvd.js";export{a as default};
@@ -0,0 +1,2 @@
1
+ // @bun
2
+ import{I as e}from"./cli-vt93z537.js";import"./cli-yjt0k8jp.js";import"./cli-vbncttvd.js";var n=Object.freeze(JSON.parse(`{"displayName":"XSL","name":"xsl","patterns":[{"begin":"(<)(xsl)((:))(template)","captures":{"1":{"name":"punctuation.definition.tag.xml"},"2":{"name":"entity.name.tag.namespace.xml"},"3":{"name":"entity.name.tag.xml"},"4":{"name":"punctuation.separator.namespace.xml"},"5":{"name":"entity.name.tag.localname.xml"}},"end":"(>)","name":"meta.tag.xml.template","patterns":[{"captures":{"1":{"name":"entity.other.attribute-name.namespace.xml"},"2":{"name":"entity.other.attribute-name.xml"},"3":{"name":"punctuation.separator.namespace.xml"},"4":{"name":"entity.other.attribute-name.localname.xml"}},"match":" (?:([-0-9A-Z_a-z]+)((:)))?([-A-Za-z]+)"},{"include":"#doublequotedString"},{"include":"#singlequotedString"}]},{"include":"text.xml"}],"repository":{"doublequotedString":{"begin":"\\"","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.xml"}},"end":"\\"","endCaptures":{"0":{"name":"punctuation.definition.string.end.xml"}},"name":"string.quoted.double.xml"},"singlequotedString":{"begin":"'","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.xml"}},"end":"'","endCaptures":{"0":{"name":"punctuation.definition.string.end.xml"}},"name":"string.quoted.single.xml"}},"scopeName":"text.xml.xsl","embeddedLangs":["xml"]}`)),a=[...e,n];export{a as default};
@@ -0,0 +1,2 @@
1
+ // @bun
2
+ import{q as a}from"./cli-5jp9npt1.js";import"./cli-vbncttvd.js";export{a as default};
@@ -0,0 +1,2 @@
1
+ // @bun
2
+ import"./cli-vbncttvd.js";var e=Object.freeze(JSON.parse('{"displayName":"ZenScript","fileTypes":["zs"],"name":"zenscript","patterns":[{"match":"\\\\b((0([Xx])\\\\h*)|(([0-9]+\\\\.?[0-9]*)|(\\\\.[0-9]+))(([Ee])([-+])?[0-9]+)?)([DFLUdflu]|UL|ul)?\\\\b","name":"constant.numeric.zenscript"},{"match":"\\\\b-?(0[BOXbox])(0|[1-9A-Fa-f][_\\\\h]*)[A-Z_a-z]*\\\\b","name":"constant.numeric.zenscript"},{"include":"#code"},{"match":"\\\\b((?:[a-z]\\\\w*\\\\.)*[A-Z]+\\\\w*)(?=\\\\[)","name":"storage.type.object.array.zenscript"}],"repository":{"brackets":{"patterns":[{"captures":{"1":{"name":"keyword.control.zenscript"},"2":{"name":"keyword.other.zenscript"},"3":{"name":"keyword.control.zenscript"},"4":{"name":"variable.other.zenscript"},"5":{"name":"keyword.control.zenscript"},"6":{"name":"constant.numeric.zenscript"},"7":{"name":"keyword.control.zenscript"}},"match":"(<)\\\\b(.*?)(:(.*?(:(\\\\*|\\\\d+)?)?)?)(>)","name":"keyword.other.zenscript"}]},"class":{"captures":{"1":{"name":"storage.type.zenscript"},"2":{"name":"entity.name.type.class.zenscript"}},"match":"(zenClass)\\\\s+(\\\\w+)","name":"meta.class.zenscript"},"code":{"patterns":[{"include":"#class"},{"include":"#functions"},{"include":"#dots"},{"include":"#quotes"},{"include":"#brackets"},{"include":"#comments"},{"include":"#var"},{"include":"#keywords"},{"include":"#constants"},{"include":"#operators"}]},"comments":{"patterns":[{"match":"//[^\\\\n]*","name":"comment.line.double=slash"},{"begin":"/\\\\*","beginCaptures":{"0":{"name":"comment.block"}},"end":"\\\\*/","endCaptures":{"0":{"name":"comment.block"}},"name":"comment.block"}]},"dots":{"captures":{"1":{"name":"storage.type.zenscript"},"2":{"name":"keyword.control.zenscript"},"5":{"name":"keyword.control.zenscript"}},"match":"\\\\b(\\\\w+)(\\\\.)(\\\\w+)((\\\\.)(\\\\w+))*","name":"plain.text.zenscript"},"functions":{"captures":{"0":{"name":"storage.type.function.zenscript"},"1":{"name":"entity.name.function.zenscript"}},"match":"function\\\\s+([$A-Z_a-z][$\\\\w]*)\\\\s*(?=\\\\()","name":"meta.function.zenscript"},"keywords":{"patterns":[{"match":"\\\\b(instanceof|get|implements|set|import|function|override|const|if|else|do|while|for|throw|panic|lock|try|catch|finally|return|break|continue|switch|case|default|in|is|as|match|throws|super|new)\\\\b","name":"keyword.control.zenscript"},{"match":"\\\\b(zenClass|zenConstructor|alias|class|interface|enum|struct|expand|variant|set|void|bool|byte|sbyte|short|ushort|int|uint|long|ulong|usize|float|double|char|string)\\\\b","name":"storage.type.zenscript"},{"match":"\\\\b(variant|abstract|final|private|public|export|internal|static|protected|implicit|virtual|extern|immutable)\\\\b","name":"storage.modifier.zenscript"},{"match":"\\\\b(Native|Precondition)\\\\b","name":"entity.other.attribute-name"},{"match":"\\\\b(null|true|false)\\\\b","name":"constant.language"}]},"operators":{"patterns":[{"match":"\\\\b(\\\\.\\\\.??|\\\\.\\\\.\\\\.|[+,]|\\\\+=|\\\\+\\\\+|-=??|--|~=??|\\\\*=??|/=??|%=??|\\\\|=??|\\\\|\\\\||&=??|&&|\\\\^=??|\\\\?\\\\.??|\\\\?\\\\?|<=??|<<=??|>=??|>>=??|>>>=??|=>?|===??|!=??|!==|[$`])\\\\b","name":"keyword.control"},{"match":"\\\\b([:;])\\\\b","name":"keyword.control"}]},"quotes":{"patterns":[{"begin":"\\"","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.zenscript"}},"end":"\\"","endCaptures":{"0":{"name":"punctuation.definition.string.end.zenscript"}},"name":"string.quoted.double.zenscript","patterns":[{"match":"\\\\\\\\.","name":"constant.character.escape.zenscript"}]},{"begin":"\'","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.zenscript"}},"end":"\'","endCaptures":{"0":{"name":"punctuation.definition.string.end.zenscript"}},"name":"string.quoted.single.zenscript","patterns":[{"match":"\\\\\\\\.","name":"constant.character.escape.zenscript"}]}]},"var":{"match":"\\\\b(va[lr])\\\\b","name":"storage.type"}},"scopeName":"source.zenscript"}')),t=[e];export{t as default};
@@ -0,0 +1,2 @@
1
+ // @bun
2
+ import"./cli-vbncttvd.js";var e=Object.freeze(JSON.parse('{"displayName":"Zig","fileTypes":["zig","zon"],"name":"zig","patterns":[{"include":"#comments"},{"include":"#strings"},{"include":"#keywords"},{"include":"#operators"},{"include":"#punctuation"},{"include":"#numbers"},{"include":"#support"},{"include":"#variables"}],"repository":{"commentContents":{"patterns":[{"match":"\\\\b(TODO|FIXME|XXX|NOTE)\\\\b:?","name":"keyword.todo.zig"}]},"comments":{"patterns":[{"begin":"//[!/](?=[^/])","end":"$","name":"comment.line.documentation.zig","patterns":[{"include":"#commentContents"}]},{"begin":"//","end":"$","name":"comment.line.double-slash.zig","patterns":[{"include":"#commentContents"}]}]},"keywords":{"patterns":[{"match":"\\\\binline\\\\b(?!\\\\s*\\\\bfn\\\\b)","name":"keyword.control.repeat.zig"},{"match":"\\\\b(while|for)\\\\b","name":"keyword.control.repeat.zig"},{"match":"\\\\b(extern|packed|export|pub|noalias|inline|comptime|volatile|align|linksection|threadlocal|allowzero|noinline|callconv)\\\\b","name":"keyword.storage.zig"},{"match":"\\\\b(struct|enum|union|opaque)\\\\b","name":"keyword.structure.zig"},{"match":"\\\\b(asm|unreachable)\\\\b","name":"keyword.statement.zig"},{"match":"\\\\b(break|return|continue|defer|errdefer)\\\\b","name":"keyword.control.flow.zig"},{"match":"\\\\b(resume|suspend|nosuspend)\\\\b","name":"keyword.control.async.zig"},{"match":"\\\\b(try|catch)\\\\b","name":"keyword.control.trycatch.zig"},{"match":"\\\\b(if|else|switch|orelse)\\\\b","name":"keyword.control.conditional.zig"},{"match":"\\\\b(null|undefined)\\\\b","name":"keyword.constant.default.zig"},{"match":"\\\\b(true|false)\\\\b","name":"keyword.constant.bool.zig"},{"match":"\\\\b(test|and|or)\\\\b","name":"keyword.default.zig"},{"match":"\\\\b(bool|void|noreturn|type|error|anyerror|anyframe|anytype|anyopaque)\\\\b","name":"keyword.type.zig"},{"match":"\\\\b(f16|f32|f64|f80|f128|u\\\\d+|i\\\\d+|isize|usize|comptime_int|comptime_float)\\\\b","name":"keyword.type.integer.zig"},{"match":"\\\\b(c_(?:char|short|ushort|int|uint|long|ulong|longlong|ulonglong|longdouble))\\\\b","name":"keyword.type.c.zig"}]},"numbers":{"patterns":[{"match":"\\\\b0x\\\\h[_\\\\h]*(\\\\.\\\\h[_\\\\h]*)?([Pp][-+]?[_\\\\h]+)?\\\\b","name":"constant.numeric.hexfloat.zig"},{"match":"\\\\b[0-9][0-9_]*(\\\\.[0-9][0-9_]*)?([Ee][-+]?[0-9_]+)?\\\\b","name":"constant.numeric.float.zig"},{"match":"\\\\b[0-9][0-9_]*\\\\b","name":"constant.numeric.decimal.zig"},{"match":"\\\\b0x[_\\\\h]+\\\\b","name":"constant.numeric.hexadecimal.zig"},{"match":"\\\\b0o[0-7_]+\\\\b","name":"constant.numeric.octal.zig"},{"match":"\\\\b0b[01_]+\\\\b","name":"constant.numeric.binary.zig"},{"match":"\\\\b[0-9](([EPep][-+])|[0-9A-Z_a-z])*(\\\\.(([EPep][-+])|[0-9A-Z_a-z])*)?([EPep][-+])?[0-9A-Z_a-z]*\\\\b","name":"constant.numeric.invalid.zig"}]},"operators":{"patterns":[{"match":"(?<=\\\\[)\\\\*c(?=])","name":"keyword.operator.c-pointer.zig"},{"match":"\\\\b((and|or))\\\\b|(==|!=|<=|>=|[<>])","name":"keyword.operator.comparison.zig"},{"match":"(-%?|\\\\+%?|\\\\*%?|[%/])=?","name":"keyword.operator.arithmetic.zig"},{"match":"(<<%?|>>|[!\\\\&^|~])=?","name":"keyword.operator.bitwise.zig"},{"match":"(==|\\\\+\\\\+|\\\\*\\\\*|->)","name":"keyword.operator.special.zig"},{"match":"=","name":"keyword.operator.assignment.zig"},{"match":"\\\\?","name":"keyword.operator.question.zig"}]},"punctuation":{"patterns":[{"match":"\\\\.","name":"punctuation.accessor.zig"},{"match":",","name":"punctuation.comma.zig"},{"match":":","name":"punctuation.separator.key-value.zig"},{"match":";","name":"punctuation.terminator.statement.zig"}]},"stringcontent":{"patterns":[{"match":"\\\\\\\\([\\"\'\\\\\\\\nrt]|(x\\\\h{2})|(u\\\\{\\\\h+}))","name":"constant.character.escape.zig"},{"match":"\\\\\\\\.","name":"invalid.illegal.unrecognized-string-escape.zig"}]},"strings":{"patterns":[{"begin":"\\"","end":"\\"","name":"string.quoted.double.zig","patterns":[{"include":"#stringcontent"}]},{"begin":"\\\\\\\\\\\\\\\\","end":"$","name":"string.multiline.zig"},{"match":"\'([^\'\\\\\\\\]|\\\\\\\\(x\\\\h{2}|[012][0-7]{0,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.))\'","name":"string.quoted.single.zig"}]},"support":{"patterns":[{"match":"@[A-Z_a-z][0-9A-Z_a-z]*","name":"support.function.builtin.zig"}]},"variables":{"patterns":[{"name":"meta.function.declaration.zig","patterns":[{"captures":{"1":{"name":"storage.type.function.zig"},"2":{"name":"entity.name.type.zig"}},"match":"\\\\b(fn)\\\\s+([A-Z][0-9A-Za-z]*)\\\\b"},{"captures":{"1":{"name":"storage.type.function.zig"},"2":{"name":"entity.name.function.zig"}},"match":"\\\\b(fn)\\\\s+([A-Z_a-z][0-9A-Z_a-z]*)\\\\b"},{"begin":"\\\\b(fn)\\\\s+@\\"","beginCaptures":{"1":{"name":"storage.type.function.zig"}},"end":"\\"","name":"entity.name.function.string.zig","patterns":[{"include":"#stringcontent"}]},{"match":"\\\\b(const|var|fn)\\\\b","name":"keyword.default.zig"}]},{"name":"meta.function.call.zig","patterns":[{"match":"([A-Z][0-9A-Za-z]*)(?=\\\\s*\\\\()","name":"entity.name.type.zig"},{"match":"([A-Z_a-z][0-9A-Z_a-z]*)(?=\\\\s*\\\\()","name":"entity.name.function.zig"}]},{"name":"meta.variable.zig","patterns":[{"match":"\\\\b[A-Z_a-z][0-9A-Z_a-z]*\\\\b","name":"variable.zig"},{"begin":"@\\"","end":"\\"","name":"variable.string.zig","patterns":[{"include":"#stringcontent"}]}]}]}},"scopeName":"source.zig"}')),n=[e];export{n as default};
package/package.json CHANGED
@@ -1,50 +1,78 @@
1
1
  {
2
2
  "name": "@seanmozeik/markdown-display",
3
- "version": "0.3.5",
3
+ "version": "0.4.0",
4
4
  "description": "Beautiful terminal markdown viewer",
5
- "module": "src/index.ts",
6
- "type": "module",
5
+ "keywords": [
6
+ "bun",
7
+ "cli",
8
+ "effect",
9
+ "markdown",
10
+ "terminal"
11
+ ],
12
+ "license": "MIT",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/seanmozeik/markdown-display.git"
16
+ },
7
17
  "bin": {
8
- "md": "dist/index.js"
18
+ "md": "./dist/md.js"
9
19
  },
10
20
  "files": [
11
- "dist/index.js"
21
+ "dist",
22
+ "src"
12
23
  ],
24
+ "type": "module",
25
+ "main": "./src/index.ts",
26
+ "types": "./src/index.ts",
27
+ "exports": {
28
+ ".": "./src/index.ts"
29
+ },
13
30
  "publishConfig": {
14
31
  "access": "public"
15
32
  },
16
33
  "scripts": {
34
+ "build": "bun scripts/build.ts",
35
+ "build:release": "bun scripts/build.ts -- --release",
36
+ "build:themes": "bun scripts/build-themes.ts",
37
+ "check": "bun run format && bun run lint:fix && bun run typecheck",
38
+ "dev": "bun run src/cli.ts",
39
+ "prepublishOnly": "bun run build",
17
40
  "test": "bun test",
18
- "dev": "bun run src/index.ts",
19
- "build": "bun build ./src/index.ts --compile --outfile md --minify",
20
- "bundle": "bun build ./src/index.ts --outfile dist/index.js --target=bun --minify",
21
- "lint": "biome lint src/",
22
- "format": "biome format --write src/",
23
- "check": "biome check --write --unsafe src/",
24
- "tc": "tsc --noEmit"
41
+ "tc": "tsc --noEmit",
42
+ "typecheck": "tsc --noEmit",
43
+ "format": "oxfmt --write .",
44
+ "lint": "oxlint --format agent --tsconfig tsconfig.oxlint.json ./src ./tests ./scripts",
45
+ "lint:fix": "oxlint --format agent --tsconfig tsconfig.oxlint.json --fix ./src ./tests ./scripts",
46
+ "prepare": "effect-language-service patch"
25
47
  },
26
48
  "dependencies": {
27
- "@clack/prompts": "1.0.1",
28
- "@shikijs/cli": "^3.23.0",
49
+ "@clack/prompts": "1.4.0",
50
+ "@effect/platform-bun": "^4.0.0-beta.66",
51
+ "@shikijs/cli": "^4.0.2",
29
52
  "boxen": "^8.0.1",
30
53
  "console-table-printer": "^2.15.0",
54
+ "effect": "^4.0.0-beta.66",
31
55
  "fuzzysort": "^3.1.0",
32
56
  "gradient-string": "^3.0.0",
33
57
  "hyphen": "^1.14.1",
34
- "marked": "^17.0.3",
35
- "picocolors": "^1.1.1",
36
- "shiki": "^3.23.0",
37
- "supports-color": "^10.2.2"
58
+ "marked": "^17.0.6",
59
+ "shiki": "^4.0.2",
60
+ "supports-color": "^10.2.2",
61
+ "typescript": "^6.0.3"
38
62
  },
39
63
  "devDependencies": {
40
- "@biomejs/biome": "^2.4.4",
41
- "@types/bun": "1.3.9",
64
+ "@effect/language-service": "^0.86.1",
42
65
  "@types/gradient-string": "^1.1.6",
43
66
  "@types/hyphen": "^1.14.0",
44
- "typescript": "^5.9.3"
67
+ "bun-types": "1.3.14",
68
+ "oxfmt": "^0.51.0",
69
+ "oxlint": "^1.65.0",
70
+ "oxlint-tsgolint": "^0.23.0"
45
71
  },
46
72
  "peerDependencies": {
47
- "typescript": "^5"
73
+ "typescript": "^5.9.3"
48
74
  },
49
- "license": "MIT"
75
+ "engines": {
76
+ "bun": ">=1.3.0"
77
+ }
50
78
  }
@@ -0,0 +1,90 @@
1
+ import boxen from 'boxen';
2
+ import { Effect, Schema } from 'effect';
3
+
4
+ import { loadUserConfig } from '../config';
5
+ import { loadTheme } from '../ui/themes';
6
+ import { setColorConfig } from '../ui/themes/color-support';
7
+ import {
8
+ getAccentColor,
9
+ getHeadingColor,
10
+ getHexColors,
11
+ getMutedColor,
12
+ getSuccessColor,
13
+ } from '../ui/themes/semantic';
14
+
15
+ class BannerImportError extends Schema.TaggedErrorClass<BannerImportError>()('BannerImportError', {
16
+ cause: Schema.Unknown,
17
+ }) {}
18
+
19
+ const loadBanner = Effect.fn('md.loadBanner')(function* loadBannerGen() {
20
+ return yield* Effect.tryPromise({
21
+ catch: (cause) => new BannerImportError({ cause }),
22
+ try: () => import('../ui/banner'),
23
+ });
24
+ });
25
+
26
+ const prepareThemedCli = Effect.fn('md.prepareThemedCli')(function* prepareThemedCliGen() {
27
+ const config = yield* loadUserConfig();
28
+ yield* Effect.sync(() => {
29
+ setColorConfig(config.truecolor);
30
+ loadTheme(config.theme);
31
+ });
32
+ });
33
+
34
+ export const showVersion = Effect.fn('md.showVersion')((version: string) =>
35
+ Effect.gen(function* showVersionGen() {
36
+ yield* prepareThemedCli();
37
+ const { showBanner } = yield* loadBanner();
38
+ yield* Effect.sync(() => {
39
+ showBanner();
40
+ });
41
+ const colors = getHexColors();
42
+ console.log(
43
+ boxen(getMutedColor()(`v${version}`), {
44
+ borderColor: colors.accent,
45
+ borderStyle: 'round',
46
+ padding: { bottom: 0, left: 2, right: 2, top: 0 },
47
+ }),
48
+ );
49
+ }),
50
+ );
51
+
52
+ export const showHelp = Effect.fn('md.showHelp')((version: string) =>
53
+ Effect.gen(function* showHelpGen() {
54
+ yield* prepareThemedCli();
55
+ const { showBanner } = yield* loadBanner();
56
+ yield* Effect.sync(() => {
57
+ showBanner();
58
+ });
59
+ console.log(getMutedColor()(`v${version}`));
60
+ console.log();
61
+
62
+ const h = getHeadingColor(1);
63
+ const accent = getAccentColor();
64
+ const opt = getSuccessColor();
65
+ const colors = getHexColors();
66
+ const dim = getMutedColor();
67
+ const helpText = `${h('Usage:')}
68
+ ${accent('md')} ${dim('[file...]')} ${dim('[options]')}
69
+
70
+ ${h('Options:')}
71
+ ${opt('-h, --help')} Show this help message
72
+ ${opt('-v, --version')} Show version number
73
+ ${opt('-w, --width <n>')} Set output width (default: auto)
74
+ ${opt('-t, --theme <name>')} Color theme (e.g., nord, dracula)
75
+ ${opt('--list-themes')} List all available themes
76
+ ${opt('-p, --plain')} No colors, just structure
77
+ ${opt('-r, --raw')} Pass through without rendering
78
+ ${opt('--no-pager')} Write directly, never use pager
79
+ ${opt('--scroll')} Horizontal scroll for code blocks
80
+ ${opt('--wrap')} Wrap code blocks (default)
81
+
82
+ ${h('Examples:')}
83
+ ${dim('$')} md README.md
84
+ ${dim('$')} md README.md CHANGELOG.md
85
+ ${dim('$')} md docs/guide.md --width 80
86
+ ${dim('$')} cat file.md | md`;
87
+
88
+ console.log(boxen(helpText, { borderColor: colors.accent, borderStyle: 'round', padding: 1 }));
89
+ }),
90
+ );
@@ -0,0 +1,19 @@
1
+ import type { ConfigParseError } from '../config/errors';
2
+ import type { ConfigReadError } from '../config/read-error';
3
+ import type { FileNotFoundError } from './file-not-found-error';
4
+ import type { InvalidThemeError } from './invalid-theme-error';
5
+ import type { PagerError } from './pager-error';
6
+ import type { StdinReadError } from './stdin-read-error';
7
+
8
+ export type MdAppError =
9
+ | ConfigParseError
10
+ | ConfigReadError
11
+ | FileNotFoundError
12
+ | InvalidThemeError
13
+ | PagerError
14
+ | StdinReadError;
15
+
16
+ export { FileNotFoundError } from './file-not-found-error';
17
+ export { InvalidThemeError } from './invalid-theme-error';
18
+ export { PagerError } from './pager-error';
19
+ export { StdinReadError } from './stdin-read-error';
@@ -0,0 +1,6 @@
1
+ import { Schema } from 'effect';
2
+
3
+ export class FileNotFoundError extends Schema.TaggedErrorClass<FileNotFoundError>()(
4
+ 'FileNotFoundError',
5
+ { path: Schema.String },
6
+ ) {}
@@ -0,0 +1,35 @@
1
+ import { Match } from 'effect';
2
+
3
+ import { ConfigParseError } from '../config/errors';
4
+ import { ConfigReadError } from '../config/read-error';
5
+ import { getErrorColor } from '../ui/themes/semantic';
6
+ import type { MdAppError } from './errors';
7
+ import { FileNotFoundError } from './file-not-found-error';
8
+ import { InvalidThemeError } from './invalid-theme-error';
9
+ import { PagerError } from './pager-error';
10
+ import { StdinReadError } from './stdin-read-error';
11
+
12
+ const formatMdAppError = (error: MdAppError): string =>
13
+ Match.value(error).pipe(
14
+ Match.tagsExhaustive({
15
+ ConfigParseError: (e: ConfigParseError) =>
16
+ getErrorColor()(`Config parse error (${e.path}): ${String(e.cause)}`),
17
+ ConfigReadError: (e: ConfigReadError) =>
18
+ getErrorColor()(`Config read error (${e.path}): ${String(e.cause)}`),
19
+ FileNotFoundError: (e) => getErrorColor()(`Error: File not found: ${e.path}`),
20
+ InvalidThemeError: (e) =>
21
+ getErrorColor()(`Invalid theme: ${e.theme}\nUse --list-themes to see available themes.`),
22
+ PagerError: (e) => getErrorColor()(`Pager error: ${String(e.cause)}`),
23
+ StdinReadError: (e) => getErrorColor()(`Read error: ${String(e.cause)}`),
24
+ }),
25
+ );
26
+
27
+ const isMdAppError = (error: unknown): error is MdAppError =>
28
+ error instanceof ConfigParseError ||
29
+ error instanceof ConfigReadError ||
30
+ error instanceof FileNotFoundError ||
31
+ error instanceof InvalidThemeError ||
32
+ error instanceof PagerError ||
33
+ error instanceof StdinReadError;
34
+
35
+ export { formatMdAppError, isMdAppError };
@@ -0,0 +1,6 @@
1
+ import { Schema } from 'effect';
2
+
3
+ export class InvalidThemeError extends Schema.TaggedErrorClass<InvalidThemeError>()(
4
+ 'InvalidThemeError',
5
+ { theme: Schema.String },
6
+ ) {}
@@ -0,0 +1,5 @@
1
+ import { Schema } from 'effect';
2
+
3
+ export class PagerError extends Schema.TaggedErrorClass<PagerError>()('PagerError', {
4
+ cause: Schema.Unknown,
5
+ }) {}
@@ -0,0 +1,197 @@
1
+ import { Effect } from 'effect';
2
+
3
+ import { type MdConfig, loadUserConfig } from '../config';
4
+ import { stripAnsi } from '../lib/ansi';
5
+ import { calculateLayout } from '../lib/layout';
6
+ import { countLines, PagingMode, pipeToLess, shouldUseColor, shouldUsePager } from '../lib/pager';
7
+ import { render } from '../lib/render';
8
+ import { getRawTerminalWidth, getTerminalHeight, getTerminalWidth } from '../lib/width';
9
+ import { showFilePicker } from '../ui/picker';
10
+ import { availableThemes, isValidTheme, loadTheme } from '../ui/themes';
11
+ import { setColorConfig } from '../ui/themes/color-support';
12
+ import { getSubtleColor } from '../ui/themes/semantic';
13
+ import { FileNotFoundError, InvalidThemeError, PagerError, StdinReadError } from './errors';
14
+
15
+ interface MdCliOptions {
16
+ readonly files: readonly string[];
17
+ readonly listThemes: boolean;
18
+ readonly noColor: boolean;
19
+ readonly noPager: boolean;
20
+ readonly plain: boolean;
21
+ readonly raw: boolean;
22
+ readonly scroll: boolean;
23
+ readonly theme: string | undefined;
24
+ readonly width: string | undefined;
25
+ readonly wrap: boolean;
26
+ }
27
+
28
+ const readStdin = Effect.fn('md.readStdin')(function* readStdinGen() {
29
+ return yield* Effect.tryPromise({
30
+ catch: (cause) => new StdinReadError({ cause }),
31
+ try: () => Bun.stdin.text(),
32
+ });
33
+ });
34
+
35
+ const readFile = Effect.fn('md.readFile')(function* readFileGen(filePath: string) {
36
+ const file = Bun.file(filePath);
37
+ const exists = yield* Effect.tryPromise({
38
+ catch: () => new FileNotFoundError({ path: filePath }),
39
+ try: () => file.exists(),
40
+ });
41
+ if (!exists) {
42
+ return yield* new FileNotFoundError({ path: filePath });
43
+ }
44
+ const content = yield* Effect.tryPromise({
45
+ catch: () => new FileNotFoundError({ path: filePath }),
46
+ try: () => file.text(),
47
+ });
48
+ return { content, path: filePath };
49
+ });
50
+
51
+ const renderFileHeader = (filePath: string, layout: ReturnType<typeof calculateLayout>): string => {
52
+ const label = ` ${filePath} `;
53
+ const leftPad = 3;
54
+ const rightLen = Math.max(0, layout.contentWidth - leftPad - label.length);
55
+ const header = getSubtleColor()(`${'─'.repeat(leftPad)}${label}${'─'.repeat(rightLen)}`);
56
+ return layout.sidePadding > 0 ? ' '.repeat(layout.sidePadding) + header : header;
57
+ };
58
+
59
+ const applyCliOverrides = (config: MdConfig, flags: MdCliOptions): MdConfig => {
60
+ const next = { ...config, code: { ...config.code }, display: { ...config.display } };
61
+ if (flags.width !== undefined) {
62
+ next.width = Number.parseInt(flags.width, 10);
63
+ next.display = { ...next.display, maxWidth: 0 };
64
+ }
65
+ if (flags.scroll) {
66
+ next.code = { ...next.code, wrap: false };
67
+ }
68
+ if (flags.wrap) {
69
+ next.code = { ...next.code, wrap: true };
70
+ }
71
+ return next;
72
+ };
73
+
74
+ const listThemes = Effect.fn('md.listThemes')(function* listThemesGen() {
75
+ yield* Effect.sync(() => {
76
+ console.log('Available themes:\n');
77
+ for (const id of availableThemes()) {
78
+ console.log(` ${id}`);
79
+ }
80
+ });
81
+ });
82
+
83
+ const readFiles = Effect.fn('md.readFiles')((filePaths: readonly string[]) =>
84
+ Effect.forEach(filePaths, readFile, { concurrency: 8 }),
85
+ );
86
+
87
+ const renderFiles = Effect.fn('md.renderFiles')(
88
+ (
89
+ files: readonly { path: string; content: string }[],
90
+ config: MdConfig,
91
+ layout: ReturnType<typeof calculateLayout>,
92
+ ) =>
93
+ Effect.forEach(
94
+ files,
95
+ (file) =>
96
+ render(file.content, config).pipe(
97
+ Effect.map((rendered) =>
98
+ files.length > 1 ? `${renderFileHeader(file.path, layout)}\n\n${rendered}` : rendered,
99
+ ),
100
+ ),
101
+ { concurrency: 4 },
102
+ ),
103
+ );
104
+
105
+ export const runMd = Effect.fn('md.run')((flags: MdCliOptions) =>
106
+ Effect.gen(function* runMdGen() {
107
+ const config = yield* loadUserConfig();
108
+ yield* Effect.sync(() => {
109
+ setColorConfig(config.truecolor);
110
+ });
111
+
112
+ if (flags.listThemes) {
113
+ yield* listThemes();
114
+ return;
115
+ }
116
+
117
+ const themeName = flags.theme ?? config.theme;
118
+ yield* flags.theme !== undefined && !isValidTheme(flags.theme)
119
+ ? Effect.fail(new InvalidThemeError({ theme: flags.theme }))
120
+ : Effect.sync(() => {
121
+ loadTheme(themeName);
122
+ });
123
+
124
+ let filePaths = [...flags.files];
125
+ const hasStdin = !process.stdin.isTTY;
126
+ const stdoutTTY = process.stdout.isTTY;
127
+ const stdinTTY = process.stdin.isTTY;
128
+
129
+ if (filePaths.length === 0 && !hasStdin) {
130
+ const { showBanner } = yield* Effect.tryPromise({
131
+ catch: (cause) => new StdinReadError({ cause }),
132
+ try: () => import('../ui/banner'),
133
+ });
134
+ yield* Effect.sync(() => {
135
+ showBanner();
136
+ });
137
+ const selected = yield* showFilePicker().pipe(
138
+ Effect.mapError((cause) => new StdinReadError({ cause })),
139
+ );
140
+ if (selected.length === 0) {
141
+ return;
142
+ }
143
+ filePaths = [...selected];
144
+ }
145
+
146
+ const files: { path: string; content: string }[] =
147
+ filePaths.length > 0
148
+ ? yield* readFiles(filePaths)
149
+ : [{ content: yield* readStdin(), path: '' }];
150
+
151
+ if (flags.raw) {
152
+ yield* Effect.sync(() => {
153
+ console.log(files.map((f) => f.content).join('\n'));
154
+ });
155
+ return;
156
+ }
157
+
158
+ const resolvedConfig = applyCliOverrides(config, flags);
159
+
160
+ const outputWidth: number =
161
+ resolvedConfig.width === 'auto' ? getTerminalWidth() : resolvedConfig.width;
162
+ const rawTerminalWidth = getRawTerminalWidth();
163
+ const layout = calculateLayout(rawTerminalWidth, outputWidth, {
164
+ maxWidth: resolvedConfig.display.maxWidth,
165
+ padding: resolvedConfig.display.padding,
166
+ });
167
+
168
+ const outputs = yield* renderFiles(files, resolvedConfig, layout);
169
+ let output = outputs.join('\n\n');
170
+
171
+ const useColor = shouldUseColor() && !flags.plain && !flags.noColor;
172
+ if (!useColor) {
173
+ output = stripAnsi(output);
174
+ }
175
+
176
+ const lines = countLines(output, outputWidth);
177
+ const height = getTerminalHeight();
178
+
179
+ const pagingMode = shouldUsePager({
180
+ height,
181
+ lines,
182
+ noPager: flags.noPager,
183
+ stdinTTY,
184
+ stdoutTTY,
185
+ });
186
+
187
+ yield* pagingMode === PagingMode.Never
188
+ ? Effect.sync(() => {
189
+ console.log(output);
190
+ })
191
+ : pipeToLess(output, resolvedConfig.pager).pipe(
192
+ Effect.mapError((cause) => new PagerError({ cause })),
193
+ );
194
+ }),
195
+ );
196
+
197
+ export type { MdCliOptions };
@@ -0,0 +1,5 @@
1
+ import { Schema } from 'effect';
2
+
3
+ export class StdinReadError extends Schema.TaggedErrorClass<StdinReadError>()('StdinReadError', {
4
+ cause: Schema.Unknown,
5
+ }) {}
@@ -0,0 +1,20 @@
1
+ import type { Option } from 'effect';
2
+ import { Flag } from 'effect/unstable/cli';
3
+
4
+ const describe = <A>(flag: Flag.Flag<A>, description: string): Flag.Flag<A> =>
5
+ flag.pipe(Flag.withDescription(description));
6
+
7
+ const optionalString = (name: string, description: string): Flag.Flag<Option.Option<string>> =>
8
+ describe(Flag.string(name).pipe(Flag.optional), description);
9
+
10
+ export const mdCliOptions = {
11
+ listThemes: describe(Flag.boolean('list-themes'), 'List all available themes and exit'),
12
+ noColor: describe(Flag.boolean('no-color'), 'Disable color output'),
13
+ noPager: describe(Flag.boolean('no-pager'), 'Write directly, never use pager'),
14
+ plain: describe(Flag.boolean('plain').pipe(Flag.withAlias('p')), 'No colors, just structure'),
15
+ raw: describe(Flag.boolean('raw').pipe(Flag.withAlias('r')), 'Pass through without rendering'),
16
+ scroll: describe(Flag.boolean('scroll'), 'Horizontal scroll for code blocks'),
17
+ theme: optionalString('theme', 'Color theme (e.g. nord, dracula)').pipe(Flag.withAlias('t')),
18
+ width: optionalString('width', 'Set output width').pipe(Flag.withAlias('w')),
19
+ wrap: describe(Flag.boolean('wrap'), 'Wrap code blocks (default)'),
20
+ };
package/src/cli-app.ts ADDED
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env bun
2
+ /* eslint-disable no-console */
3
+ import { BunRuntime, BunServices } from '@effect/platform-bun';
4
+ import { Cause, Effect, Layer, Logger, type LogLevel, Option, References } from 'effect';
5
+ import { Argument, Command } from 'effect/unstable/cli';
6
+
7
+ import pkg from '../package.json' with { type: 'json' };
8
+ import { showHelp, showVersion } from './app/cli-info';
9
+ import { formatMdAppError, isMdAppError } from './app/format-error';
10
+ import { runMd } from './app/run-md';
11
+ import { mdCliOptions } from './cli/options';
12
+ import { getErrorColor } from './ui/themes/semantic';
13
+
14
+ const filesArg = Argument.string('file').pipe(
15
+ Argument.variadic(),
16
+ Argument.withDescription('Markdown files to render'),
17
+ );
18
+
19
+ const md = Command.make('md', { files: filesArg, ...mdCliOptions }, (options) =>
20
+ runMd({
21
+ files: options.files,
22
+ listThemes: options.listThemes,
23
+ noColor: options.noColor,
24
+ noPager: options.noPager,
25
+ plain: options.plain,
26
+ raw: options.raw,
27
+ scroll: options.scroll,
28
+ theme: Option.getOrUndefined(options.theme),
29
+ width: Option.getOrUndefined(options.width),
30
+ wrap: options.wrap,
31
+ }),
32
+ ).pipe(Command.withDescription('Beautiful terminal markdown viewer'));
33
+
34
+ const program = Command.run(md, { version: pkg.version });
35
+
36
+ const stderrLogger = Logger.make(({ logLevel, message }) => {
37
+ let text: string;
38
+ if (Array.isArray(message)) {
39
+ text = message.map((m) => (typeof m === 'string' ? m : JSON.stringify(m))).join(' ');
40
+ } else if (typeof message === 'string') {
41
+ text = message;
42
+ } else {
43
+ text = JSON.stringify(message);
44
+ }
45
+ process.stderr.write(`[${logLevel.toLowerCase()}] ${text}\n`);
46
+ });
47
+
48
+ const verbose = process.argv.includes('--verbose');
49
+ const minLogLevel: LogLevel.LogLevel = verbose ? 'Debug' : 'Warn';
50
+
51
+ const runtimeLayer = Layer.mergeAll(
52
+ BunServices.layer,
53
+ Logger.layer([stderrLogger]),
54
+ Layer.succeed(References.MinimumLogLevel, minLogLevel),
55
+ );
56
+
57
+ const formatUnknownError = (error: unknown): string => {
58
+ if (error instanceof Error) {
59
+ return error.message;
60
+ }
61
+ if (typeof error === 'string') {
62
+ return error;
63
+ }
64
+ return String(error);
65
+ };
66
+
67
+ const writeBoundaryError = (error: unknown): void => {
68
+ if (isMdAppError(error)) {
69
+ console.error(formatMdAppError(error));
70
+ process.exitCode = 1;
71
+ return;
72
+ }
73
+
74
+ console.error(getErrorColor()(formatUnknownError(error)));
75
+ process.exitCode = 1;
76
+ };
77
+
78
+ const wantsVersion = (): boolean =>
79
+ process.argv.includes('--version') || process.argv.includes('-v');
80
+
81
+ const wantsHelp = (): boolean => process.argv.includes('--help') || process.argv.includes('-h');
82
+
83
+ const runnableProgram = Effect.gen(function* cliMain() {
84
+ if (wantsVersion()) {
85
+ yield* showVersion(pkg.version);
86
+ return;
87
+ }
88
+ if (wantsHelp()) {
89
+ yield* showHelp(pkg.version);
90
+ return;
91
+ }
92
+ yield* program;
93
+ }).pipe(
94
+ Effect.provide(runtimeLayer),
95
+ Effect.catchCause((cause) =>
96
+ Effect.sync(() => {
97
+ const fail = cause.reasons.find(Cause.isFailReason);
98
+ writeBoundaryError(fail === undefined ? cause : fail.error);
99
+ }),
100
+ ),
101
+ );
102
+
103
+ const runCliApp = (): void => {
104
+ BunRuntime.runMain(runnableProgram);
105
+ };
106
+
107
+ if (import.meta.main) {
108
+ runCliApp();
109
+ }
110
+
111
+ const app = md;
112
+
113
+ export { app, md, program, runnableProgram, runCliApp, runtimeLayer };