Syntax injection selector problem
Posted: 28 March 2011 01:15 PM   [ Ignore ]
Newbie
Rank
Total Posts:  5
Joined  2011-03-26

I’ve got a little problem with syntax injections in my sugar.
In Smarty, there is a {literal} tag (its zone is named “element.literal”) to allow html and javascript to be inserted without the need to escape ”{” and ”}” characters. I am able to disable Smarty highlighting for this tag, while the html highlighting is still present.
However, there is an injection set, among others, for html tags:

<injection name="eu.ptrm.injections.smarty.tag" selector="sourcecode.smarty tag.open" action="insert-before-children">
    <include 
syntax="sourcecode.smarty" collection="tags" />
</
injection

So when I try something like this:

{literal}
    {$var}
    
<div class="foo" {$bar}></div>
{/literal} 


Smarty tags inside html tags still get highlighted.

I tried to use :not() in the injection selector (e.g. “sourcecode.smarty :not(.literal) tag.open”), but it doesn’t seem to work.
I’d be grateful for any ideas why it is so.

The full sugar code is available at https://github.com/ptrm/smarty.sugar

Profile
 
 
Posted: 28 March 2011 05:09 PM   [ Ignore ]   [ # 1 ]
Moderator
RankRankRankRank
Total Posts:  1252
Joined  2008-10-28

The likeliest problem with your injection selector is that it is too generic. Currently, it will inject that rule into any “tag.open” zone, regardless of whether it is HTML, Smarty, or embedded somewhere in a PHP block (not likely, but possible given that the shipping version of PHP embeds HTML in some strings). Some things that might solve the problem:

1) Specifically target immediate descendants of the root zone:

selector="sourcecode.smarty > tags.open" 

All HTML tags live in the root syntax zone, whereas all of your Smarty tags are embedded within broader zones (“element.paired.open”, “element.paired.literal”, etc.) so this should restrict your injection to HTML tags.

2) Target a specific zone on your Smarty “tag.open” zones to explicitly exclude them:

selector="sourcecode.smarty tag.open:not(identifier.function)" 

The benefit of this is that HTML tags are unlikely to ever have that identifier, whereas you can add it to any Smarty tags (if they don’t already have it), and the rule will work at any level of the hierarchy (if you have HTML nested in some other zone, which didn’t appear to be the case in my perusal of your sourcecode).

Good luck! Let us know if you have any other questions or problems with the Sugar.

 Signature 

Ian Beck
MacRabbit Support

Follow us on Twitter, or try my custom themes: Quiet Light & Earthworm

Profile
 
 
Posted: 29 March 2011 09:03 AM   [ Ignore ]   [ # 2 ]
Newbie
Rank
Total Posts:  5
Joined  2011-03-26

Thanks for a quick reply.
I’d like clear my intentions up before asking further questions.

The point is, the injection works perfectly well, but I would like to make one exception for it in the case when the html tag is between the {literal}{/literal} Smarty tags. This is the case when the injection shouldn’t be performed.
Also, I think it’s safer to mention that in the root syntax zone there can occur html tags as well as smarty tags (that’s the point of this template language). {literal} is just to make the compiler ignore whatever Smarty tags there would appear enclosed within this tag.

So, this code should have all ”{foreach}” highlighted:

{foreach}
<script{foreach}</script>
<style>{foreach}</style>
<
div {foreach} id="{foreach}">{foreach} 


Whereas this should have none (except for {literal}{/literal} and css and javascript highlighting)

{literal}
    {foreach}
    
<script{foreach}</script>
    
<style>{foreach}</style>
    <
div {foreach} id="{foreach}">{foreach}
{
/literal} 


(The syntax definitions have been pushed to github recently, so please update before testing so we will get the same results).

 

When it comes to the selector advice:

Ian Beck - 28 March 2011 05:09 PM
The likeliest problem with your injection selector is that it is too generic. Currently, it will inject that rule into any “tag.open” zone, regardless of whether it is HTML, Smarty, or embedded somewhere in a PHP block (not likely, but possible given that the shipping version of PHP embeds HTML in some strings).

This doesn’t seem to be the point here. The only injected syntax from outside is text.html.basic, and I use the element.<type> pattern for Smarty tags. Thanks for pointing this out for the future, however.

Ian Beck - 28 March 2011 05:09 PM

1) Specifically target immediate descendants of the root zone:

selector="sourcecode.smarty > tags.open" 

All HTML tags live in the root syntax zone, whereas all of your Smarty tags are embedded within broader zones (“element.paired.open”, “element.paired.literal”, etc.) so this should restrict your injection to HTML tags.

The problem starts here:

selector="sourcecode.smarty > tag.open" 


results in no injection for <tag {$smarty}> at all, although it seems it should match tags which are direct children of the root syntax zone.

Isn’t the comment on wiki (http://wiki.macrabbit.com/index/Syntaxes/) the point here? :

Syntax Injections
[...]
The selector attribute specifies which syntax rules have to be targeted for this particular injection. Note that the selector is interpreted against syntax rules in the syntax definitions, not against the resulting syntax zones.

It seems as if the hierarchy to consider is the one inside the definitions, not the one that the Syntax Inspector shows.

Also, I am not sure whether I understand one thing correctly:
If the zone is named “tag.open.style.html”, should the ”.open.style.html” part be treated as class values to “tag” (which seems more logical to me), or are they just multiple names for the zone, and the “style.html” selector (without the preceding dot) matches them as well? I got this doubts when I read the HTML sugar Itemizers file, which say for example:

<start-selector>html.tag.open:has-child(name:capture(name))</start-selector


While the words occur in different order in Syntax definitions file, e.g.:

<zone name="tag.open.other.html"


I hope this wasn’t too long.

Profile
 
 
Posted: 29 March 2011 11:20 AM   [ Ignore ]   [ # 3 ]
Moderator
RankRankRankRank
Total Posts:  1252
Joined  2008-10-28
Piotrek - 29 March 2011 09:03 AM
It seems as if the hierarchy to consider is the one inside the definitions, not the one that the Syntax Inspector shows.

D’oh! You are of course correct. I had a total brain fart and forgot how injections actually work. Not the first time that distinction has confused the heck out of me.

I will download your latest changes from GitHub and test out your example code later today to see if I can pinpoint more specifically the problem.

If the zone is named “tag.open.style.html”, should the ”.open.style.html” part be treated as class values to “tag” (which seems more logical to me), or are they just multiple names for the zone, and the “style.html” selector (without the preceding dot) matches them as well?

They are just multiple names for the zone. So “tag”, “open.style”, “html.style.open”, and “tag.style” should all match that zone.

 Signature 

Ian Beck
MacRabbit Support

Follow us on Twitter, or try my custom themes: Quiet Light & Earthworm

Profile
 
 
Posted: 29 March 2011 06:46 PM   [ Ignore ]   [ # 4 ]
Moderator
RankRankRankRank
Total Posts:  1252
Joined  2008-10-28

I have been experimenting with this, and I think your problems are a side effect of how Espresso 1.0 caches syntax injections to prevent overly expensive iteration through the syntax zone tree. Which unfortunately means that it doesn’t really matter what you put in the selector, it’s going to be all or nothing either way.

I will do more testing tomorrow to try and determine for sure if this is the case.

 Signature 

Ian Beck
MacRabbit Support

Follow us on Twitter, or try my custom themes: Quiet Light & Earthworm

Profile
 
 
Posted: 31 March 2011 03:46 AM   [ Ignore ]   [ # 5 ]
Newbie
Rank
Total Posts:  5
Joined  2011-03-26

Thank you for taking your time to inspect this.

When it comes to selectors, there is another problem I’ve stumbled upon recently while writing selectors for CodeSense providers.
When I write a selector this way:

<provider>
    <
selector>sourcecode.smarty element.standalone:has-child(identifier.function.tag:capture(name))</selector>
    <
completions>eu.ptrm.smarty.${name}.attributes</completions>
    <
complete-match capture="2">(\s)([a-zA-Z0-9-_]*)</complete-match>
    <require-
suffix>(\s|\}|^)</require-suffix>
</
provider

the ${name} variable seems not to be set.

When I remove the “sourcecode.smarty ” part, however:

<selector>element.standalone:has-child(identifier.function.tag:capture(name))</selector>
<
completions>eu.ptrm.smarty.${name}.attributes</completions


everything works fine, and the selector matches the standalone elements.

It seems to be the matter of :capture(name) not setting the variable, because replacing the variable with a tag name:

<selector>sourcecode.smarty element.standalone:has-child(identifier.function.tag:capture(name))</selector>
<
completions>eu.ptrm.smarty.include.attributes</completions


shows auto-completion list as well, although in a limited way.

In the code there are more rules per <selector>, I simplified it to avoid confusion. To make it even more clear: the selector I’ve chosen for the example should work with {include } tag with the insertion point followed by a space (”{include | }” and not ”{include |}”).

Profile