This page is generated using both sed(1)
and ml1
MCSKIP # NL
The above line defines the comment syntax that ML/I would ignore, so the inline markups would be rendered to HTML text shown in this page.
ML/I can freely choose what combination of delimiters to ignore. This gives opportunity for a literate programming example.
Since sed uses #
, we choose the same syntax
to reused the same solution for ML/I and sed comments.
For arbitrary reason I choose the <![ML1[text]]>
syntax to macro delimiter.
The only requirement would be not conflict with commonly used HTML syntax.
MCSKIP MT, < WITH ! WITH [ ML1 WITH [ ] WITH ] WITH > MCINS \ .
After the standard setup, first is the MCFOR
macro,
which is taken from from ML/I documentation with little
modification
MCDEF MCFOR = OPT STEP N1 OR N1 TO ALL NL REPEAT AS <![ML1[MCSET \A1. = \A2. MCSET T3 = 1 MCGO L1 IF T1 EN 4 MCSET T3 = \A3. MCGO L1 IF T3 GR 0 \L2.MCGO L0 IF \AT1-1. GR \A1. \AT1.MCSET \A1. = \A1. + T3 MCGO L2 \L1.MCGO L0 IF \A1. GR \AT1-1. \AT1.MCSET \A1. = \A1. + T3 MCGO L1 ]]>
Now we define several macros used to maintain a site news file.
Although it looks silly, there is potential that the news list item macro need a different definition in the future.
# News item counter MCSET P9 = 0 # News entry, each increases the counter by 1. MCDEF @ WITH { AS <![ML1[MCSET P9 = P9 + 1 <p>]]> MCDEF @ WITH } AS </p>
A helper macro to define audio element.
AUDELM{filename}
is the standard call,
AUDELM+{filename}
in addition shows a filename
that has the URL.
MCDEF AUDELM { } AS <![ML1[MCDEF FILE AS \A2. MCGO L1 UNLESS \A1. = + <p><a href="/audio/FILE">FILE</a></p> \L1.<div class="player"><audio preload="none"> <source src="/audio/FILE" type="audio/mpeg"> <p>Sad! Your browser does not support the <code>audio</code> element. <br> But you can download the file MCGO L2 IF \A1. = + FILE <a href="/audio/FILE">here</a>.MCGO L3 \L2.use the link above.\L3.</p> </audio></div>]]>
The idea here is I want to have a dictated page to list all the audio files in the news.
# counter for audio files MCSET P10 = 0 # macro for audio player # each entry is recorded for later use MCDEF @ WITH aud WITH { } AS <![ML1[MCSTOP NL MCSET P10 = P10 + 1 MCDEFG AU\P10. AS \A1. AUDELM{AU\P10.}]]> # macro to list all audio files MCDEF @ WITH AUDIOS AS <![ML1[MCFOR P1 = 1 TO P10 AUDELM+{AU\P1.} REPEAT]]>
A helper macro to open the URL in a new browser page.
MCDEF @ WITH url WITHS [ N1 ] WITHS { N2 } AS <![ML1[<a target="new" href="\A2.">\A1.</a>]]>
An example usage of this macro is in the next section.
The idea is I only need to edit a news file and the macro will help me distribute the content into different places.
@ONUM
shows old news items.
MCDEF BEGNEWS OLD ODD ENDNEWS WITHS NL SSAS <![ML1[MCDEFG @ WITHS NEWS AS \A1. MCSET P9 = 0 MCDEFG @ WITH ONEWS AS \A2. MCDEFG @ WITH ONUM AS \P9. more old news items. MCDEFG @ WITH ENEWS AS \A3. ]]>
Shared element for webpages.
Every webpage uses the same metadata in the HTML header.
# HTML metadata MCDEF @ WITH META AS <![ML1[<meta charset="utf-8"> <link rel="stylesheet" href="/css/style.css"> <link rel="icon" type="image/png" href="/favicon.png">]]>
Some webpage can use a music player to play the audio file.
Even though I'm personally against using JavaScript, the default audio player is just too bad that I copied some free code and rolled my own player.
Text browser users can use the download link.
MCDEF @ WITH PLAYER AS <![ML1[<link rel="stylesheet" href="/css/green-audio-player.css"> <script src="/js/green-audio-player.js"></script> <script> document.addEventListener('DOMContentLoaded', function() { GreenAudioPlayer.init({ selector: '.player', stopOthersOnPlay: true });}); </script>]]>
A fancy footer. With URL to this page.
MCDEF @ WITH FOOTER AS <![ML1[<footer> <p><b>The SDF Public Access UNIX System</b></p> <p>@url[<code>ml1</code>]{/mcs.html} and @url[GNU Emacs]{https://www.gnu.org/software/emacs/} are used to build this site.</p> <p>©2019-2025 LdBeth</p> <p><a rel="license" href="http://creativecommons.org/licenses/by/3.0/us/"> <img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/3.0/us/88x31.png"></a> <br> This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/3.0/us/">Creative Commons Attribution 3.0 United States License</a>.</p></footer>]]>
The navigation header.
The Skip Navigation link is required by some HTML accessibility guide.
MCDEF @ WITH HEADER AS <![ML1[<header><h3>[ LdBeth's Homepage ]</h3> <nav> <a href="#main" class="skip">Skip Navigation</a> <del>SDF-CN</del> <a href="https://emacs-china.org">Emacs China</a> <a href="https://github.com/LdBeth">GitHub</a> <a rel="me" href="https://mastodon.sdf.org/@ldbeth">Mastodon</a> <a rel="alternate" type="application/rss+xml" href="https://ldbeth.sdf.org/rss.xml">RSS</a> <a href="https://sdfcn.org">SDFCN</a> <a href="https://kekkan.org">RnE</a> <br> <a href="/articles/">Articles</a> <a href="/audio/">aNONradio</a> <a href="/aplfont.html">TeX Fonts</a> <a href="/lsml/">LsML</a> <a href="/cltl2.html">CLtL2</a> <a href="/">News</a></nav></header> <hr>]]>
Call MCNOSKIP
here to remove both the comment and
the macro delimiter. Also this ML/I macro will be used to process
the HTML generated from the same source file, to prevent the macro
referenced in the HTML been called and cause disaster, add these too
MCSKIP
delimiters.
The sed script in the next-next section will take care to handler the HTML markup in comment blocks.
# prevent macro executing in HTML code elements. MCNOSKIP\L99.MCSKIP DT, < WITH pre < WITH / WITH pre WITH > MCSKIP DT, < WITH code < WITH / WITH code WITH >
BEGNEWS @{Now the <code>ml1</code> @url[macro]{mcs.html} is documented in literate programming style.@} @{@url[Advent of Code 2024]{aplcomp/aoc2024.zip} This year I only did last two problems.@} @{A bit late for an announcement, but I have updated @url[zellio/j-mode]{https://github.com/zellio/j-mode}.@} OLD @{Advent of Code 2023 @url[answers]{aplcomp/aoc2023.zip}.@} @{SBR on Sept 16th.@} @aud{sbrsept16th.mp3} @{2023 APL Competition @url[answer]{aplcomp/pot.html}. Phase 2 only.@} @aud{sbrjun10th.mp3} @{SBR on June 10th.@} @aud{sbrjun10th.mp3} @{Another test on piano lib.@} @aud{vanille.mp3} @{Test out new piano lib.@} @aud{light.mp3} @{This time I put the both two parts from SBR of Jan 28th, because I like both of them.@} @aud{sbrjan28a.mp3} @aud{sbrjan28b.mp3} @{SDF-CN dead.@} @{An RSS feed has been added for this site to avoid growing this list.@} @{Another audio proof.@} @aud{audioproof2.mp3} @{A proof of concept did for first @url[NEC]{audio/index.html}.@} @aud{audioproof.mp3} @{SBR of Dec 3rd, went old method.@} @aud{sbrdec3rd.mp3} @{SBR of Nov 19th.@} @aud{sbrnov19th.mp3} @{Eternal Embrace, Gumi feat.@} @aud{eem.mp3} @{SBR of Nov 5th.@} @aud{sbrnov5th.mp3} @{Largo al factotum, feat. Megurine Luka.@} @aud{factotum.mp3} @{SBR of Oct 22nd.@} @aud{sbroct22nd.mp3} @{SBR of Oct 8th.@} @aud{sbroct8th.mp3} @{Again, good o'd physical modeling through CLM.@} @aud{yokanpiano.mp3} @{The <code>ml1</code> @url[macro]{mcs.html} I wrote to build the website.@} @{@url[Blackjack]{blackjack.txt} for CASIO fx-9860GII SD.@} @{God Knows... feat. Kagamine Rin.@} @aud{gk.mp3} @{Yokan feat. Megurine Luka.@} @aud{yokan.mp3} ODD @{Dyalog APL competition 2022 solutions: @url[Phase 1]{aplcomp/2022/phase1.html} and @url[Phase 2]{aplcomp/2022/phase2.html}.@} @{SDF-CN has been reset, well.@} @{Working on @url[LaTeX src of AMOP]{The_Art_of_the_Metaobject_Protocol.pdf}.@} @{Working on a proof of concept TECO editor in <del>Common Lisp. Now in Haskell. Probably will be in Scheme.</del><ins>Maybe just port to Plan9.</ins>@} @{A implementation of plot lib demonstrated in the book <i>Common LISP Modules</i> by Mark Watson is @url[here]{mig.pdf}.@} @aud{ee.mp3} @{This music its generated by @url[CLM]{https://ccrma.stanford.edu/software/clm/}, a Common Lisp MUSIC V implementation, according to @url[this sheet]{sheet.jpg}.@} ENDNEWS
The sed(1)
script used to generate this page.
Insert header.
1i\ <!DOCTYPE html><html lang="en">\ <head>@META<title>ML1 source for this website</title></head><body>\ <h1>Build HTML pages using ML/I</h1>\ <p><em>This page is generated using both </em><code>sed(1)</code>\ <em> and </em><code>ml1</code></p>\ <p><a href="https://www.ml1.org.uk/whatis.html">What is ML/I</a></p>\ <h2>The macro</h2>\ <pre class="programlisting">
Translate to HTML character entities so it can be embedded to HTML. Do not translate in comment blocks since they directly use HTML for markup, like this one.
/^#\*/!{ s/&/\&/g s/</\</g s/>/\>/g s/"/\"/g s/'/\'/g }
A hack to implement code blocks.
/^##\[/c\ </pre> /^##]/c\ <pre class="programlisting"> s/^#\* *//
Split files at appropriate places.
/^BEGNEWS/i\ </pre>\ <h2>News file</h2>\ <pre class="programlisting"> /^ENDNEWS$/a\ </pre>\ <h2>Bonus: The sed</h2>\ <p>The <code>sed(1)</code> script used to generate this page.</p>
Finally, append the page footer.
$a\ </pre></body></html>