emmetio / sublime-text-plugin

The essential toolkit for web-developers
https://emmet.io
MIT License
250 stars 30 forks source link

Expanding HTML abbreviation in double-quote PHP strings breaks the string #155

Open brodenbrett opened 3 years ago

brodenbrett commented 3 years ago

When expanding HTML in double-quote PHP strings, any quotes inside the resulting code are also double quotes, which breaks the string. Is it possible to edit my Emmet settings to detect and take this into account?

<?php 
"div.foo"; // My abbreviation

"<div class="foo"></div>"; // What it expands into

"<div class='foo'></div>"; // Is it possible to achieve this instead?
"<div class=\"foo\"></div>"; // Or (less preferably) this?
?>
sergeche commented 3 years ago

It’s possible to set output quotes of generated Emmet snippets. I made a small update in 2.3.3 so you can set it for PHP but it’s quite tricky:

  1. Create a new mapping of Sublime Text selector to syntax name in Emmet preferences. To do so, you have to update syntax_scopes key and create a new, custom syntax name. For example:
"phpstr": "string.quoted.double.php"

e.g. whenever you expand abbreviation inside string.quoted.double.php scope, Emmet will treat its syntax as phpstr. By default, all unknown syntaxes are treated as markup (which is used for HTML, Pug, Slim etc.)

  1. Now, you can Emmet options for your custom phpstr syntax: edit config key of Emmet preferences and set output.attributeQuotes option to single:
"config": {
    "phpstr": {
        "options": {
            "output.attributeQuotes": "single"
        }   
    }
}

Your final Emmet.sublime-preferences should look like this:

{
    "syntax_scopes": {
        "html": "text.html - source - meta.attribute-with-value.style",
        "xml": "text.xml - text.xml.xsl",
        "xsl": "text.xml.xsl",
        "jsx": "source.js.jsx | source.tsx | source.js | source.jsx",
        "haml": "source.haml",
        "jade": "text.jade | source.pyjade",
        "pug": "text.pug | source.pypug",
        "slim": "text.slim",

        "css": "source.css | source.postcss | meta.attribute-with-value.style.html string.quoted",
        "sass": "source.sass",
        "scss": "source.scss",
        "less": "source.less",
        "stylus": "source.stylus",
        "sss": "source.sss",

        // Your custom syntax
        "phpstr": "string.quoted.double.php"
    },
    "config": {
        "phpstr": {
            "options": {
                "output.attributeQuotes": "single"
            }   
        }
    }
}
brodenbrett commented 3 years ago

Thanks @sergeche. This is close, however there are still some issues as I can't get this fix to work while still allowing me to expand abbreviations with the tab key. It seems to be conflicting with the solution from this previous issue.

It looks like it has to do with the "html" syntax scope - I currently have it set to "text.html - source - meta.attribute-with-value.style, text.html source.php string". Any thoughts on how I can have it both ways?

Here's my current user settings:

{
    // Editor scope to Emmet syntax mapping
    "syntax_scopes": {
        "html": "text.html - source - meta.attribute-with-value.style, text.html source.php string",
        "xml": "text.xml - text.xml.xsl",
        "xsl": "text.xml.xsl",
        "jsx": "source.js.jsx | source.tsx | source.js | source.jsx",
        "haml": "source.haml",
        "jade": "text.jade | source.pyjade",
        "pug": "text.pug | source.pypug",
        "slim": "text.slim",

        "css": "source.css | source.postcss | meta.attribute-with-value.style.html string.quoted",
        "sass": "source.sass",
        "scss": "source.scss",
        "less": "source.less",
        "stylus": "source.stylus",
        "sss": "source.sss",

        // custom scope for double-quoted PHP strings
        "phpstr": "string.quoted.double.php"
    }, 

    "abbreviation_scopes": [
        "source.php string",
        "(text.html | text.xml) - source - meta - comment",
        "source.sass - meta.property-value - meta.property-name - string - punctuation - comment",
        "(source.css | source.scss | source.less | source.postcss | source.stylus) & meta.property-list",
        "(source.css | source.scss | source.less | source.postcss | source.stylus) - meta.property-value - meta.property-name - string - comment",
        "(source.tsx | source.js | source.jsx) - comment",
        "text.html.cfml - meta.tag",
        // Inline CSS
        "text.html meta.attribute-with-value.style (string.quoted | source.css)"
    ],

    "config": {

        // custom scope for double-quoted PHP strings
        "phpstr": {
            "options": {
                "output.attributeQuotes": "single"
            }   
        }
    }
}
brodenbrett commented 3 years ago

Hey @sergeche, it's been a few days so just wanted to double-check you were aware of the ask. No rush.

sergeche commented 3 years ago

Not sure where the problem is and what you’re trying to achieve

brodenbrett commented 3 years ago

I'll try to go into more detail. I'm wondering if there is a way to both:

  1. Account for double-quoted PHP strings by using single quotes
  2. Allow PHP string literals to be context for HTML syntax

Referencing this previous issue; the solution for No. 2 involved adding the source.php string property into abbreviation_scopes, well as letting Emmet know that PHP strings are context for HTML syntax by modifying the html selector in syntax_scopes as follows:

"html": "text.html - source - meta.attribute-with-value.style, text.html source.php string",

It seems this doesn't play well with the solution you provided. I have tried modifying the html selector in syntax_scopes in a few different ways, but I haven't been able to expand HTML in PHP string literals while the given solution is implemented.

As an example, when I force an HTML abbreviation to expand using the ctrl+e hotkey, this works as intended:

<?php

echo 'foo.bar';
// Expands into: 
echo '<foo class="bar"></foo>';

echo "foo.bar";
// Expands into:
echo "<foo class='bar'></foo>";

?>

However, when I try to expand with the tab key, the abbreviation no longer expands:

<?php

echo "foo.bar";
// Expands into:
echo "foo.bbcode_set_arg_parser(bbcode_container, bbcode_arg_parser)"; // Some random intellisense garbage

?>

Hope this makes it more clear.

sergeche commented 3 years ago

OK, so it looks like you’re trying to the same behaviour with Tab key as in HTML? With automatic abbreviation marking and preview?

brodenbrett commented 3 years ago

Yup, that's correct.

sergeche commented 3 years ago

I need some time to update plugin to make this work

brodenbrett commented 3 years ago

Sounds good - thanks for looking into this.