Ctify_ v26.6.3
Foldered preformatted text block (bug fix)
Yesterday, I already had a strong gut feeling that combining my custom-made PmWiki markup with the original built-in PmWiki markup is not that easy. Turns out, it’s true. Ctify_ v26.6.2 has this specific bug regarding the recently added “foldered preformatted text block” functionality.
In short, you can’t simply wrap the main text with `<pre class=’escaped’></pre>` and expect it to be escaped, because PmWiki will internally preprocess that text first instead of leaving it raw.
So today, I noticed that for every newline in the main text, PmWiki replaces it with this `<:vspace>` tag.
Later, this `vspace` tag -- and its CSS class -- causes it to appear “bigger than the usual newline”, something affected by either `margin-top` CSS or `padding-top` CSS. Ruining the aesthetics that I personally prefer.
So, I wish I could skip this PmWiki preprocessing code and make it show the good old newline.
But this preprocessing code is buried deep within `scripts/stdmarkup.php`.
It’s not the usual periphery code; it is the soul of PmWiki itself. The main raison d’être of PmWiki is simply to preprocess those syntaxes into properly rendered HTML code.
So, if I have to modify that sacred `stdmarkup.php`, there is a high chance that I’ll break PmWiki as a whole. The unintended consequences will spread everywhere, hard to detect, hard to catch. Scary.
So instead of that, I want to keep it safe. I want to “reimplement” the main functionality of `[@` in my markup function in `local/config.php`. No need to modify `stdmarkup.php`.
// local/config.php
Markup('g-folder', 'fulltext',
'/\\[\\[g:(.*?)\\]\\](.*?)\\[\\[\/g\\]\\]/is',
function($m) {
$title = htmlspecialchars(trim($m[1]), ENT_QUOTES);
$raw_content = str_replace(array('<:vspace>', '<:block>'), "", $m[2]);
// Escape content like [@ @] does
$content = htmlspecialchars(trim($raw_content), ENT_NOQUOTES);
return Keep(
"<details class='tvt-folder'>" .
"<summary><span class='folder-icon'>📁</span> {$title}</summary>" .
"<div class='folder-content'>" .
"<pre class='escaped'>{$content}</pre>" .
"</div>" .
"</details>"
);
}
);Markup('g-folder', 'fulltext',This registers a custom markup rule.
‘g-folder’ is the internal name of the rule. It can be any unique string.
‘fulltext’ is the processing stage (called $when in PmWiki). It tells PmWiki when this markup should run. Fulltext means run after most wiki processing is done. So in this strategy, I will let PmWiki do its own normal processing, even if it adds that
<:vspace>tag. It is okay. later, I will hunt them down using regex or something.
'/\\[\\[g:(.*?)\\]\\](.*?)\\[\\[\/g\\]\\]/is',This is the regex pattern that finds [[g:]] custom syntax.
Regex input :
[[g:Movies]]
hello
world
[[/g]]Regex output :
$m[0] = entire matched block
$m[1] = "Movies"
$m[2] = "hello\nworld"$raw_content = str_replace(array('<:vspace>', '<:block>'), "", $m[2]);This removes PmWiki internal formatting markers, since PmWiki secretly inserts tokens like <:vspace> or <:block> during parsing to represent paragraph spacing and block boundaries. This line cleans them out.
$content = htmlspecialchars(trim($raw_content), ENT_NOQUOTES);This mimics [@. trim() removes leading/trailing whitespace. htmlspecialchars() escapes wiki/HTML syntax so it appears literally. ENT_NOQUOTES means quotes are not escaped.
Keep()Keep() tells PmWiki: “Do not process this HTML any further.” Without Keep(), PmWiki might try to interpret things inside the HTML again and break it.
