Closed weary-adventurer closed 2 months ago
In Smarty v5, you should be able to create a TagCompiler
that implements \Smarty\Compile\CompilerInterface
and return it from getTagCompiler
in your custom Extension. Or actually two, one that handles highlight
and one that handles highlightclose
.
Thanks! Can you make a simple example that shows how to get attributes and content between opening and closing tags? I've looked at the \Smarty\Compile\Base usages for tags but none of them seem to be getting the contents directly.
I assume it will look something like this:
<?php
class HighlightTag extends \Smarty\Compile\Base {
public function compile($args, $compiler, $parameter = [], $tag = null, $function = null) {
// ...
}
}
class HighlightCloseTag extends \Smarty\Compile\Base {
public function compile($args, $compiler, $parameter = [], $tag = null, $function = null) {
// TODO: Get attributes from {highlight lang=xyz}
// TODO: Get content between {highlight}xyz{/highlight}
// TODO: Return processed content
}
}
class HighlightExtension extends \Smarty\Extension\Base {
public function getTagCompiler(string $tag): \Smarty\Compile\CompilerInterface {
switch ($tag) {
case "highlight": return new HighlightTag();
case "highlightclose": return new HighlightCloseTag();
}
return null;
}
}
$smarty->addExtension(new HighlightExtension());
?>
Wow, turns out this was a bit harder than I expected, but this seems to do the trick:
<?php
require 'vendor/autoload.php';
use Smarty\Smarty;
class HighlightTag extends \Smarty\Compile\Base {
public function compile($args, $compiler, $parameter = [], $tag = null, $function = null): string
{
$this->openTag(
$compiler,
'highlight',
[
$this->getAttributes($compiler, $args),
$compiler->getParser()->current_buffer,
]
);
// Init temporary context
$compiler->getParser()->current_buffer = new \Smarty\ParseTree\Template();
return '';
}
}
class HighlightCloseTag extends \Smarty\Compile\Base {
public function compile($args, $compiler, $parameter = [], $tag = null, $function = null): string
{
$saved_data = $this->closeTag($compiler, ['highlight']);
$_attr = $saved_data[0];
// maybe use the attribute here
$blockCode = $compiler->getParser()->current_buffer;
// setup buffer for template function code
$template = new \Smarty\ParseTree\Template();
$template->append_subtree($compiler->getParser(), new \Smarty\ParseTree\Tag($compiler->getParser(),
"<div style='background-color:yellow'>"
));
$template->append_subtree($compiler->getParser(),
$blockCode
);
$template->append_subtree($compiler->getParser(), new \Smarty\ParseTree\Tag($compiler->getParser(),
"</div>"
));
$output = $template->to_smarty_php($compiler->getParser());
// restore old buffer
$compiler->getParser()->current_buffer = $saved_data[1];
return $output;
}
}
class HighlightExtension extends \Smarty\Extension\Base {
public function getTagCompiler(string $tag): ?\Smarty\Compile\CompilerInterface {
switch ($tag) {
case "highlight": return new HighlightTag();
case "highlightclose": return new HighlightCloseTag();
}
return null;
}
}
$smarty = new Smarty();
$smarty->addExtension(new HighlightExtension());
$smarty->display('string: BEFORE {highlight} my <bold>attempt</bold> dfsdf {/highlight} AFTER');
Note that this relies heavily on internal Smarty methods that might very well change in the future. @weary-adventurer
@weary-adventurer PS2: $blockCode
is a parse tree, not a plain string. It might contain (parsed) smarty tags, for example. You cannot just run in through Highlight\Highlighter
.
Thanks, this is pretty good. Would it be possible to wrap it into a "blockcompiler" plugin or plugins are no longer supported and it's now done with extensions? There are already "block" and "compiler" plugins that are very easy to use and it makes sense to add a "blockcompiler" as well.
Either way, I think it would be a good idea to add this example to documentation.
Extensions are the preferred way now, but since this depends so heavily on internal smarty methods, end because of PS2 above, I don't really feel like documenting it.
I would like to have a way to process a block tag at compile time. For example, to highlight a code snippet:
Currently this runs at runtime even thought the code is constant. It is possible to do it with a compile-time inline tag:
But for some reason, there is no compile-time block tag. I think there must be a "blockcompiler" so it's possible to preprocess arbitrary content.