Textpattern CMS support forum
You are not logged in. Register | Login | Help
- Topics: Active | Unanswered
Making plugins first-class citizens
Wouldn’t it be nice if instead of writing code like this:
<txp:zem_contact to="me@example.com">
<txp:zem_contact_email />
<txp:zem_contact_textarea />
<txp:zem_contact_submit />
</txp_zem_contact>
… we could simply write this:
<zem:contact to="me@example.com">
<zem:contact_email />
<zem:contact_textarea />
<zem:contact_submit />
</zem:contact>
As it turns out, that only requires a minor modification to the parser: patch for txp4.6-dev
The patch assumes that every plugin developer uses a 3 character plugin prefix, which they should if they follow the guidelines. The patch doesn’t force people to use the new notation; it just offers it as an alternative.
edit:
3 letter prefix patch (updated with fixes for splat and EvalElse)
3 char prefix patch
2-3 char prefix patch
Offline
Re: Making plugins first-class citizens
That would be nice, indeed, but could clash with importing namespaced xml documents. And I think you need to do a minor change in splat()
function too, unless I’ve overlooked it in your patch (sorry then).
Online
#3 2014-11-16 22:00:40
- gomedia
- Plugin Author
- Registered: 2008-06-01
- Posts: 1,373
Re: Making plugins first-class citizens
ruud wrote #285799:
Wouldn’t it be nice if instead of writing code like this … we could simply write this …
Yes it would! Any modifications to plugin code required?
And in the interest of forum post interlinking: here’s one that dreamt of a bright new future, including namespaces and tag registering.
Offline
Re: Making plugins first-class citizens
This looks nice. What would happen if a plugin author chose a prefix with a different length?
Offline
Re: Making plugins first-class citizens
etc wrote #285804:
That would be nice, indeed, but could clash with importing namespaced xml documents.
It’s not really different from TXP tags, so those would then potentially clash with XML documents as well, I think.
And I think you need to do a minor change in
splat()
function too, unless I’ve overlooked it in your patch (sorry then).
splat()
gets the string of attributes as input, not the tagname itself.
gomedia wrote #285807:
Yes it would! Any modifications to plugin code required?
None at all.
wet wrote #285809:
This looks nice. What would happen if a plugin author chose a prefix with a different length?
With the patch I provided, <long:tag> and <i:m to=“short”> would not be recognized as tags. Those would have to be written as <txp:long_tag> and <txp:i_m to=“short”>
However, it’s easy to rewrite the patch to support variable length prefixes. I chose a fixed width of 3 chars, because that’s what our plugin guidelines specify. Actually, the guidelines specify 3 letters, which is even more specific.
- 290 three letter prefixes
- 4 two letter prefixes (it, ja, jk, vg)
- 4 three character prefixes (an7, e26, ob1,r11)
One could argue that allowing 2-char prefixes gives an unfair advantage, because shorter tends to be more popular.
I’ll update the first post with new patches for strict 3 letter, 3 character, 2-3 character prefixes. The latter can be changed to longer prefixes by changing 2 characters in the patch.
Offline
Re: Making plugins first-class citizens
Very cool. And backwards compatible too, as it’s just an extension for permitting simpler syntax (so no plugin changes required). Reinforcing the three-character prefix in order to take advantage of this feature is a reasonable restriction/convention and actually makes the case for proper prefixing stronger, because plugin authors will surely want their user base to do less typing to work with their public-side plugins :-)
Haven’t tested it yet, but it does look as though etc is right: splat()
may need changing to parse and display attributes from first-class plugins in the tag trace. The trick is to do this efficiently, since it’s called a lot.
Regarding the XML import, it shouldn’t be a problem as tags need registering prior to execution to avoid throwing the warning and (ultimately, one day) failing outright. So unless the XML document is handled by a plugin that auto-registers namespaced tags within Textpattern, we should be covered. Ummm, I think…
I’m all for this. And I’d love to see some stuff in the parser like Gocom mentioned in the post to which gomedia linked. I was trying to find that post the other day and failed, thanks!
The smd plugin menagerie — for when you need one more gribble of power from Textpattern. Bleeding-edge code available on GitHub.
Txp Builders – finely-crafted code, design and Txp
Offline
Re: Making plugins first-class citizens
ruud wrote #285833:
It’s not really different from TXP tags, so those would then potentially clash with XML documents as well, I think.
Sure, but every new prefix results in the clash probability increase. Suppose that you need to export some articles as Excel sheet, which includes plenty of <mso:tags />
, then using any mso_plugin
would be problematic.
splat()
gets the string of attributes as input, not the tagname itself.
I mean this:
if (strpos($m[3], '<txp:') !== FALSE)
{
trace_add("[attribute '".$m[1]."']");
$val = parse($val);
trace_add("[/attribute]");
}
It’s not only trace_add()
, but parse()
.
Edit: EvalElse()
probably needs to be modified too.
Last edited by etc (2014-11-17 14:43:30)
Online
Re: Making plugins first-class citizens
Bloke wrote #285834:
The trick is to do this efficiently, since it’s called a lot.
I’ve made some modifications in parse()
(running in the wild here) to cache the results of preg_split
. The modified parser itself is much faster, but the overall performance is just a little better, because most of runtime is taken by db calls / udfs. It’s still worth implementing, at the risk of sha1
collision (but then it will be the first known one :).
Online
Re: Making plugins first-class citizens
New patch (see opening post) with fixes for splat and EvalElse.
Offline
Re: Making plugins first-class citizens
Superb, thanks. Hadn’t considered EvalElse()
but from reading the patch, it seems to allow lovely constructs like:
<smd:if ...>
Yay :-)
<smd:else />
Nay :-(
</smd:if>
effectively retrofitting every plugin with a personal else tag. If that’s true (is it?), it’ll make multiple nested conditional pages easier to follow, because you can marry else tags up with a plugin’s opening / closing tags by prefix. Brilliant. Of course there’s every chance I’ve misinterpreted the patch out of context with the source itself.
Will test this when I get a chance.
The smd plugin menagerie — for when you need one more gribble of power from Textpattern. Bleeding-edge code available on GitHub.
Txp Builders – finely-crafted code, design and Txp
Offline
Re: Making plugins first-class citizens
Bloke wrote #285840:
Superb, thanks. Hadn’t considered
EvalElse()
but from reading the patch, it seems to allow lovely constructs like: […] effectively retrofitting every plugin with a personal else tag.
Hmm… to do that you’d have to replace
$els = strpos($thing, '<txp:else');
with something monstrous like (not tested):
for ($pos = 3, $len = strlen($thing); $pos < $len and false !== $pos = strpos($thing, ':else', $pos+1);)
{
if ($thing[$pos - 4] != '<') continue;
for ($i = $pos - 3; $i < $pos; $i++) if (ord($thing[$i]) < 97 or ord($thing[$i]) > 122) continue 2;
$len = true;
}
$pos = $len ? $pos : $false;
but if we’re not desperately trying to avoid preg_match, you could replace:
$els = strpos($thing, '<txp:else');
if ($els === false) {
// no <txp:else /> tag
if ($condition) {
return $thing;
}
return '';
} elseif ($els === strpos($thing, '<') or $els + 4 === strpos($thing, ':') or !preg_match('/<[a-z]{3}:/', substr($thing, 0, $els))) {
// no TXP tag before the <txp:else /> tag
if ($condition) {
return substr($thing, 0, $els);
}
return substr($thing, strpos($thing, '>', $els) + 1);
}
with (also not tested):
if (false === $els = strpos($thing, ':else', 4) or !preg_match('/<[a-z]{3}:(\w+)/', $thing, $matches)) {
// no <txp:else /> tag
if ($condition) {
return $thing;
} else {
return '';
}
} elseif ($matches[1] === 'else') {
// <txp:else /> is the first tag in $thing
if ($condition) {
return substr($thing, 0, $els - 4);
} else {
return substr($thing, strpos($thing, '>', $els) + 1);
}
}
Keep in mind, that this part of the code is just speed optimisation. If someone passes <txp:title /> :else
that ideally would trigger the “no <txp:else />” condition, but failing to do so doesn’t break EvalElse. It just makes it a bit slower. Realistically, that is not a situation that will occur a lot. If $thing contains :else
, then it’s very likely that it’s part of a TXP tag.
Offline
Re: Making plugins first-class citizens
No worries if it doesn’t do that. I just read the code wrong in haste. Speed of parsing is my main concern rather than the bonus of a mega else tag so the original patch with the EvalElse
fixes is just fine at the mo. Thanks for your hard work.
The smd plugin menagerie — for when you need one more gribble of power from Textpattern. Bleeding-edge code available on GitHub.
Txp Builders – finely-crafted code, design and Txp
Offline