├── .eslintrc.json ├── .gitattributes ├── .github └── FUNDING.yml ├── .gitignore ├── .vscode ├── extensions.json ├── launch.json └── settings.json ├── .vscodeignore ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── extension └── index.js ├── images └── icon.png ├── package-lock.json ├── package.json ├── rollup.config.js └── src ├── extension.js ├── hover ├── filters.json ├── functions.json └── twig.json ├── languages └── twig.configuration.json ├── snippets └── snippets.json └── syntaxes └── twig.tmLanguage /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": false, 4 | "commonjs": true, 5 | "es6": true, 6 | "node": true 7 | }, 8 | "parserOptions": { 9 | "ecmaFeatures": { 10 | "jsx": true 11 | }, 12 | "sourceType": "module" 13 | }, 14 | "rules": { 15 | "no-const-assign": "warn", 16 | "no-this-before-super": "warn", 17 | "no-undef": "warn", 18 | "no-unreachable": "warn", 19 | "no-unused-vars": "warn", 20 | "constructor-super": "warn", 21 | "valid-typeof": "warn" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set default behavior to automatically normalize line endings. 2 | * text=auto 3 | 4 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [mblode] 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .vscode-test/ 3 | *.vsix 4 | 5 | ### OSX ### 6 | # General 7 | .DS_Store 8 | .AppleDouble 9 | .LSOverride 10 | 11 | # Icon must end with two \r 12 | Icon 13 | 14 | # Thumbnails 15 | ._* 16 | 17 | # Files that might appear in the root of a volume 18 | .DocumentRevisions-V100 19 | .fseventsd 20 | .Spotlight-V100 21 | .TemporaryItems 22 | .Trashes 23 | .VolumeIcon.icns 24 | .com.apple.timemachine.donotpresent 25 | 26 | # Directories potentially created on remote AFP share 27 | .AppleDB 28 | .AppleDesktop 29 | Network Trash Folder 30 | Temporary Items 31 | .apdisk 32 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "dbaeumer.vscode-eslint" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that launches the extension inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "runtimeExecutable": "${execPath}", 13 | "args": [ 14 | "--extensionDevelopmentPath=${workspaceFolder}" 15 | ] 16 | }, 17 | { 18 | "name": "Extension Tests", 19 | "type": "extensionHost", 20 | "request": "launch", 21 | "runtimeExecutable": "${execPath}", 22 | "args": [ 23 | "--extensionDevelopmentPath=${workspaceFolder}", 24 | "--extensionTestsPath=${workspaceFolder}/test" 25 | ] 26 | } 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "eslint.enable": true 3 | } 4 | -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | test/** 4 | .gitignore 5 | jsconfig.json 6 | vsc-extension-quickstart.md 7 | .eslintrc.json 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | ## [0.8.0] - 2019-04-17 6 | 7 | ### Changed 8 | 9 | - Pretty Diff formatting bug has been solved correctly 10 | 11 | ### Added 12 | 13 | - Added many more configuration options 14 | 15 | ## [0.7.0] - 2019-04-01 16 | 17 | ### Changed 18 | 19 | - Fixed bug that clears entire document and only leaves the script tag 20 | - Preserved new lines 21 | - Updated packages 22 | - Converted extension to ES6 23 | 24 | ## [0.6.0] - 2019-02-26 25 | 26 | ### Changed 27 | 28 | - Updated snippets for Craft CMS 3 29 | 30 | ## [0.5.1] - 2019-01-31 31 | 32 | ## Added 33 | 34 | - Add changelog (finally) 35 | 36 | ### Changed 37 | 38 | - Update Prettydiff package to 100.1.7 39 | 40 | ## [0.4.4] - 2019-01-05 41 | 42 | ### Changed 43 | 44 | - Move to Pretty Diff 3 45 | - Clean up package.json 46 | - Refactor format selection based on Unibeautify and Prettier 47 | - Fix extension settings to match Pretty Diff 3's option changes 48 | - Fix tab size issue 49 | - Update readme to be more clear about limitations of the extension 50 | 51 | ## [0.3.2] - 2018-04-02 52 | 53 | ### Changed 54 | 55 | - Fix issues with snippes 56 | - Refine readme documentation 57 | 58 | ## [0.2.11] - 2018-01-20 59 | 60 | ### Added 61 | 62 | - Create new extension based on Twig Language 1 63 | 64 | ### Changed 65 | 66 | - Change name to Twig Language 2 67 | - Update readme based on name change 68 | - Change activation events 69 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 mblode 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |

VS Code Twig Language 2 👋

6 | 7 |

8 | 9 | 10 | Maintenance 11 | 12 | 13 | License: MIT 14 | 15 |

16 | 17 | - Syntax highlighting 18 | - Snippets 19 | - Emmet 20 | - Pretty Diff 3 Formatting 21 | - Hover 22 | 23 | ## What has changed since version 1? 24 | 25 | This extension does **not** have HTML Intellisense. If you need HTML Intellisense (which can be quite useful), please download my other Twig Language extension: https://github.com/mblode/vscode-twig-language. 26 | 27 | I have created a new extension to fix the issues that I (and all of you) were having with file association, commenting and VS Code UI issues. 28 | 29 | Simply add these lines to your VS Code settings to get emmet working and also to associate HTML files as twig syntax. 30 | 31 | ``` 32 | "files.associations": { 33 | "*.html": "twig" 34 | }, 35 | "emmet.includeLanguages": { 36 | "twig": "html" 37 | }, 38 | ``` 39 | 40 | ## Installation 41 | 42 | Install through Visual Studio Code extensions. Search for `Twig Language 2` 43 | 44 | [Visual Studio Code Market Place: Twig Language 2](https://marketplace.visualstudio.com/items?itemName=mblode.twig-language-2) 45 | 46 | ## Configuration 47 | 48 | Restart VS Code after making changes to Twig Language 2 extension settings. 49 | 50 | ## Documentation 51 | 52 | Twig Language 2 is a Visual Studio Code extension that provides snippets, syntax highlighting, hover, and formatting for the Twig file format. 53 | 54 | ### Twig syntax highlighting and language support 55 | 56 | This extension provides language support for the Twig syntax. 57 | 58 | ### Code formatter/beautifier for Twig files 59 | 60 | Using PrettyDiff, this extension implements the only working code formatter for Twig files in VS Code. 61 | 62 | ### Information about Twig code on hover 63 | 64 | VS Code Twig language 2 shows information about the symbol/object that's below the mouse cursor when you hover within Twig files. 65 | 66 | ### Craft CMS/Twig code snippets 67 | 68 | Adds a set of Craft CMS/Twig code snippets to use in your Twig templates. 69 | 70 | ### Generic Triggers 71 | 72 | ```twig 73 | 74 | do {% do ... %} 75 | extends {% extends 'template' %} 76 | from {% from 'template' import 'macro' %} 77 | import {% import 'template' as name %} 78 | importself {% import _self as name %} 79 | inc, include {% include 'template' %} 80 | incp {% include 'template' with params %} 81 | inckv {% include 'template' with { key: value } %} 82 | use {% use 'template' %} 83 | 84 | autoescape {% autoescape 'type' %}...{% endautoescape %} 85 | block, blockb {% block name %} ... {% endblock %} 86 | blockf {{ block('...') }} 87 | embed {% embed "template" %}...{% endembed %} 88 | filter, filterb {% filter name %} ... {% endfilter %} 89 | macro {% macro name(params) %}...{% endmacro %} 90 | set, setb {% set var = value %} 91 | spaceless {% spaceless %}...{% endspaceless %} 92 | verbatim {% verbatim %}...{% endverbatim %} 93 | 94 | if, ifb {% if condition %} ... {% endif %} 95 | ife {% if condition %} ... {% else %} ... {% endif %} 96 | for {% for item in seq %} ... {% endfor %} 97 | fore {% for item in seq %} ... {% else %} ... {% endfor %} 98 | 99 | else {% else %} 100 | endif {% endif %} 101 | endfor {% endfor %} 102 | endset {% endset %} 103 | endblock {% endblock %} 104 | endfilter {% endfilter %} 105 | endautoescape {% endautoescape %} 106 | endembed {% endembed %} 107 | endfilter {% endfilter %} 108 | endmacro {% endmacro %} 109 | endspaceless {% endspaceless %} 110 | endverbatim {% endverbatim %} 111 | 112 | ``` 113 | 114 | ### Craft Triggers 115 | 116 | ```twig 117 | asset craft.assets.one() 118 | assets, assetso craft.assets loop 119 | categories, categorieso craft.categories loop 120 | entries, entrieso craft.entries loop 121 | feed craft.app.feeds.getFeedItems loop 122 | t | t 123 | replace | replace('search', 'replace') 124 | replacex | replace('/(search)/i', 'replace') 125 | split | split('\n') 126 | tags, tagso craft.tags loop 127 | users, userso craft.users loop 128 | 129 | cache {% cache %}...{% endcache %} 130 | children {% children %} 131 | exit {% exit 404 %} 132 | ifchildren {% ifchildren %}...{% endifchildren %} 133 | css {% css %}...{% endcss %} 134 | registercssfile {% do view.registerCssFile("/resources/css/global.css") %} 135 | js {% js %}...{% endjs %} 136 | registerjsfile {% do view.registerJsFile("/resources/js/global.js") %} 137 | matrix, matrixif Basic Matrix field loop using if statements 138 | matrixifelse Basic Matrix field loop using if/elseif 139 | matrixswitch Basic Matrix field loop using switch 140 | nav {% nav item in items %}...{% endnav %} 141 | paginate Outputs example of pagination and prev/next links 142 | redirect {% redirect 'login' %} 143 | requirelogin {% requireLogin %} 144 | requirepermission {% requirePermission "spendTheNight" %} 145 | switch {% switch variable %}...{% endswitch %} 146 | 147 | csrf {{ csrfInput() }} 148 | endbody {{ endBody() }} 149 | head {{ head() }} 150 | 151 | getparam craft.app.request.getParam() 152 | getbodyparam craft.app.request.getBodyParam() 153 | getqueryparam craft.app.request.getQueryParam() 154 | getsegment craft.app.request.getSegment() 155 | 156 | case {% case "value" %} 157 | endcache {% endcache %} 158 | endifchildren {% endifchildren %} 159 | endcss {% endcss %} 160 | endjs {% endjs %} 161 | endnav {% endnav %} 162 | 163 | ceil ceil() 164 | floor floor() 165 | max max() 166 | min min() 167 | shuffle shuffle() 168 | random random() 169 | round num | round() 170 | url, urla url('path'), url('path', params, 'http', false) 171 | 172 | rss Example rss feed 173 | 174 | dd
{{ dump() }}
{% exit %} 175 | dump
{{ dump() }}
176 | ``` 177 | 178 | ### Example Forms 179 | 180 | ```twig 181 | 182 | formlogin Example login form 183 | formuserprofile Example user profile form 184 | formuserregistration Example user registration form 185 | formforgotpassword Example forgot password form 186 | formsetpassword Example set password form 187 | formsearch Example search form 188 | formsearchresults Example search form results 189 | 190 | ``` 191 | 192 | ### Reference Hints 193 | 194 | ```twig 195 | 196 | info All craft.assets properties and template tags 197 | info All craft.crategories properties and template tags 198 | info All craft.config properties and template tags 199 | info All craft.entries properties and template tags 200 | info All craft.feeds properties and template tags 201 | info All craft.fields properties and template tags 202 | info All craft.globals properties and template tags 203 | info All craft.request properties and template tags 204 | info All craft.sections properties and template tags 205 | info All craft.session properties and template tags 206 | info All craft.tags properties and template tags 207 | info All craft.users properties and template tags 208 | info All craft globals (site info, date, users, template tags) 209 | 210 | ``` 211 | 212 | ## Author 213 | 214 | 👤 **Matthew Blode** 215 | 216 | * Github: [@mblode](https://github.com/mblode) 217 | 218 | ## 🤝 Contributing 219 | 220 | Contributions, issues and feature requests are welcome !
Feel free to check [issues page](https://github.com/mblode/vscode-twig-language-2/issues). 221 | 222 | ## Show your support 223 | 224 | Give a ⭐️ if this project helped you ! 225 | 226 | ## 📝 License 227 | 228 | Copyright © 2019 [Matthew Blode](https://github.com/mblode).
229 | This project is [MIT](https://github.com/mblode/vscode-twig-language-2/blob/master/LICENSE.md) licensed. 230 | -------------------------------------------------------------------------------- /extension/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var vscode = require('vscode'); 4 | var prettydiff = require('prettydiff'); 5 | 6 | function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } 7 | 8 | var vscode__default = /*#__PURE__*/_interopDefaultLegacy(vscode); 9 | var prettydiff__default = /*#__PURE__*/_interopDefaultLegacy(prettydiff); 10 | 11 | const abs={text:"abs",body:"abs",description:"filter returns the absolute value"};const batch={prefix:"batch",body:"batch(${size}, ${fill})",text:"batch(size, fill)",description:"filter \"batches\" items by returning a list of lists with the given number of items. A second parameter can be provided and used to fill in missing items"};const capitalize={text:"capitalize",body:"capitalize",description:"filter capitalizes a value. The first character will be uppercase, all others lowercase"};const convert_encoding={prefix:"convert_encoding",body:"convert_encoding('${to}', '${from}')",text:"convert_encoding('to', 'from')",description:"filter converts a string from one encoding to another. The first argument is the expected output charset and the second one is the input charset"};const date={prefix:"date",body:"date(\"${m/d/Y}\")",text:"date(\"m/d/Y\")",description:"filter formats a date to a given format"};const date_modify={prefix:"date_modify",body:"date_modify(\"${+1 day}\")",text:"date_modify(\"+1 day\")",description:"filter modifies a date with a given modifier string"};const first={text:"first",body:"first",description:"filter returns the first \"element\" of a sequence, a mapping, or a string"};const format={prefix:"format",body:"format($1)",text:"format()",description:"filter formats a given string by replacing the placeholders (placeholders follows the sprintf notation)",example:"{% set foo = \"foo\" %}\n{{ \"I like %s and %s.\"| format(foo, \"bar\") }}\n\n{# outputs I like foo and bar #}"};const join={prefix:"join",body:"join${('optional')}",text:"join",description:"filter returns a string which is the concatenation of the items of a sequence"};const json_encode={prefix:"json_encode",body:"json_encode()",text:"json_encode()",description:"filter returns the JSON representation of a value. Internally, Twig uses the PHP json_encode function."};const keys={text:"keys",body:"keys",description:"filter returns the keys of an array. It is useful when you want to iterate over the keys of an array"};const last={text:"last",body:"last",description:"filter returns the last \"element\" of a sequence, a mapping, or a string"};const length={text:"length",body:"length",description:"filter returns the number of items of a sequence or mapping, or the length of a string"};const lower={text:"lower",body:"lower",description:"filter converts a value to lowercase"};const merge={prefix:"merge",body:"merge(${array})",text:"merge(array)",description:"filter merges an array with another array"};const nl2br={text:"nl2br",body:"nl2br",description:"filter inserts HTML line breaks before all newlines in a string"};const number_format={prefix:"number_format",body:"number_format(${0}, '${.}', '${,}')",text:"number_format",description:"filter formats numbers. It is a wrapper around PHP's number_format function"};const raw={text:"raw",body:"raw",description:"filter marks the value as being \"safe\", which means that in an environment with automatic escaping enabled this variable will not be escaped if raw is the last filter applied to it."};const replace={prefix:"replace",body:"replace('${search}' : '${replace}')",text:"replace('search' : 'replace')",description:"filter formats a given string by replacing the placeholders."};const reverse={text:"reverse",body:"reverse",description:"filter reverses a sequence, a mapping, or a string"};const round={prefix:"round",body:"${0} | round(1, '${floor}')",text:"round",description:"filter rounds a number to a given precision"};const slice={prefix:"slice",body:"slice(${start}, ${length})",text:"slice(start, length)",description:"filter extracts a slice of a sequence, a mapping, or a string"};const sort={text:"sort",body:"sort",description:"filter sorts an array"};const split={prefix:"split",body:"split('$1')",text:"split('')",description:"filter splits a string by the given delimiter and returns a list of strings"};const striptags={text:"striptags",body:"striptags",description:"filter strips SGML/XML tags and replace adjacent whitespace by one space"};const title={text:"title",body:"title",description:"filter returns a titlecased version of the value. Words will start with uppercase letters, all remaining characters are lowercase"};const trim={text:"trim",body:"trim",description:"filter strips whitespace (or other characters) from the beginning and end of a string"};const upper={text:"upper",body:"upper",description:"filter converts a value to uppercase"};const url_encode={text:"url_encode",body:"url_encode",description:"filter percent encodes a given string as URL segment or an array as query string"};var snippetsArr = {abs:abs,batch:batch,capitalize:capitalize,convert_encoding:convert_encoding,date:date,date_modify:date_modify,"default": {prefix:"default",body:"default('${default value}')",text:"default('default value')",description:"filter returns the passed default value if the value is undefined or empty, otherwise the value of the variable"},"escape": {text:"escape",body:"escape",description:"filter escapes a string for safe insertion into the final output. It supports different escaping strategies depending on the template context"},first:first,format:format,join:join,json_encode:json_encode,keys:keys,last:last,length:length,lower:lower,merge:merge,nl2br:nl2br,number_format:number_format,raw:raw,replace:replace,reverse:reverse,round:round,slice:slice,"slice [] notation": {prefix:"slice [] notation",body:"[${start}:${length}]",description:"filter extracts a slice of a sequence, a mapping, or a string"},sort:sort,split:split,striptags:striptags,title:title,trim:trim,"trim()": {prefix:"trim()",body:"trim('$1')",description:"filter strips whitespace (or other characters) from the beginning and end of a string"},upper:upper,url_encode:url_encode}; 12 | 13 | const attribute={prefix:"attribute",body:"{{ attribute($1) }}$2",description:"The attribute function can be used to access a \"dynamic\" attribute of a variable",example:""};const block={prefix:"block",body:"{{ block('${block name}') }}$1",description:"When a template uses inheritance and if you want to print a block multiple times, use the block function",example:""};const constant={prefix:"constant",body:"{{ constant('${const name}') }}$1",description:"constant returns the constant value for a given string",example:"{{ some_date | date(constant('DATE_W3C')) }}\n{{ constant('Namespace\\Classname::CONSTANT_NAME') }}"};const cycle={prefix:"cycle",body:"{{ cycle(${array}, ${position}) }}$1",description:"The cycle function cycles on an array of values",example:""};const date$1={prefix:"date",body:"{% set ${currentDate} = date($1) %}$2",description:"Converts an argument to a date to allow date comparison",example:"{% date() %}\n{% date('-2days') %}\n{% date('-2days', 'Europe/Paris') %}"};const dump={prefix:"dump",body:"{{ dump(${array}) }}$1",description:"(function) dumps information about a template variable. This is mostly useful to debug a template that does not behave as expected by introspecting its variables",example:""};const include={prefix:"include function",body:"{{ include('${filename}.twig') }}$1",description:"(function) returns the rendered content of a template",example:""};const max={prefix:"max",body:"{% set ${result} = max(${array}) %}$1",description:"(function) returns the biggest value of a sequence or a set of values",example:"{{ max(1, 3, 2) }}\n{# returns \"3\" #}\n\n{{ max({2: \"e\", 3: \"a\", 1: \"b\", 5: \"d\", 4: \"c\"}) }}\n{# returns \"e\" #}"};const min={prefix:"min",body:"{% set ${result} = min(${array}) %}$1",description:"(function) returns the lowest value of a sequence or a set of values",example:"{{ min(1, 3, 2) }}\n{# returns \"1\" #}\n\n{{ min({2: \"e\", 3: \"a\", 1: \"b\", 5: \"d\", 4: \"c\"}) }}\n{# returns \"a\" #}"};const parent={prefix:"parent",body:"{{ parent() }}",description:"(function) return the content of the block as defined in the base template",example:"{% extends \"base.html\" %}\n\n{% block sidebar %}\n\t

Table Of Contents

\n\t...\n\t{{ parent() }}\n{% endblock %}"};const random={prefix:"random",hover:"",body:"{% set ${result} = random($1) %}$2",description:"(function) returns a random value depending on the supplied parameter type",example:"{{ random(['apple', 'orange', 'citrus']) }}\n{# example output: orange #}\n\n{{ random('ABC') }}\n{# example output: C #}\n\n{{ random() }}\n{# example output: 15386094 (works as the native PHP mt_rand function) #}\n\n{{ random(5) }}\n{# example output: 3 #}"};const range={prefix:"range",body:"range(${low}, ${high}, ${step})",description:"(function) Returns an array of elements from low to high, inclusive",example:"{% set result = range(0, 6, 2) %}\n{% dump(result) %}\n{# output: array(0, 2, 4, 6) #}"};const source={prefix:"source",body:"{{ source('${template}.twig') }}$1",description:"(function) returns the content of a template without rendering it",example:""};const template_from_string={prefix:"template_from_string",body:"{{ include(template_from_string(\"$1\")) }}$2",description:"(function) loads a template from a string",example:"{{ include(template_from_string(\"Hello {{ name }}\")) }}"};var functionsArr = {attribute:attribute,block:block,constant:constant,cycle:cycle,date:date$1,dump:dump,include:include,max:max,min:min,parent:parent,random:random,"range set": {prefix:"range set",body:"{% set ${result} = range(${low}, ${high}, ${step}) %}$1",description:"(function) Returns an array of elements from low to high, inclusive",example:"{% set result = range(0, 6, 2) %}\n{% dump(result) %}\n{# output: array(0, 2, 4, 6) #}"},range:range,source:source,template_from_string:template_from_string}; 14 | 15 | const show={prefix:"show",body:"{{ $1 }}",description:"{{ }}"};const execute={prefix:"execute",body:"{% $1 %}",description:"{% %}"};const autoescape={prefix:"autoescape",body:["{% autoescape %}","\t$1","{% endautoescape %}"],description:"Whether automatic escaping is enabled or not, you can mark a section of a template to be escaped or not by using the autoescape tag",example:"{% autoescape %}\n Everything will be automatically escaped in this block\n using the HTML strategy\n{% endautoescape %}\n\n{% autoescape 'html' %}\n Everything will be automatically escaped in this block\n using the HTML strategy\n{% endautoescape %}\n\n{% autoescape 'js' %}\n Everything will be automatically escaped in this block\n using the js escaping strategy\n{% endautoescape %}\n\n{% autoescape false %}\n Everything will be outputted as is in this block\n{% endautoescape %}"};const block$1={prefix:"block",body:["{% block ${name} %}","\t$1","{% endblock ${name} %}"],description:"When a template uses inheritance and if you want to print a block multiple times, use the block function"};const embed={prefix:"embed",body:["{% embed \"${filename}.twig\" %}","\t$1","{% endembed %}"],description:"The embed tag combines the behaviour of include and extends. It allows you to include another template's contents, just like include does. But it also allows you to override any block defined inside the included template, like when extending a template"};const filter={prefix:"filter",body:["{% filter ${filter name} %}","\t$1","{% endfilter %}"],description:"Filter sections allow you to apply regular Twig filters on a block of template data. Just wrap the code in the special filter section",example:"{% filter lower | escape %}\n SOME TEXT\n{% endfilter %}\n\n{# outputs \"<strong>some text</strong>\" #}"};const flush={prefix:"flush",body:["{% flush %}"],description:"The flush tag tells Twig to flush the output buffer",example:"{% flush %}"};const loop={prefix:"loop",body:"loop.",description:"special variables inside of a for loop block"};const _self={prefix:"_self",body:"_self",description:"To import macros from the current file, use the special _self variable for the source"};const include$1={prefix:"include",body:"{% include \"${filename}.twig\" %}",description:"The include statement includes a template and returns the rendered content of that file into the current namespace"};const macro={prefix:"macro",body:["{% macro ${name}($1) %}","\t$2","{% endmacro %}"],description:"Twig snippets"};const sandbox={prefix:"sandbox",body:["{% sandbox %}","\t$1","{% endsandbox %}"],description:"The sandbox tag can be used to enable the sandboxing mode for an included template, when sandboxing is not enabled globally for the Twig environment"};const set={prefix:"set",body:["{% set ${name} = ${value} %}$1"],description:"Assign values to variables"};const spaceless={prefix:"spaceless",body:["{% spaceless %}","\t$1","{% endspaceless %}"],description:"Use the spaceless tag to remove whitespace between HTML tags, not whitespace within HTML tags or whitespace in plain text"};const use={prefix:"use",body:"{% use \"${filename}.twig\" %}",description:"Twig snippets"};const verbatim={prefix:"verbatim",body:["{% verbatim %}","\t$1","{% endverbatim %}"],description:"The verbatim tag marks sections as being raw text that should not be parsed. For example to put Twig syntax as example into a template you can use this snippet"};var twigArr = {show:show,execute:execute,autoescape:autoescape,block:block$1,"do": {prefix:"do",body:["{% do $1 %}"],description:"The do tag works exactly like the regular variable expression ({{ ... }}) just that it doesn't print anything",example:"{% do 1 + 2 %}"},embed:embed,"extends": {prefix:"extends",body:"{% extends \"${filename}.twig\" %}",description:"Twig snippets"},filter:filter,flush:flush,"for": {prefix:"for",body:["{% for ${row} in ${array} %}","\t$1","{% endfor %}"],description:"Loop over each item in a sequence"},"for if": {prefix:"for if",body:["{% for ${row} in ${array} if ${condition} %}","\t$1","{% endfor %}"],description:"Loop over each item in a sequence"},"for else": {prefix:"for else",body:["{% for ${row} in ${array} %}","\t$1","{% else %}","\t$2","{% endfor %}"],description:"Loop over each item in a sequence"},"for if else": {prefix:"for if else",body:["{% for ${row} in ${array} if ${condition} %}","\t$1","{% else %}","\t$2","{% endfor %}"],description:"Loop over each item in a sequence"},loop:loop,"if": {prefix:"if",body:["{% if ${condition} %}","\t$1","{% endif %}"],description:"The if statement in Twig is comparable with the if statements of PHP"},"if else": {prefix:"if else",body:["{% if ${condition} %}","\t$1","{% else %}","\t$2","{% endif %}"],description:"The if statement in Twig is comparable with the if statements of PHP"},"else": {prefix:"else",body:"{% else %}",description:"The if statement in Twig is comparable with the if statements of PHP"},"else if": {prefix:"else if",body:"{% elseif ${condition} %}",description:"The if statement in Twig is comparable with the if statements of PHP"},"import": {prefix:"import",body:"{% import \"${filename}.twig\" as ${alias}%}",description:"Twig supports putting often used code into macros. These macros can go into different templates and get imported from there."},_self:_self,include:include$1,macro:macro,sandbox:sandbox,set:set,"set block": {prefix:"set (block)",body:["{% set ${name} %}","\t$1","{% endset %}"],description:"Inside code blocks you can also assign values to variables. Assignments use the set tag and can have multiple targets"},spaceless:spaceless,use:use,verbatim:verbatim}; 16 | 17 | const editor = vscode__default['default'].workspace.getConfiguration('editor'); 18 | const config = vscode__default['default'].workspace.getConfiguration('twig-language-2'); 19 | 20 | function createHover(snippet, type) { 21 | const example = typeof snippet.example == 'undefined' ? '' : snippet.example; 22 | const description = typeof snippet.description == 'undefined' ? '' : snippet.description; 23 | return new vscode__default['default'].Hover({ 24 | language: type, 25 | value: description + '\n\n' + example 26 | }); 27 | } 28 | 29 | function prettyDiff(document, range) { 30 | const result = []; 31 | let output = ""; 32 | let options = prettydiff__default['default'].options; 33 | 34 | let tabSize = editor.tabSize; 35 | let indentChar = " "; 36 | 37 | if (config.tabSize > 0) { 38 | tabSize = config.tabSize; 39 | } 40 | 41 | if (config.indentStyle == "tab") { 42 | tabSize = 0; 43 | indentChar = "\t"; 44 | } 45 | 46 | options.source = document.getText(range); 47 | options.mode = 'beautify'; 48 | options.language = 'html'; 49 | options.lexer = 'markup'; 50 | options.brace_line = config.braceLine; 51 | options.brace_padding = config.bracePadding; 52 | options.brace_style = config.braceStyle; 53 | options.braces = config.braces; 54 | options.comment_line = config.commentLine; 55 | options.comments = config.comments; 56 | options.compressed_css = config.compressedCss; 57 | options.correct = config.correct; 58 | options.cssInsertLines = config.cssInsertLines; 59 | options.else_line = config.elseLine; 60 | options.end_comma = config.endComma; 61 | options.force_attribute = config.forceAttribute; 62 | options.force_indent = config.forceIndent; 63 | options.format_array = config.formatArray; 64 | options.format_object = config.formatObject; 65 | options.function_name = config.functionName; 66 | options.indent_level = config.indentLevel; 67 | options.indent_char = indentChar; 68 | options.indent_size = tabSize; 69 | options.method_chain = config.methodChain; 70 | options.never_flatten = config.neverFlatten; 71 | options.new_line = config.newLine; 72 | options.no_case_indent = config.noCaseIndent; 73 | options.no_lead_zero = config.noLeadZero; 74 | options.object_sort = config.objectSort; 75 | options.preserve = config.preserve; 76 | options.preserve_comment = config.preserveComment; 77 | options.quote_convert = config.quoteConvert; 78 | options.space = config.space; 79 | options.space_close = config.spaceSlose; 80 | options.tag_merge = config.tagMerge; 81 | options.tag_sort = config.tagSort; 82 | options.ternary_line = config.ternaryLine; 83 | options.unformatted = config.unformatted; 84 | options.variable_list = config.variableList; 85 | options.vertical = config.vertical; 86 | options.wrap = config.wrap; 87 | 88 | output = prettydiff__default['default'](); 89 | 90 | options.end = 0; 91 | options.start = 0; 92 | 93 | result.push(vscode__default['default'].TextEdit.replace(range, output)); 94 | return result; 95 | } 96 | function activate(context) { 97 | const active = vscode__default['default'].window.activeTextEditor; 98 | if (!active || !active.document) return 99 | 100 | registerDocType('twig'); 101 | 102 | function registerDocType(type) { 103 | if (config.hover === true) { 104 | context.subscriptions.push(vscode__default['default'].languages.registerHoverProvider(type, { 105 | provideHover(document, position) { 106 | const range = document.getWordRangeAtPosition(position); 107 | const word = document.getText(range); 108 | 109 | for (const snippet in snippetsArr) { 110 | if (snippetsArr[snippet].prefix == word || snippetsArr[snippet].hover == word) { 111 | return createHover(snippetsArr[snippet], type) 112 | } 113 | } 114 | 115 | for (const snippet in functionsArr) { 116 | if (functionsArr[snippet].prefix == word || functionsArr[snippet].hover == word) { 117 | return createHover(functionsArr[snippet], type) 118 | } 119 | } 120 | 121 | for (const snippet in twigArr) { 122 | if (twigArr[snippet].prefix == word || twigArr[snippet].hover == word) { 123 | return createHover(twigArr[snippet], type) 124 | } 125 | } 126 | } 127 | })); 128 | } 129 | 130 | if (config.formatting === true) { 131 | context.subscriptions.push(vscode__default['default'].languages.registerDocumentFormattingEditProvider(type, { 132 | provideDocumentFormattingEdits: function (document) { 133 | const start = new vscode__default['default'].Position(0, 0); 134 | 135 | const end = new vscode__default['default'].Position(document.lineCount - 1, document.lineAt(document.lineCount - 1).text.length); 136 | 137 | const rng = new vscode__default['default'].Range(start, end); 138 | return prettyDiff(document, rng); 139 | } 140 | })); 141 | 142 | context.subscriptions.push(vscode__default['default'].languages.registerDocumentRangeFormattingEditProvider(type, { 143 | provideDocumentRangeFormattingEdits: function (document, range) { 144 | let end = range.end; 145 | 146 | if (end.character === 0) { 147 | end = end.translate(-1, Number.MAX_VALUE); 148 | } else { 149 | end = end.translate(0, Number.MAX_VALUE); 150 | } 151 | 152 | const rng = new vscode__default['default'].Range(new vscode__default['default'].Position(range.start.line, 0), end); 153 | return prettyDiff(document, rng); 154 | } 155 | })); 156 | } 157 | } 158 | } 159 | 160 | exports.activate = activate; 161 | -------------------------------------------------------------------------------- /images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mblode/vscode-twig-language-2/f62292b533e7c3628c3039214edf45869f8d16c9/images/icon.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "twig-language-2", 3 | "displayName": "Twig Language 2", 4 | "description": "Snippets, Syntax Highlighting, Hover, and Formatting for Twig", 5 | "version": "0.9.4", 6 | "publisher": "mblode", 7 | "license": "MIT", 8 | "author": { 9 | "name": "Matthew Blode", 10 | "email": "m@blode.co", 11 | "url": "https://matthewblode.com" 12 | }, 13 | "homepage": "https://github.com/mblode/vscode-twig-language-2", 14 | "bugs": { 15 | "url": "https://github.com/mblode/vscode-twig-language-2/issues" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "https://github.com/mblode/vscode-twig-language-2.git" 20 | }, 21 | "icon": "images/icon.png", 22 | "engines": { 23 | "vscode": "^1.30.0" 24 | }, 25 | "categories": [ 26 | "Formatters", 27 | "Programming Languages", 28 | "Snippets", 29 | "Other" 30 | ], 31 | "keywords": [ 32 | "php", 33 | "twig", 34 | "snippets", 35 | "craft", 36 | "beautify" 37 | ], 38 | "activationEvents": [ 39 | "onLanguage:twig" 40 | ], 41 | "main": "./extension/index", 42 | "contributes": { 43 | "languages": [ 44 | { 45 | "id": "twig", 46 | "aliases": [ 47 | "HTML (Twig)", 48 | "twig" 49 | ], 50 | "extensions": [ 51 | ".twig", 52 | ".html.twig" 53 | ], 54 | "configuration": "./src/languages/twig.configuration.json" 55 | } 56 | ], 57 | "grammars": [ 58 | { 59 | "language": "twig", 60 | "scopeName": "text.html.twig", 61 | "path": "./src/syntaxes/twig.tmLanguage", 62 | "embeddedLanguages": { 63 | "source.json": "json", 64 | "source.css": "css", 65 | "source.css.scss": "scss", 66 | "source.js": "javascript", 67 | "source.ts": "typescript" 68 | } 69 | } 70 | ], 71 | "snippets": [ 72 | { 73 | "language": "twig", 74 | "path": "./src/snippets/snippets.json" 75 | } 76 | ], 77 | "configuration": { 78 | "type": "object", 79 | "title": "Twig Language 2", 80 | "properties": { 81 | "twig-language-2.hover": { 82 | "type": "boolean", 83 | "default": true, 84 | "description": "Whether to enable/disable Twig hover." 85 | }, 86 | "twig-language-2.formatting": { 87 | "type": "boolean", 88 | "default": true, 89 | "description": "Whether to enable/disable Twig PrettyDiff formatting." 90 | }, 91 | "twig-language-2.braceLine": { 92 | "type": "boolean", 93 | "default": false, 94 | "description": "If true an empty line will be inserted after opening curly braces and before closing curly braces." 95 | }, 96 | "twig-language-2.bracePadding": { 97 | "type": "boolean", 98 | "default": false, 99 | "description": "Inserts a space after the start of a container and before the end of the container if the contents of that container are not indented; such as: conditions, function arguments, and escaped sequences of template strings." 100 | }, 101 | "twig-language-2.braceStyle": { 102 | "type": "string", 103 | "enum": [ 104 | "collapse", 105 | "collapse-preserve-inline", 106 | "expand", 107 | "none" 108 | ], 109 | "default": "none", 110 | "description": "Emulates JSBeautify's brace_style option using existing Pretty Diff options." 111 | }, 112 | "twig-language-2.braces": { 113 | "type": "boolean", 114 | "default": false, 115 | "description": "Determines if opening curly braces will exist on the same line as their condition or be forced onto a new line." 116 | }, 117 | "twig-language-2.commentLine": { 118 | "type": "boolean", 119 | "default": false, 120 | "description": "If a blank new line should be forced above comments." 121 | }, 122 | "twig-language-2.comments": { 123 | "type": "boolean", 124 | "default": false, 125 | "description": "This will determine whether comments should always start at position 0 of each line or if comments should be indented according to the code." 126 | }, 127 | "twig-language-2.compressedCss": { 128 | "type": "boolean", 129 | "default": false, 130 | "description": "If CSS should be beautified in a style where the properties and values are minifed for faster reading of selectors." 131 | }, 132 | "twig-language-2.correct": { 133 | "type": "boolean", 134 | "default": false, 135 | "description": "Automatically correct some sloppiness in code." 136 | }, 137 | "twig-language-2.cssInsertLines": { 138 | "type": "boolean", 139 | "default": false, 140 | "description": "Inserts new line characters between every CSS code block." 141 | }, 142 | "twig-language-2.elseLine": { 143 | "type": "boolean", 144 | "default": false, 145 | "description": "If else_line is true then the keyword 'else' is forced onto a new line." 146 | }, 147 | "twig-language-2.endComma": { 148 | "type": "string", 149 | "enum": [ 150 | "always", 151 | "never", 152 | "none" 153 | ], 154 | "default": false, 155 | "description": "If there should be a trailing comma in arrays and objects. Value multiline only applies to modes beautify and diff." 156 | }, 157 | "twig-language-2.forceAttribute": { 158 | "type": "boolean", 159 | "default": false, 160 | "description": "If all markup attributes should be indented each onto their own line." 161 | }, 162 | "twig-language-2.forceIndent": { 163 | "type": "boolean", 164 | "default": false, 165 | "description": "Will force indentation upon all content and tags without regard for the creation of new text nodes." 166 | }, 167 | "twig-language-2.formatArray": { 168 | "type": "string", 169 | "enum": [ 170 | "default", 171 | "indent", 172 | "inline" 173 | ], 174 | "default": "default", 175 | "description": "Determines if all array indexes should be indented, never indented, or left to the default." 176 | }, 177 | "twig-language-2.formatObject": { 178 | "type": "string", 179 | "enum": [ 180 | "default", 181 | "indent", 182 | "inline" 183 | ], 184 | "default": "default", 185 | "description": "Determines if all object keys should be indented, never indented, or left to the default." 186 | }, 187 | "twig-language-2.functionName": { 188 | "type": "boolean", 189 | "default": false, 190 | "description": "If a space should follow a JavaScript function name." 191 | }, 192 | "twig-language-2.indentStyle": { 193 | "type": "string", 194 | "enum": [ 195 | "space", 196 | "tab" 197 | ], 198 | "default": "tab", 199 | "description": "Choose to indent using tabs or spaces. This formatter will not use the \"Editor: Insert Spaces\" setting, nor will it use the `indent_style` setting declared in `.editorconfig` files." 200 | }, 201 | "twig-language-2.indentLevel": { 202 | "type": "integer", 203 | "default": 0, 204 | "description": "How much indentation padding should be applied to beautification? This option is internally used for code that requires switching between libraries." 205 | }, 206 | "twig-language-2.tabSize": { 207 | "type": "integer", 208 | "default": 0, 209 | "description": "0 will default to the editor's tab size (`editor.tabSize`). This formatter will not use the `indent_size` setting declared in `.editorconfig` files." 210 | }, 211 | "twig-language-2.methodChain": { 212 | "type": "integer", 213 | "default": 0, 214 | "description": "When to break consecutively chained methods and properties onto separate lines. A negative value disables this option. A value of 0 ensures method chains are never broken." 215 | }, 216 | "twig-language-2.neverFlatten": { 217 | "type": "boolean", 218 | "default": false, 219 | "description": "If destructured lists in script should never be flattend." 220 | }, 221 | "twig-language-2.newLine": { 222 | "type": "boolean", 223 | "default": true, 224 | "description": "Insert an empty line at the end of output." 225 | }, 226 | "twig-language-2.noCaseIndent": { 227 | "type": "boolean", 228 | "default": false, 229 | "description": "If a case statement should receive the same indentation as the containing switch block." 230 | }, 231 | "twig-language-2.noLeadZero": { 232 | "type": "boolean", 233 | "default": false, 234 | "description": "Whether leading 0s in CSS values immediately preceeding a decimal should be removed or prevented." 235 | }, 236 | "twig-language-2.objectSort": { 237 | "type": "boolean", 238 | "default": false, 239 | "description": "Sorts markup attributes and properties by key name in script and style." 240 | }, 241 | "twig-language-2.preserve": { 242 | "type": "integer", 243 | "default": 2, 244 | "description": "The maximum number of consecutive empty lines to retain." 245 | }, 246 | "twig-language-2.preserveComment": { 247 | "type": "boolean", 248 | "default": false, 249 | "description": "Prevent comment reformatting due to option wrap." 250 | }, 251 | "twig-language-2.quoteConvert": { 252 | "type": "string", 253 | "enum": [ 254 | "double", 255 | "none", 256 | "single" 257 | ], 258 | "default": "none", 259 | "description": "If the quotes of script strings or markup attributes should be converted to single quotes or double quotes." 260 | }, 261 | "twig-language-2.space": { 262 | "type": "boolean", 263 | "default": true, 264 | "description": "Inserts a space following the function keyword for anonymous functions." 265 | }, 266 | "twig-language-2.spaceClose": { 267 | "type": "boolean", 268 | "default": false, 269 | "description": "Markup self-closing tags end will end with ' />' instead of '/>'." 270 | }, 271 | "twig-language-2.tagMerge": { 272 | "type": "boolean", 273 | "default": false, 274 | "description": "Allows immediately adjacement start and end markup tags of the same name to be combined into a single self-closing tag." 275 | }, 276 | "twig-language-2.tagSort": { 277 | "type": "boolean", 278 | "default": false, 279 | "description": "Sort child items of each respective markup parent element." 280 | }, 281 | "twig-language-2.ternaryLine": { 282 | "type": "boolean", 283 | "default": true, 284 | "description": "If ternary operators in JavaScript ? and : should remain on the same line." 285 | }, 286 | "twig-language-2.unformatted": { 287 | "type": "boolean", 288 | "default": false, 289 | "description": "If markup tags should have their insides preserved. This option is only available to markup and does not support child tokens that require a different lexer." 290 | }, 291 | "twig-language-2.variableList": { 292 | "type": "string", 293 | "enum": [ 294 | "each", 295 | "list", 296 | "none" 297 | ], 298 | "default": "none", 299 | "description": "If consecutive JavaScript variables should be merged into a comma separated list or if variables in a list should be separated." 300 | }, 301 | "twig-language-2.vertical": { 302 | "type": "boolean", 303 | "default": false, 304 | "description": "If lists of assignments and properties should be vertically aligned. This option is not used with the markup lexer." 305 | }, 306 | "twig-language-2.wrap": { 307 | "type": "integer", 308 | "default": 0, 309 | "description": "Character width limit before applying word wrap. A 0 value disables this option. A negative value concatenates script strings." 310 | } 311 | } 312 | } 313 | }, 314 | "capabilities": { 315 | "hoverProvider": "true" 316 | }, 317 | "scripts": { 318 | "start": "rollup -c", 319 | "build": "rollup -c", 320 | "watch": "rollup -c -w" 321 | }, 322 | "devDependencies": { 323 | "@types/mocha": "^8.0.3", 324 | "@types/node": "^14.6.0", 325 | "eslint": "^7.7.0", 326 | "eslint-config-prettier": "^6.11.0", 327 | "typescript": "^4.0.2", 328 | "vscode": "^1.1.37" 329 | }, 330 | "dependencies": { 331 | "prettydiff": "^101.2.6", 332 | "rollup": "^2.26.5", 333 | "rollup-plugin-babel": "^4.4.0", 334 | "rollup-plugin-json": "^4.0.0" 335 | } 336 | } 337 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import json from 'rollup-plugin-json'; 2 | 3 | export default [ 4 | { 5 | input: 'src/extension.js', 6 | output: { 7 | file: 'extension/index.js', 8 | format: 'cjs' 9 | }, 10 | plugins: [ 11 | json({ 12 | // All JSON files will be parsed by default, 13 | // but you can also specifically include/exclude files 14 | exclude: ['node_modules/**'], 15 | 16 | // for tree-shaking, properties will be declared as 17 | // variables, using either `var` or `const` 18 | preferConst: true, // Default: false 19 | 20 | // specify indentation for the generated default export — 21 | // defaults to '\t' 22 | indent: ' ', 23 | 24 | // ignores indent and generates the smallest code 25 | compact: true, // Default: false 26 | 27 | // generate a named export for every property of the JSON object 28 | namedExports: true // Default: true 29 | }) 30 | ] 31 | }, 32 | ] 33 | -------------------------------------------------------------------------------- /src/extension.js: -------------------------------------------------------------------------------- 1 | import vscode from 'vscode' 2 | import prettydiff from 'prettydiff' 3 | import snippetsArr from './hover/filters.json' 4 | import functionsArr from './hover/functions.json' 5 | import twigArr from './hover/twig.json' 6 | 7 | const editor = vscode.workspace.getConfiguration('editor'); 8 | const config = vscode.workspace.getConfiguration('twig-language-2'); 9 | 10 | function createHover(snippet, type) { 11 | const example = typeof snippet.example == 'undefined' ? '' : snippet.example 12 | const description = typeof snippet.description == 'undefined' ? '' : snippet.description 13 | return new vscode.Hover({ 14 | language: type, 15 | value: description + '\n\n' + example 16 | }); 17 | } 18 | 19 | function prettyDiff(document, range) { 20 | const result = []; 21 | let output = ""; 22 | let options = prettydiff.options; 23 | 24 | let tabSize = editor.tabSize; 25 | let indentChar = " "; 26 | 27 | if (config.tabSize > 0) { 28 | tabSize = config.tabSize; 29 | } 30 | 31 | if (config.indentStyle == "tab") { 32 | tabSize = 0; 33 | indentChar = "\t"; 34 | } 35 | 36 | options.source = document.getText(range); 37 | options.mode = 'beautify'; 38 | options.language = 'html'; 39 | options.lexer = 'markup'; 40 | options.brace_line = config.braceLine; 41 | options.brace_padding = config.bracePadding; 42 | options.brace_style = config.braceStyle; 43 | options.braces = config.braces; 44 | options.comment_line = config.commentLine; 45 | options.comments = config.comments; 46 | options.compressed_css = config.compressedCss; 47 | options.correct = config.correct; 48 | options.cssInsertLines = config.cssInsertLines; 49 | options.else_line = config.elseLine; 50 | options.end_comma = config.endComma; 51 | options.force_attribute = config.forceAttribute; 52 | options.force_indent = config.forceIndent; 53 | options.format_array = config.formatArray; 54 | options.format_object = config.formatObject; 55 | options.function_name = config.functionName; 56 | options.indent_level = config.indentLevel; 57 | options.indent_char = indentChar; 58 | options.indent_size = tabSize; 59 | options.method_chain = config.methodChain; 60 | options.never_flatten = config.neverFlatten; 61 | options.new_line = config.newLine; 62 | options.no_case_indent = config.noCaseIndent; 63 | options.no_lead_zero = config.noLeadZero; 64 | options.object_sort = config.objectSort; 65 | options.preserve = config.preserve; 66 | options.preserve_comment = config.preserveComment; 67 | options.quote_convert = config.quoteConvert; 68 | options.space = config.space; 69 | options.space_close = config.spaceSlose; 70 | options.tag_merge = config.tagMerge; 71 | options.tag_sort = config.tagSort; 72 | options.ternary_line = config.ternaryLine; 73 | options.unformatted = config.unformatted; 74 | options.variable_list = config.variableList; 75 | options.vertical = config.vertical; 76 | options.wrap = config.wrap; 77 | 78 | output = prettydiff(); 79 | 80 | options.end = 0; 81 | options.start = 0; 82 | 83 | result.push(vscode.TextEdit.replace(range, output)); 84 | return result; 85 | }; 86 | 87 | function activate(context) { 88 | const active = vscode.window.activeTextEditor 89 | if (!active || !active.document) return 90 | 91 | registerDocType('twig'); 92 | 93 | function registerDocType(type) { 94 | if (config.hover === true) { 95 | context.subscriptions.push(vscode.languages.registerHoverProvider(type, { 96 | provideHover(document, position) { 97 | const range = document.getWordRangeAtPosition(position); 98 | const word = document.getText(range); 99 | 100 | for (const snippet in snippetsArr) { 101 | if (snippetsArr[snippet].prefix == word || snippetsArr[snippet].hover == word) { 102 | return createHover(snippetsArr[snippet], type) 103 | } 104 | } 105 | 106 | for (const snippet in functionsArr) { 107 | if (functionsArr[snippet].prefix == word || functionsArr[snippet].hover == word) { 108 | return createHover(functionsArr[snippet], type) 109 | } 110 | } 111 | 112 | for (const snippet in twigArr) { 113 | if (twigArr[snippet].prefix == word || twigArr[snippet].hover == word) { 114 | return createHover(twigArr[snippet], type) 115 | } 116 | } 117 | } 118 | })); 119 | } 120 | 121 | if (config.formatting === true) { 122 | context.subscriptions.push(vscode.languages.registerDocumentFormattingEditProvider(type, { 123 | provideDocumentFormattingEdits: function (document) { 124 | const start = new vscode.Position(0, 0) 125 | 126 | const end = new vscode.Position(document.lineCount - 1, document.lineAt(document.lineCount - 1).text.length); 127 | 128 | const rng = new vscode.Range(start, end) 129 | return prettyDiff(document, rng); 130 | } 131 | })); 132 | 133 | context.subscriptions.push(vscode.languages.registerDocumentRangeFormattingEditProvider(type, { 134 | provideDocumentRangeFormattingEdits: function (document, range) { 135 | let end = range.end 136 | 137 | if (end.character === 0) { 138 | end = end.translate(-1, Number.MAX_VALUE); 139 | } else { 140 | end = end.translate(0, Number.MAX_VALUE); 141 | } 142 | 143 | const rng = new vscode.Range(new vscode.Position(range.start.line, 0), end) 144 | return prettyDiff(document, rng); 145 | } 146 | })); 147 | } 148 | } 149 | } 150 | 151 | exports.activate = activate; 152 | -------------------------------------------------------------------------------- /src/hover/filters.json: -------------------------------------------------------------------------------- 1 | { 2 | "abs": { 3 | "text": "abs", 4 | "body": "abs", 5 | "description": "filter returns the absolute value" 6 | }, 7 | "batch": { 8 | "prefix": "batch", 9 | "body": "batch(${size}, ${fill})", 10 | "text": "batch(size, fill)", 11 | "description": 12 | "filter \"batches\" items by returning a list of lists with the given number of items. A second parameter can be provided and used to fill in missing items" 13 | }, 14 | "capitalize": { 15 | "text": "capitalize", 16 | "body": "capitalize", 17 | "description": 18 | "filter capitalizes a value. The first character will be uppercase, all others lowercase" 19 | }, 20 | "convert_encoding": { 21 | "prefix": "convert_encoding", 22 | "body": "convert_encoding('${to}', '${from}')", 23 | "text": "convert_encoding('to', 'from')", 24 | "description": 25 | "filter converts a string from one encoding to another. The first argument is the expected output charset and the second one is the input charset" 26 | }, 27 | "date": { 28 | "prefix": "date", 29 | "body": "date(\"${m/d/Y}\")", 30 | "text": "date(\"m/d/Y\")", 31 | "description": "filter formats a date to a given format" 32 | }, 33 | "date_modify": { 34 | "prefix": "date_modify", 35 | "body": "date_modify(\"${+1 day}\")", 36 | "text": "date_modify(\"+1 day\")", 37 | "description": "filter modifies a date with a given modifier string" 38 | }, 39 | "default": { 40 | "prefix": "default", 41 | "body": "default('${default value}')", 42 | "text": "default('default value')", 43 | "description": 44 | "filter returns the passed default value if the value is undefined or empty, otherwise the value of the variable" 45 | }, 46 | "escape": { 47 | "text": "escape", 48 | "body": "escape", 49 | "description": 50 | "filter escapes a string for safe insertion into the final output. It supports different escaping strategies depending on the template context" 51 | }, 52 | "first": { 53 | "text": "first", 54 | "body": "first", 55 | "description": 56 | "filter returns the first \"element\" of a sequence, a mapping, or a string" 57 | }, 58 | "format": { 59 | "prefix": "format", 60 | "body": "format($1)", 61 | "text": "format()", 62 | "description": 63 | "filter formats a given string by replacing the placeholders (placeholders follows the sprintf notation)", 64 | "example": 65 | "{% set foo = \"foo\" %}\n{{ \"I like %s and %s.\"| format(foo, \"bar\") }}\n\n{# outputs I like foo and bar #}" 66 | }, 67 | "join": { 68 | "prefix": "join", 69 | "body": "join${('optional')}", 70 | "text": "join", 71 | "description": 72 | "filter returns a string which is the concatenation of the items of a sequence" 73 | }, 74 | "json_encode": { 75 | "prefix": "json_encode", 76 | "body": "json_encode()", 77 | "text": "json_encode()", 78 | "description": 79 | "filter returns the JSON representation of a value. Internally, Twig uses the PHP json_encode function." 80 | }, 81 | "keys": { 82 | "text": "keys", 83 | "body": "keys", 84 | "description": 85 | "filter returns the keys of an array. It is useful when you want to iterate over the keys of an array" 86 | }, 87 | "last": { 88 | "text": "last", 89 | "body": "last", 90 | "description": 91 | "filter returns the last \"element\" of a sequence, a mapping, or a string" 92 | }, 93 | "length": { 94 | "text": "length", 95 | "body": "length", 96 | "description": 97 | "filter returns the number of items of a sequence or mapping, or the length of a string" 98 | }, 99 | "lower": { 100 | "text": "lower", 101 | "body": "lower", 102 | "description": "filter converts a value to lowercase" 103 | }, 104 | "merge": { 105 | "prefix": "merge", 106 | "body": "merge(${array})", 107 | "text": "merge(array)", 108 | "description": "filter merges an array with another array" 109 | }, 110 | "nl2br": { 111 | "text": "nl2br", 112 | "body": "nl2br", 113 | "description": 114 | "filter inserts HTML line breaks before all newlines in a string" 115 | }, 116 | "number_format": { 117 | "prefix": "number_format", 118 | "body": "number_format(${0}, '${.}', '${,}')", 119 | "text": "number_format", 120 | "description": 121 | "filter formats numbers. It is a wrapper around PHP's number_format function" 122 | }, 123 | "raw": { 124 | "text": "raw", 125 | "body": "raw", 126 | "description": 127 | "filter marks the value as being \"safe\", which means that in an environment with automatic escaping enabled this variable will not be escaped if raw is the last filter applied to it." 128 | }, 129 | "replace": { 130 | "prefix": "replace", 131 | "body": "replace('${search}' : '${replace}')", 132 | "text": "replace('search' : 'replace')", 133 | "description": 134 | "filter formats a given string by replacing the placeholders." 135 | }, 136 | "reverse": { 137 | "text": "reverse", 138 | "body": "reverse", 139 | "description": "filter reverses a sequence, a mapping, or a string" 140 | }, 141 | "round": { 142 | "prefix": "round", 143 | "body": "${0} | round(1, '${floor}')", 144 | "text": "round", 145 | "description": "filter rounds a number to a given precision" 146 | }, 147 | "slice": { 148 | "prefix": "slice", 149 | "body": "slice(${start}, ${length})", 150 | "text": "slice(start, length)", 151 | "description": 152 | "filter extracts a slice of a sequence, a mapping, or a string" 153 | }, 154 | "slice [] notation": { 155 | "prefix": "slice [] notation", 156 | "body": "[${start}:${length}]", 157 | "description": 158 | "filter extracts a slice of a sequence, a mapping, or a string" 159 | }, 160 | "sort": { 161 | "text": "sort", 162 | "body": "sort", 163 | "description": "filter sorts an array" 164 | }, 165 | "split": { 166 | "prefix": "split", 167 | "body": "split('$1')", 168 | "text": "split('')", 169 | "description": 170 | "filter splits a string by the given delimiter and returns a list of strings" 171 | }, 172 | "striptags": { 173 | "text": "striptags", 174 | "body": "striptags", 175 | "description": 176 | "filter strips SGML/XML tags and replace adjacent whitespace by one space" 177 | }, 178 | "title": { 179 | "text": "title", 180 | "body": "title", 181 | "description": 182 | "filter returns a titlecased version of the value. Words will start with uppercase letters, all remaining characters are lowercase" 183 | }, 184 | "trim": { 185 | "text": "trim", 186 | "body": "trim", 187 | "description": 188 | "filter strips whitespace (or other characters) from the beginning and end of a string" 189 | }, 190 | "trim()": { 191 | "prefix": "trim()", 192 | "body": "trim('$1')", 193 | "description": 194 | "filter strips whitespace (or other characters) from the beginning and end of a string" 195 | }, 196 | "upper": { 197 | "text": "upper", 198 | "body": "upper", 199 | "description": "filter converts a value to uppercase" 200 | }, 201 | "url_encode": { 202 | "text": "url_encode", 203 | "body": "url_encode", 204 | "description": 205 | "filter percent encodes a given string as URL segment or an array as query string" 206 | } 207 | } 208 | -------------------------------------------------------------------------------- /src/hover/functions.json: -------------------------------------------------------------------------------- 1 | { 2 | "attribute": { 3 | "prefix": "attribute", 4 | "body": "{{ attribute($1) }}$2", 5 | "description": 6 | "The attribute function can be used to access a \"dynamic\" attribute of a variable", 7 | "example": "" 8 | }, 9 | "block": { 10 | "prefix": "block", 11 | "body": "{{ block('${block name}') }}$1", 12 | "description": 13 | "When a template uses inheritance and if you want to print a block multiple times, use the block function", 14 | "example": "" 15 | }, 16 | "constant": { 17 | "prefix": "constant", 18 | "body": "{{ constant('${const name}') }}$1", 19 | "description": "constant returns the constant value for a given string", 20 | "example": 21 | "{{ some_date | date(constant('DATE_W3C')) }}\n{{ constant('Namespace\\Classname::CONSTANT_NAME') }}" 22 | }, 23 | "cycle": { 24 | "prefix": "cycle", 25 | "body": "{{ cycle(${array}, ${position}) }}$1", 26 | "description": "The cycle function cycles on an array of values", 27 | "example": "" 28 | }, 29 | "date": { 30 | "prefix": "date", 31 | "body": "{% set ${currentDate} = date($1) %}$2", 32 | "description": 33 | "Converts an argument to a date to allow date comparison", 34 | "example": 35 | "{% date() %}\n{% date('-2days') %}\n{% date('-2days', 'Europe/Paris') %}" 36 | }, 37 | "dump": { 38 | "prefix": "dump", 39 | "body": "{{ dump(${array}) }}$1", 40 | "description": 41 | "(function) dumps information about a template variable. This is mostly useful to debug a template that does not behave as expected by introspecting its variables", 42 | "example": "" 43 | }, 44 | "include": { 45 | "prefix": "include function", 46 | "body": "{{ include('${filename}.twig') }}$1", 47 | "description": "(function) returns the rendered content of a template", 48 | "example": "" 49 | }, 50 | "max": { 51 | "prefix": "max", 52 | "body": "{% set ${result} = max(${array}) %}$1", 53 | "description": 54 | "(function) returns the biggest value of a sequence or a set of values", 55 | "example": 56 | "{{ max(1, 3, 2) }}\n{# returns \"3\" #}\n\n{{ max({2: \"e\", 3: \"a\", 1: \"b\", 5: \"d\", 4: \"c\"}) }}\n{# returns \"e\" #}" 57 | }, 58 | "min": { 59 | "prefix": "min", 60 | "body": "{% set ${result} = min(${array}) %}$1", 61 | "description": 62 | "(function) returns the lowest value of a sequence or a set of values", 63 | "example": 64 | "{{ min(1, 3, 2) }}\n{# returns \"1\" #}\n\n{{ min({2: \"e\", 3: \"a\", 1: \"b\", 5: \"d\", 4: \"c\"}) }}\n{# returns \"a\" #}" 65 | }, 66 | "parent": { 67 | "prefix": "parent", 68 | "body": "{{ parent() }}", 69 | "description": 70 | "(function) return the content of the block as defined in the base template", 71 | "example": 72 | "{% extends \"base.html\" %}\n\n{% block sidebar %}\n\t

Table Of Contents

\n\t...\n\t{{ parent() }}\n{% endblock %}" 73 | }, 74 | "random": { 75 | "prefix": "random", 76 | "hover": "", 77 | "body": "{% set ${result} = random($1) %}$2", 78 | "description": 79 | "(function) returns a random value depending on the supplied parameter type", 80 | "example": 81 | "{{ random(['apple', 'orange', 'citrus']) }}\n{# example output: orange #}\n\n{{ random('ABC') }}\n{# example output: C #}\n\n{{ random() }}\n{# example output: 15386094 (works as the native PHP mt_rand function) #}\n\n{{ random(5) }}\n{# example output: 3 #}" 82 | }, 83 | "range set": { 84 | "prefix": "range set", 85 | "body": "{% set ${result} = range(${low}, ${high}, ${step}) %}$1", 86 | "description": 87 | "(function) Returns an array of elements from low to high, inclusive", 88 | "example": 89 | "{% set result = range(0, 6, 2) %}\n{% dump(result) %}\n{# output: array(0, 2, 4, 6) #}" 90 | }, 91 | "range": { 92 | "prefix": "range", 93 | "body": "range(${low}, ${high}, ${step})", 94 | "description": 95 | "(function) Returns an array of elements from low to high, inclusive", 96 | "example": 97 | "{% set result = range(0, 6, 2) %}\n{% dump(result) %}\n{# output: array(0, 2, 4, 6) #}" 98 | }, 99 | "source": { 100 | "prefix": "source", 101 | "body": "{{ source('${template}.twig') }}$1", 102 | "description": 103 | "(function) returns the content of a template without rendering it", 104 | "example": "" 105 | }, 106 | "template_from_string": { 107 | "prefix": "template_from_string", 108 | "body": "{{ include(template_from_string(\"$1\")) }}$2", 109 | "description": "(function) loads a template from a string", 110 | "example": "{{ include(template_from_string(\"Hello {{ name }}\")) }}" 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/hover/twig.json: -------------------------------------------------------------------------------- 1 | { 2 | "show": { 3 | "prefix": "show", 4 | "body": "{{ $1 }}", 5 | "description": "{{ }}" 6 | }, 7 | "execute": { 8 | "prefix": "execute", 9 | "body": "{% $1 %}", 10 | "description": "{% %}" 11 | }, 12 | "autoescape": { 13 | "prefix": "autoescape", 14 | "body": ["{% autoescape %}", "\t$1", "{% endautoescape %}"], 15 | "description": 16 | "Whether automatic escaping is enabled or not, you can mark a section of a template to be escaped or not by using the autoescape tag", 17 | "example": 18 | "{% autoescape %}\n Everything will be automatically escaped in this block\n using the HTML strategy\n{% endautoescape %}\n\n{% autoescape 'html' %}\n Everything will be automatically escaped in this block\n using the HTML strategy\n{% endautoescape %}\n\n{% autoescape 'js' %}\n Everything will be automatically escaped in this block\n using the js escaping strategy\n{% endautoescape %}\n\n{% autoescape false %}\n Everything will be outputted as is in this block\n{% endautoescape %}" 19 | }, 20 | "block": { 21 | "prefix": "block", 22 | "body": ["{% block ${name} %}", "\t$1", "{% endblock ${name} %}"], 23 | "description": 24 | "When a template uses inheritance and if you want to print a block multiple times, use the block function" 25 | }, 26 | "do": { 27 | "prefix": "do", 28 | "body": ["{% do $1 %}"], 29 | "description": 30 | "The do tag works exactly like the regular variable expression ({{ ... }}) just that it doesn't print anything", 31 | "example": "{% do 1 + 2 %}" 32 | }, 33 | "embed": { 34 | "prefix": "embed", 35 | "body": ["{% embed \"${filename}.twig\" %}", "\t$1", "{% endembed %}"], 36 | "description": 37 | "The embed tag combines the behaviour of include and extends. It allows you to include another template's contents, just like include does. But it also allows you to override any block defined inside the included template, like when extending a template" 38 | }, 39 | "extends": { 40 | "prefix": "extends", 41 | "body": "{% extends \"${filename}.twig\" %}", 42 | "description": "Twig snippets" 43 | }, 44 | "filter": { 45 | "prefix": "filter", 46 | "body": ["{% filter ${filter name} %}", "\t$1", "{% endfilter %}"], 47 | "description": 48 | "Filter sections allow you to apply regular Twig filters on a block of template data. Just wrap the code in the special filter section", 49 | "example": 50 | "{% filter lower | escape %}\n SOME TEXT\n{% endfilter %}\n\n{# outputs \"<strong>some text</strong>\" #}" 51 | }, 52 | "flush": { 53 | "prefix": "flush", 54 | "body": ["{% flush %}"], 55 | "description": "The flush tag tells Twig to flush the output buffer", 56 | "example": "{% flush %}" 57 | }, 58 | "for": { 59 | "prefix": "for", 60 | "body": ["{% for ${row} in ${array} %}", "\t$1", "{% endfor %}"], 61 | "description": "Loop over each item in a sequence" 62 | }, 63 | "for if": { 64 | "prefix": "for if", 65 | "body": [ 66 | "{% for ${row} in ${array} if ${condition} %}", 67 | "\t$1", 68 | "{% endfor %}" 69 | ], 70 | "description": "Loop over each item in a sequence" 71 | }, 72 | "for else": { 73 | "prefix": "for else", 74 | "body": [ 75 | "{% for ${row} in ${array} %}", 76 | "\t$1", 77 | "{% else %}", 78 | "\t$2", 79 | "{% endfor %}" 80 | ], 81 | "description": "Loop over each item in a sequence" 82 | }, 83 | "for if else": { 84 | "prefix": "for if else", 85 | "body": [ 86 | "{% for ${row} in ${array} if ${condition} %}", 87 | "\t$1", 88 | "{% else %}", 89 | "\t$2", 90 | "{% endfor %}" 91 | ], 92 | "description": "Loop over each item in a sequence" 93 | }, 94 | "loop": { 95 | "prefix": "loop", 96 | "body": "loop.", 97 | "description": "special variables inside of a for loop block" 98 | }, 99 | "if": { 100 | "prefix": "if", 101 | "body": ["{% if ${condition} %}", "\t$1", "{% endif %}"], 102 | "description": 103 | "The if statement in Twig is comparable with the if statements of PHP" 104 | }, 105 | "if else": { 106 | "prefix": "if else", 107 | "body": [ 108 | "{% if ${condition} %}", 109 | "\t$1", 110 | "{% else %}", 111 | "\t$2", 112 | "{% endif %}" 113 | ], 114 | "description": 115 | "The if statement in Twig is comparable with the if statements of PHP" 116 | }, 117 | "else": { 118 | "prefix": "else", 119 | "body": "{% else %}", 120 | "description": 121 | "The if statement in Twig is comparable with the if statements of PHP" 122 | }, 123 | "else if": { 124 | "prefix": "else if", 125 | "body": "{% elseif ${condition} %}", 126 | "description": 127 | "The if statement in Twig is comparable with the if statements of PHP" 128 | }, 129 | "import": { 130 | "prefix": "import", 131 | "body": "{% import \"${filename}.twig\" as ${alias}%}", 132 | "description": 133 | "Twig supports putting often used code into macros. These macros can go into different templates and get imported from there." 134 | }, 135 | "_self": { 136 | "prefix": "_self", 137 | "body": "_self", 138 | "description": 139 | "To import macros from the current file, use the special _self variable for the source" 140 | }, 141 | "include": { 142 | "prefix": "include", 143 | "body": "{% include \"${filename}.twig\" %}", 144 | "description": 145 | "The include statement includes a template and returns the rendered content of that file into the current namespace" 146 | }, 147 | "macro": { 148 | "prefix": "macro", 149 | "body": ["{% macro ${name}($1) %}", "\t$2", "{% endmacro %}"], 150 | "description": "Twig snippets" 151 | }, 152 | "sandbox": { 153 | "prefix": "sandbox", 154 | "body": ["{% sandbox %}", "\t$1", "{% endsandbox %}"], 155 | "description": 156 | "The sandbox tag can be used to enable the sandboxing mode for an included template, when sandboxing is not enabled globally for the Twig environment" 157 | }, 158 | "set": { 159 | "prefix": "set", 160 | "body": ["{% set ${name} = ${value} %}$1"], 161 | "description": "Assign values to variables" 162 | }, 163 | "set block": { 164 | "prefix": "set (block)", 165 | "body": ["{% set ${name} %}", "\t$1", "{% endset %}"], 166 | "description": 167 | "Inside code blocks you can also assign values to variables. Assignments use the set tag and can have multiple targets" 168 | }, 169 | "spaceless": { 170 | "prefix": "spaceless", 171 | "body": ["{% spaceless %}", "\t$1", "{% endspaceless %}"], 172 | "description": 173 | "Use the spaceless tag to remove whitespace between HTML tags, not whitespace within HTML tags or whitespace in plain text" 174 | }, 175 | "use": { 176 | "prefix": "use", 177 | "body": "{% use \"${filename}.twig\" %}", 178 | "description": "Twig snippets" 179 | }, 180 | "verbatim": { 181 | "prefix": "verbatim", 182 | "body": ["{% verbatim %}", "\t$1", "{% endverbatim %}"], 183 | "description": 184 | "The verbatim tag marks sections as being raw text that should not be parsed. For example to put Twig syntax as example into a template you can use this snippet" 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /src/languages/twig.configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | "blockComment": [ "{#", "#}" ] 4 | }, 5 | "brackets": [ 6 | ["{", "}"], 7 | ["[", "]"], 8 | ["(", ")"] 9 | ], 10 | "surroundingPairs": [ 11 | { "open": "'", "close": "'" }, 12 | { "open": "\"", "close": "\"" }, 13 | { "open": "{", "close": "}"}, 14 | { "open": "[", "close": "]"}, 15 | { "open": "(", "close": ")" }, 16 | { "open": "<", "close": ">" } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /src/snippets/snippets.json: -------------------------------------------------------------------------------- 1 | { 2 | "apply": { 3 | "prefix": "apply", 4 | "body": "{% apply %}\n\t$0\n{% endapply %}", 5 | "description": "apply", 6 | "scope": "text.html.twig" 7 | }, 8 | "asset": { 9 | "prefix": "asset", 10 | "body": 11 | "{% set asset = ${1:entry.assetFieldHandle}.one() %}\n\n{% if asset %}\n\t\"{{\n{% endif %}", 12 | "description": "asset", 13 | "scope": "text.html.twig" 14 | }, 15 | "assets": { 16 | "prefix": "assets", 17 | "body": 18 | "{% for image in craft.assets.\n\t.sourceId(\"${1:1}\")\n\t.kind(\"${2:image}\")\n\t.limit(${3:10})\n}).all() %}\n\t\"{{\n{% endfor %}\n$0", 19 | "description": "craft.assets", 20 | "scope": "text.html.twig" 21 | }, 22 | "autoescape": { 23 | "prefix": "autoescape", 24 | "body": "{% autoescape \"${1:type}\" %}\n\t$0\n{% endautoescape %}", 25 | "description": "autoescape", 26 | "scope": "text.html.twig" 27 | }, 28 | "blockb": { 29 | "prefix": "blockb", 30 | "body": "{% block ${1:name} %}\n\t$0\n{% endblock %}", 31 | "description": "block (block)", 32 | "scope": "text.html.twig" 33 | }, 34 | "block": { 35 | "prefix": "block", 36 | "body": "{% block ${1:name} %}$0{% endblock %}", 37 | "description": "block", 38 | "scope": "text.html.twig" 39 | }, 40 | "blockf": { 41 | "prefix": "blockf", 42 | "body": "{{ block(\"${1:name}\") }}$0", 43 | "description": "blockf", 44 | "scope": "text.html.twig" 45 | }, 46 | "cache": { 47 | "prefix": "cache", 48 | "body": "{% cache %}\n\t$1\n{% endcache %}\n$0", 49 | "description": "cache", 50 | "scope": "text.html.twig" 51 | }, 52 | "case": { 53 | "prefix": "case", 54 | "body": "{% case \"${1:value}\" %}\n\t$0", 55 | "description": "case", 56 | "scope": "text.html.twig" 57 | }, 58 | "children": { 59 | "prefix": "children", 60 | "body": "{% children %}$0", 61 | "description": "children", 62 | "scope": "text.html.twig" 63 | }, 64 | "ceil": { 65 | "prefix": "ceil", 66 | "body": "ceil($1)$0", 67 | "description": "ceil", 68 | "scope": "text.html.twig" 69 | }, 70 | "formlogin": { 71 | "prefix": "formlogin", 72 | "body": 73 | "
\n\t{{ csrfInput() }}\n\t\n\n\t

\n\t\n\n\t

\n\t\n\n\t\n\n\t\n\n\t{% if errorMessage is defined %}\n\t\t

{{ errorMessage }}

\n\t{% endif %}\n
\n\n

Forgot your password?

", 74 | "description": "craft.user - example login form", 75 | "scope": "text.html.twig" 76 | }, 77 | "formuserprofile": { 78 | "prefix": "formuserprofile", 79 | "body": 80 | "
\n\t{{ csrfInput() }}\n\t\n\t{{ redirectInput(\"users/\"~currentUser.username) }}\n\t\n\n\t\n\t\n\n\t\n\t\n\n\t\n
", 81 | "description": "craft.user - example user profile form", 82 | "scope": "text.html.twig" 83 | }, 84 | 85 | "formuserregistration": { 86 | "prefix": "formuserregistration", 87 | "body": 88 | "
\n\t{{ csrfInput() }}\n\t\n\t{{ redirectInput(\"\") }}\n\n\t{% macro errorList(errors) %}\n\t\t{% if errors %}\n\t\t\t\n\t\t{% endif %}\n\t{% endmacro %}\n\n\t{% from _self import errorList %}\n\n\t

\n\t\n\n\t{% if user is defined %}\n\t\t{{ errorList(user.getErrors(\"username\")) }}\n\t{% endif %}\n\n\t

\n\t\n\n\t{% if user is defined %}\n\t\t{{ errorList(user.getErrors(\"email\")) }}\n\t{% endif %}\n\n\t

\n\t\n\n\t{% if user is defined %}\n\t\t{{ errorList(user.getErrors(\"password\")) }}\n\t{% endif %}\n\n\t\n
", 89 | "description": "craft.user - example user registration form", 90 | "scope": "text.html.twig" 91 | }, 92 | "formforgotpassword": { 93 | "prefix": "formforgotpassword", 94 | "body": 95 | "
\n\t{{ csrfInput() }}\n\t\n\t{{ redirectInput(\"\") }}\n\n\t

\n\t\n\n\t{% if errors is defined %}\n\t\t\n\t{% endif %}\n\n\t\n
", 96 | "description": "craft.user - example forgot password form", 97 | "scope": "text.html.twig" 98 | }, 99 | "formsetpassword": { 100 | "prefix": "formsetpassword", 101 | "body": 102 | "
\n\t{{ csrfInput() }}\n\t\n\t\n\t\n\n\t

\n\t\n\t{% if errors is defined %}\n\t\t\n\t{% endif %}\n\n\t\n
", 103 | "description": "craft.user - example set password form", 104 | "scope": "text.html.twig" 105 | }, 106 | "formsearch": { 107 | "prefix": "formsearch", 108 | "body": 109 | "
\n\t\n\t\n
", 110 | "description": "craft.entries - example search form", 111 | "scope": "text.html.twig" 112 | }, 113 | "formsearchresults": { 114 | "prefix": "formsearchresults", 115 | "body": 116 | "

Search Results

\n\n{% set query = craft.app.request.getParam(\"q\") %}\n{% set entries = craft.entries.search(query).orderBy(\"score\").all() %}\n\n{% if entries | length %}\n\t

{{ entries | length }} results:

\n\n\t\n{% else %}\n\t

Your search for “{{ query }}” didn’t return any results.

\n{% endif %}", 117 | "description": "craft.entries - example search results", 118 | "scope": "text.html.twig" 119 | }, 120 | "rss": { 121 | "prefix": "rss", 122 | "body": 123 | "\n\n\t\n\t\t{{ siteName }}\n\t\t{{ siteUrl }}\n\t\t\n\t\t{{ globals.siteDescription }}\n\t\ten-us\n\t\t{{ now | rss }}\n\t\t{{ now | rss }}\n\n\t\t{% for entry in craft.entries.all() %}\n\t\t\t\n\t\t\t\t{{ entry.title }}\n\t\t\t\t{{ entry.url }}\n\t\t\t\t{{ entry.postDate | rss }}\n\t\t\t\t{{ entry.author }}\n\t\t\t\t{{ entry.url }}\n\t\t\t\t\n\t\t\t\n\t\t{% endfor %}\n\t\n", 124 | "description": "craft.entries - example rss feed", 125 | "scope": "text.html.twig" 126 | }, 127 | "assetso": { 128 | "prefix": "assetso", 129 | "body": 130 | "{% set assets = craft.assets({\n\tsourceId: \"${1:1}\",\n\tkind: \"${2:image}\",\n\tlimit: ${3:10}\n}).all() %}\n\n{% for image in assets %}\n\t\"{{\n{% endfor %}\n$0", 131 | "description": "craft.assets - object syntax", 132 | "scope": "text.html.twig" 133 | }, 134 | "categorieso": { 135 | "prefix": "categorieso", 136 | "body": 137 | "{% set categories = craft.categories({\n\tgroup: \"${1:categoryGroupHandle}\",\n\tlimit: \"${2:11}\"\n}).all() %}\n\n", 138 | "description": "craft.categories - object syntax", 139 | "scope": "text.html.twig" 140 | }, 141 | "categories": { 142 | "prefix": "categories", 143 | "body": 144 | "", 145 | "description": "craft.categories", 146 | "scope": "text.html.twig" 147 | }, 148 | "entrieso": { 149 | "prefix": "entrieso", 150 | "body": 151 | "{% set entries = craft.entries({\n\tsection: \"${1:sectionName}\",\n\tlimit: \"${2:10}\"\n}).all() %}\n\n{% for entry in entries %}\n\t{{ entry.title }}\n{% endfor %}\n$0", 152 | "description": "craft.entries - object syntax", 153 | "scope": "text.html.twig" 154 | }, 155 | "entries": { 156 | "prefix": "entries", 157 | "body": 158 | "{% for entry in craft.entries\n\t.section(\"${1:sectionName}\")\n\t.limit(${2:10})\n\t.all()\n%}\n\t{{ entry.title }}\n{% endfor %}\n$0", 159 | "description": "craft.entries", 160 | "scope": "text.html.twig" 161 | }, 162 | "feed": { 163 | "prefix": "feed", 164 | "body": 165 | "{% set feedUrl = \"${1:http://feeds.feedburner.com/blogandtonic}\" %}\n{% set limit = ${2:10} %}\n{% set items = craft.feeds.getFeedItems(feedUrl, limit).all() %}\n\n{% for item in items %}\n\t
\n\t\t

{{ item.title }}

\n\t\t

{{ item.authors[0].name }}

\n\t\t

{{ item.date }}

\n\n\t\t{{ item.summary }}\n\t
\n{% endfor %}", 166 | "description": "feed", 167 | "scope": "text.html.twig" 168 | }, 169 | "t": { 170 | "prefix": "t", 171 | "body": "{{ $1 | t }}$0", 172 | "description": "translate with | t" 173 | }, 174 | "replace": { 175 | "prefix": "replace", 176 | "body": "{{ ${1:$TM_SELECTED_TEXT} | replace(\"search\", \"replace\") }}$0", 177 | "description": "replace with | replace(\"search\", \"replace\")" 178 | }, 179 | "replacex": { 180 | "prefix": "replacex", 181 | "body": 182 | "{{ ${1:$TM_SELECTED_TEXT} | replace(\"/(search)/i\", \"replace\") }}$0", 183 | "description": "replace regex with | replace(\"/(search)/i\", \"replace\")" 184 | }, 185 | "split": { 186 | "prefix": "split", 187 | "body": "{{ ${1:$TM_SELECTED_TEXT} | split(\"\\n\") }}$0", 188 | "description": "split on | split (\"\\n\")" 189 | }, 190 | "tagso": { 191 | "prefix": "tagso", 192 | "body": 193 | "{% set tags = craft.tags({\n\tgroup: \"${1:tagGroupHandle}\"\n}).all() %}\n\n\n$0", 194 | "description": "craft.tags - object syntax", 195 | "scope": "text.html.twig" 196 | }, 197 | "tags": { 198 | "prefix": "tags", 199 | "body": 200 | "\n$0", 201 | "description": "craft.tags", 202 | "scope": "text.html.twig" 203 | }, 204 | "userso": { 205 | "prefix": "userso", 206 | "body": 207 | "{% set users = craft.users({\n\tgroup: \"${1:userGroupHandle}\"\n}).all() %}\n\n{% for user in users %}\n\t{{ user.firstName }} {{ user.lastName }}\n{% endfor %}\n$0", 208 | "description": "craft.users - object syntax", 209 | "scope": "text.html.twig" 210 | }, 211 | "users": { 212 | "prefix": "users", 213 | "body": 214 | "{% for user in craft.users.group(\"${1:userGroupHandle}\").all() %}\n\t{{ user.firstName }} {{ user.lastName }}\n{% endfor %}\n$0", 215 | "description": "craft.users", 216 | "scope": "text.html.twig" 217 | }, 218 | "csrf": { 219 | "prefix": "csrf", 220 | "body": "{{ csrfInput() }}\n$0", 221 | "description": "csrf", 222 | "scope": "text.html.twig" 223 | }, 224 | "dd": { 225 | "prefix": "dd", 226 | "body": "
\n\t{{ dump($1) }}\n
\n{% exit %}$0", 227 | "description": "dump and die", 228 | "scope": "text.html.twig" 229 | }, 230 | "do": { 231 | "prefix": "do", 232 | "body": "{% do $1 %}$0", 233 | "description": "do", 234 | "scope": "text.html.twig" 235 | }, 236 | "dojs": { 237 | "prefix": "dojs", 238 | "body": "{% do view.registerJsFile \"${1:url}\" %}$0", 239 | "description": "do js", 240 | "scope": "text.html.twig" 241 | }, 242 | "docss": { 243 | "prefix": "docss", 244 | "body": "{% do view.registerCssFile \"${1:url}\" %}$0", 245 | "description": "do css", 246 | "scope": "text.html.twig" 247 | }, 248 | "dump": { 249 | "prefix": "dump", 250 | "body": "
\n\t{{ dump($1) }}\n
", 251 | "description": "dump", 252 | "scope": "text.html.twig" 253 | }, 254 | "else": { 255 | "prefix": "else", 256 | "body": "{% else %}\n\t$0", 257 | "description": "else", 258 | "scope": "text.html.twig" 259 | }, 260 | "elseif": { 261 | "prefix": "elseif", 262 | "body": "{% elseif %}\n\t$0", 263 | "description": "elseif", 264 | "scope": "text.html.twig" 265 | }, 266 | "embed": { 267 | "prefix": "embed", 268 | "body": "{% embed \"${1:template}\" %}\n\t$0\n{% endembed %}", 269 | "description": "embed", 270 | "scope": "text.html.twig" 271 | }, 272 | "endapply": { 273 | "prefix": "endapply", 274 | "body": "{% endapply %}$0", 275 | "description": "endapply", 276 | "scope": "text.html.twig" 277 | }, 278 | "endautoescape": { 279 | "prefix": "endautoescape", 280 | "body": "{% endautoescape %}$0", 281 | "description": "endautoescape", 282 | "scope": "text.html.twig" 283 | }, 284 | "endblock": { 285 | "prefix": "endblock", 286 | "body": "{% endblock %}$0", 287 | "description": "endblock", 288 | "scope": "text.html.twig" 289 | }, 290 | "endcache": { 291 | "prefix": "endcache", 292 | "body": "{% endcache %}$0", 293 | "description": "endcache", 294 | "scope": "text.html.twig" 295 | }, 296 | "endembed": { 297 | "prefix": "endembed", 298 | "body": "{% endembed %}$0", 299 | "description": "endembed", 300 | "scope": "text.html.twig" 301 | }, 302 | "endfilter": { 303 | "prefix": "endfilter", 304 | "body": "{% endfilter %}$0", 305 | "description": "endfilter", 306 | "scope": "text.html.twig" 307 | }, 308 | "endfor": { 309 | "prefix": "endfor", 310 | "body": "{% endfor %}$0", 311 | "description": "endfor", 312 | "scope": "text.html.twig" 313 | }, 314 | "endif": { 315 | "prefix": "endif", 316 | "body": "{% endif %}$0", 317 | "description": "endif", 318 | "scope": "text.html.twig" 319 | }, 320 | "endifchildren": { 321 | "prefix": "endifchildren", 322 | "body": "{% endifchildren %}$0", 323 | "description": "endifchildren", 324 | "scope": "text.html.twig" 325 | }, 326 | "endcss": { 327 | "prefix": "endcss", 328 | "body": "{% endcss %}$0", 329 | "description": "endcss", 330 | "scope": "text.html.twig" 331 | }, 332 | "endjs": { 333 | "prefix": "endjs", 334 | "body": "{% endjs %}$0", 335 | "description": "endjs", 336 | "scope": "text.html.twig" 337 | }, 338 | "endmacro": { 339 | "prefix": "endmacro", 340 | "body": "{% endmacro %}$0", 341 | "description": "endmacro", 342 | "scope": "text.html.twig" 343 | }, 344 | "endnav": { 345 | "prefix": "endnav", 346 | "body": "{% endnav %}$0", 347 | "description": "endnav", 348 | "scope": "text.html.twig" 349 | }, 350 | "endset": { 351 | "prefix": "endset", 352 | "body": "{% endset %}$0", 353 | "description": "endset", 354 | "scope": "text.html.twig" 355 | }, 356 | "endspaceless": { 357 | "prefix": "endspaceless", 358 | "body": "{% endspaceless %}$0", 359 | "description": "endspaceless", 360 | "scope": "text.html.twig" 361 | }, 362 | "endswitch": { 363 | "prefix": "endswitch", 364 | "body": "{% endswitch %}$0", 365 | "description": "endswitch", 366 | "scope": "text.html.twig" 367 | }, 368 | "endtrans": { 369 | "prefix": "endtrans", 370 | "body": "{% endtrans %}$0", 371 | "description": "endtrans", 372 | "scope": "text.html.twig" 373 | }, 374 | "endverbatim": { 375 | "prefix": "endverbatim", 376 | "body": "{% endverbatim %}$0", 377 | "description": "endverbatim", 378 | "scope": "text.html.twig" 379 | }, 380 | "exit": { 381 | "prefix": "exit", 382 | "body": "{% exit ${1:404} %}", 383 | "description": "exit", 384 | "scope": "text.html.twig" 385 | }, 386 | "extends": { 387 | "prefix": "extends", 388 | "body": "{% extends \"${1:template}\" %}$0", 389 | "description": "extends", 390 | "scope": "text.html.twig" 391 | }, 392 | "filterb": { 393 | "prefix": "filterb", 394 | "body": "{% filter ${1:name} %}\n\t$0\n{% endfilter %}", 395 | "description": "filter (block)", 396 | "scope": "text.html.twig" 397 | }, 398 | "filter": { 399 | "prefix": "filter", 400 | "body": "{% filter ${1:name} %}$0{% endfilter %}", 401 | "description": "filter", 402 | "scope": "text.html.twig" 403 | }, 404 | "floor": { 405 | "prefix": "floor", 406 | "body": "floor($1)$0", 407 | "description": "floor", 408 | "scope": "text.html.twig" 409 | }, 410 | "fore": { 411 | "prefix": "fore", 412 | "body": 413 | "{% for ${1:item} in ${2:items} %}\n\t$3\n{% else %}\n\t$0\n{% endfor %}", 414 | "description": "for ... else", 415 | "scope": "text.html.twig" 416 | }, 417 | "for": { 418 | "prefix": "for", 419 | "body": "{% for ${1:item} in ${2:items} %}\n\t$0\n{% endfor %}", 420 | "description": "for", 421 | "scope": "text.html.twig" 422 | }, 423 | "from": { 424 | "prefix": "from", 425 | "body": "{% from \"${1:template}\" import \"${2:macro}\" %}$0", 426 | "description": "from", 427 | "scope": "text.html.twig" 428 | }, 429 | "endbody": { 430 | "prefix": "endbody", 431 | "body": "{{ endBody() }}\n$0", 432 | "description": "endBody", 433 | "scope": "text.html.twig" 434 | }, 435 | "head": { 436 | "prefix": "head", 437 | "body": "{{ head() }}\n$0", 438 | "description": "head", 439 | "scope": "text.html.twig" 440 | }, 441 | "if": { 442 | "prefix": "if", 443 | "body": "{% if ${1:condition} %}$2{% endif %}\n$0", 444 | "description": "if", 445 | "scope": "text.html.twig" 446 | }, 447 | "ifb": { 448 | "prefix": "ifb", 449 | "body": "{% if ${1:condition} %}\n\t$0\n{% endif %}", 450 | "description": "if (block)", 451 | "scope": "text.html.twig" 452 | }, 453 | "ife": { 454 | "prefix": "ife", 455 | "body": "{% if ${1:condition} %}\n\t$2\n{% else %}\n\t$0\n{% endif %}", 456 | "description": "if ... else", 457 | "scope": "text.html.twig" 458 | }, 459 | "if1": { 460 | "prefix": "if", 461 | "body": "{% if ${1:condition} %}$0{% endif %}", 462 | "description": "if", 463 | "scope": "text.html.twig" 464 | }, 465 | "ifchildren": { 466 | "prefix": "ifchildren", 467 | "body": "{% ifchildren %}\n\t$1\n{% endifchildren %}\n$0", 468 | "description": "ifchildren", 469 | "scope": "text.html.twig" 470 | }, 471 | "import": { 472 | "prefix": "import", 473 | "body": "{% import \"${1:template}\" as ${2:name} %}$0", 474 | "description": "import", 475 | "scope": "text.html.twig" 476 | }, 477 | "importself": { 478 | "prefix": "importself", 479 | "body": "{% import _self as ${1:name} %}$0", 480 | "description": "importself", 481 | "scope": "text.html.twig" 482 | }, 483 | "inckv": { 484 | "prefix": "inckv", 485 | "body": 486 | "{% include \"${1:template}\" with {\n\t${2:key}: ${3:\"${4:value}\"}\n} %}\n$0", 487 | "description": "include w/ key/value", 488 | "scope": "text.html.twig" 489 | }, 490 | "include": { 491 | "prefix": "include", 492 | "body": "{% include \"${1:template}\" %}$0", 493 | "description": "include", 494 | "scope": "text.html.twig" 495 | }, 496 | "inc": { 497 | "prefix": "inc", 498 | "body": "{% include \"${1:template}\" %}$0", 499 | "description": "inc", 500 | "scope": "text.html.twig" 501 | }, 502 | "incp": { 503 | "prefix": "incp", 504 | "body": "{% include \"${1:template}\"${2: with ${3:params} }%}$0", 505 | "description": "include w/ params", 506 | "scope": "text.html.twig" 507 | }, 508 | "css1": { 509 | "prefix": "css", 510 | "body": "{% do view.registerCssFile(\"${1:/resources/css/global.css}\") %}\n$0", 511 | "description": "registerCssFile", 512 | "scope": "text.html.twig" 513 | }, 514 | "js": { 515 | "prefix": "js", 516 | "body": "{% js %}\n\t$1\n{% endjs %}\n$0", 517 | "description": "js", 518 | "scope": "text.html.twig" 519 | }, 520 | "js1": { 521 | "prefix": "js", 522 | "body": "{% do view.registerJsFile(\"${1:/resources/js/global.js}\") %}\n$0", 523 | "description": "registerJsFile", 524 | "scope": "text.html.twig" 525 | }, 526 | "css": { 527 | "prefix": "css", 528 | "body": "{% css %}\n\t$1\n{% endcss %}\n$0", 529 | "description": "css", 530 | "scope": "text.html.twig" 531 | }, 532 | "macro": { 533 | "prefix": "macro", 534 | "body": "{% macro ${1:name}(${2:params}) %}\n\t$0\n{% endmacro %}", 535 | "description": "macro", 536 | "scope": "text.html.twig" 537 | }, 538 | "matrix": { 539 | "prefix": "matrix", 540 | "body": 541 | "{% for block in ${1:entry.matrixFieldHandle}.all() %}\n\n\t{% if block.type == \"${2:blockHandle}\" %}\n\t\t{{ block.${3:fieldHandle} }}\n\t{% endif %}\n\n\t{% if block.type == \"${4:blockHandle}\" %}\n\t\t{{ block.${5:fieldHandle} }}\n\t{% endif %}\n\n{% endfor %}\n$0", 542 | "description": "matrix", 543 | "scope": "text.html.twig" 544 | }, 545 | "matrixif": { 546 | "prefix": "matrixif", 547 | "body": 548 | "{% for block in ${1:entry.matrixFieldHandle}.all() %}\n\n\t{% if block.type == \"${2:blockHandle}\" %}\n\t\t{{ block.${3:fieldHandle} }}\n\t{% endif %}\n\n\t{% if block.type == \"${4:blockHandle}\" %}\n\t\t{{ block.${5:fieldHandle} }}\n\t{% endif %}\n\n{% endfor %}\n$0", 549 | "description": "matrixif", 550 | "scope": "text.html.twig" 551 | }, 552 | "matrixifelse": { 553 | "prefix": "matrixifelse", 554 | "body": 555 | "{% for block in ${1:entry.matrixFieldHandle}.all() %}\n\n\t{% if block.type == \"${2:blockHandle}\" %}\n\n\t\t{{ block.${3:fieldHandle} }}\n\n\t{% elseif block.type == \"${4:blockHandle}\" %}\n\n\t\t$0\n\t\n\t{% endif %}\n\n{% endfor %}", 556 | "description": "matrixifelse", 557 | "scope": "text.html.twig" 558 | }, 559 | "matrixswitch": { 560 | "prefix": "matrixswitch", 561 | "body": 562 | "{% for block in ${1:entry.matrixFieldHandle}.all() %}\n\n\t{% switch block.type %}\n\n\t\t{% case \"${2:blockHandle}\" %}\n\n\t\t\t{{ block.${3:fieldHandle} }}\n\n\t\t{% case \"${4:blockHandle}\" %}\n\n\t\t\t$0\n\n\t{% endswitch %}\n\n{% endfor %}", 563 | "description": "matrixswitch", 564 | "scope": "text.html.twig" 565 | }, 566 | "max": { 567 | "prefix": "max", 568 | "body": "max(${1:$2, $3})$0", 569 | "description": "max", 570 | "scope": "text.html.twig" 571 | }, 572 | "min": { 573 | "prefix": "min", 574 | "body": "min(${1:$2, $3})$0", 575 | "description": "min", 576 | "scope": "text.html.twig" 577 | }, 578 | "nav": { 579 | "prefix": "nav", 580 | "body": "{% nav ${1:item} in ${2:items} %}\n\t$3\n{% endnav %}\n$0", 581 | "description": "nav", 582 | "scope": "text.html.twig" 583 | }, 584 | "paginate": { 585 | "prefix": "paginate", 586 | "body": 587 | "{% paginate ${1:elements} as ${2:pageInfo}, ${3:pageEntries} %}\n\n{% for item in ${3:pageEntries} %}\n\t$0\n{% endfor %}\n\n{% if ${2:pageInfo}.prevUrl %}Previous Page{% endif %}\n{% if ${2:pageInfo}.nextUrl %}Next Page{% endif %}", 588 | "description": "paginate simple", 589 | "scope": "text.html.twig" 590 | }, 591 | "paginate1": { 592 | "prefix": "paginate", 593 | "body": 594 | "{# PAGINATION\n\t\t\nFor this pagination to work properly, we need to be sure to set\nthe paginateBase variable in the template we are including the \npagination in.\n\n{% set paginateBase = \"/blog/p\" %}\n#}\n\n{% if pageInfo.totalPages > 1 %}\n\n{% endif %}\n$0", 595 | "description": "paginate advanced", 596 | "scope": "text.html.twig" 597 | }, 598 | "redirect": { 599 | "prefix": "redirect", 600 | "body": 601 | "{% redirect \"${1:template/path or http://straightupcraft.com}\" %}\n$0", 602 | "description": "redirect", 603 | "scope": "text.html.twig" 604 | }, 605 | "getparam": { 606 | "prefix": "getparam", 607 | "body": 608 | "craft.app.request.getParam(${1:\"Query String or Post Variable Name\"})\n$0", 609 | "description": "request getParam", 610 | "scope": "text.html.twig" 611 | }, 612 | "getbodyparam": { 613 | "prefix": "getbodyparam", 614 | "body": "craft.app.request.getBodyParam(${1:\"postVariableName\"})\n$0", 615 | "description": "request getBodyParam", 616 | "scope": "text.html.twig" 617 | }, 618 | "getqueryparam": { 619 | "prefix": "getqueryparam", 620 | "body": "craft.app.request.getQueryParam(${1:\"queryStringName\"})\n$0", 621 | "description": "request getQueryParam", 622 | "scope": "text.html.twig" 623 | }, 624 | "getsegment": { 625 | "prefix": "getsegment", 626 | "body": "craft.app.request.getSegment(${1:2})\n$0", 627 | "description": "request getSegment", 628 | "scope": "text.html.twig" 629 | }, 630 | "requirelogin": { 631 | "prefix": "requirelogin", 632 | "body": "{% requireLogin %}\n$0", 633 | "description": "requireLogin", 634 | "scope": "text.html.twig" 635 | }, 636 | "requirepermission": { 637 | "prefix": "requirepermission", 638 | "body": "{% requirePermission \"${1:spendTheNight}\" %}\n$0", 639 | "description": "requirePermission", 640 | "scope": "text.html.twig" 641 | }, 642 | "round": { 643 | "prefix": "round", 644 | "body": "{{ $1 | round(1, 'floor') }}$0", 645 | "description": "round", 646 | "scope": "text.html.twig" 647 | }, 648 | "setb": { 649 | "prefix": "setb", 650 | "body": "{% set ${1:var} %}\n\t$0\n{% endset %}", 651 | "description": "set (block)", 652 | "scope": "text.html.twig" 653 | }, 654 | "set": { 655 | "prefix": "set", 656 | "body": "{% set ${1:var} = ${2:value} %}$0", 657 | "description": "set", 658 | "scope": "text.html.twig" 659 | }, 660 | "shuffle": { 661 | "prefix": "shuffle", 662 | "body": "shuffle($1)$0", 663 | "description": "shuffle", 664 | "scope": "text.html.twig" 665 | }, 666 | "random": { 667 | "prefix": "random", 668 | "body": "random($1)$0", 669 | "description": "random", 670 | "scope": "text.html.twig" 671 | }, 672 | "spaceless": { 673 | "prefix": "spaceless", 674 | "body": "{% spaceless %}\n\t$0\n{% endspaceless %}", 675 | "description": "spaceless", 676 | "scope": "text.html.twig" 677 | }, 678 | "switch": { 679 | "prefix": "switch", 680 | "body": 681 | "{% switch ${1:variable} %}\n\n\t{% case \"${2:value1}\" %}\n\t\n\n\t{% case \"${3:value2}\" %}\n\t\n\n\t{% default %}\n\t\n\n{% endswitch %}\n$0", 682 | "description": "switch", 683 | "scope": "text.html.twig" 684 | }, 685 | "trans": { 686 | "prefix": "trans", 687 | "body": "{% trans %}$0{% endtrans %}", 688 | "description": "trans", 689 | "scope": "text.html.twig" 690 | }, 691 | "urla": { 692 | "prefix": "urla", 693 | "body": 694 | "url(\"${1:path}\", ${2:{foo:\"1\", bar:\"2\"\\}}, ${3:\"http\"}, ${4:false})$0", 695 | "description": "url w/ arguments", 696 | "scope": "text.html.twig" 697 | }, 698 | "url": { 699 | "prefix": "url", 700 | "body": "url(\"${1:path}\")$0", 701 | "description": "url", 702 | "scope": "text.html.twig" 703 | }, 704 | "use": { 705 | "prefix": "use", 706 | "body": "{% use \"${1:template}\" %}$0", 707 | "description": "use", 708 | "scope": "text.html.twig" 709 | }, 710 | "verbatim": { 711 | "prefix": "verbatim", 712 | "body": "{% verbatim %}\n\t$0\n{% endverbatim %}", 713 | "description": "verbatim", 714 | "scope": "text.html.twig" 715 | } 716 | } 717 | -------------------------------------------------------------------------------- /src/syntaxes/twig.tmLanguage: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | fileTypes 6 | 7 | twig 8 | html.twig 9 | 10 | firstLineMatch 11 | <!(?i:DOCTYPE)|<(?i:html)|<\?(?i:php)|\{\{|\{%|\{# 12 | foldingStartMarker 13 | (?x) 14 | (<(?i:body|div|dl|fieldset|form|head|li|ol|script|select|style|table|tbody|tfoot|thead|tr|ul)\b.*?> 15 | |<!--(?!.*--\s*>) 16 | |^<!--\ \#tminclude\ (?>.*?-->)$ 17 | |\{%\s+(autoescape|block|embed|filter|for|if|macro|raw|sandbox|set|spaceless|trans|verbatim) 18 | ) 19 | foldingStopMarker 20 | (?x) 21 | (</(?i:body|div|dl|fieldset|form|head|li|ol|script|select|style|table|tbody|tfoot|thead|tr|ul)> 22 | |^(?!.*?<!--).*?--\s*> 23 | |^<!--\ end\ tminclude\ -->$ 24 | |\{%\s+end(autoescape|block|embed|filter|for|if|macro|raw|sandbox|set|spaceless|trans|verbatim) 25 | ) 26 | keyEquivalent 27 | ^~T 28 | name 29 | HTML (Twig) 30 | patterns 31 | 32 | 33 | begin 34 | (<)([a-zA-Z0-9:]++)(?=[^>]*></\2>) 35 | beginCaptures 36 | 37 | 1 38 | 39 | name 40 | punctuation.definition.tag.html 41 | 42 | 2 43 | 44 | name 45 | entity.name.tag.html 46 | 47 | 48 | end 49 | (>(<)/)(\2)(>) 50 | endCaptures 51 | 52 | 1 53 | 54 | name 55 | punctuation.definition.tag.html 56 | 57 | 2 58 | 59 | name 60 | meta.scope.between-tag-pair.html 61 | 62 | 3 63 | 64 | name 65 | entity.name.tag.html 66 | 67 | 4 68 | 69 | name 70 | punctuation.definition.tag.html 71 | 72 | 73 | name 74 | meta.tag.any.html 75 | patterns 76 | 77 | 78 | include 79 | #tag-stuff 80 | 81 | 82 | 83 | 84 | begin 85 | (<\?)(xml) 86 | captures 87 | 88 | 1 89 | 90 | name 91 | punctuation.definition.tag.html 92 | 93 | 2 94 | 95 | name 96 | entity.name.tag.xml.html 97 | 98 | 99 | end 100 | (\?>) 101 | name 102 | meta.tag.preprocessor.xml.html 103 | patterns 104 | 105 | 106 | include 107 | #tag-generic-attribute 108 | 109 | 110 | include 111 | #string-double-quoted 112 | 113 | 114 | include 115 | #string-single-quoted 116 | 117 | 118 | 119 | 120 | begin 121 | <!-- 122 | captures 123 | 124 | 0 125 | 126 | name 127 | punctuation.definition.comment.html 128 | 129 | 130 | end 131 | --\s*> 132 | name 133 | comment.block.html 134 | patterns 135 | 136 | 137 | match 138 | -- 139 | name 140 | invalid.illegal.bad-comments-or-CDATA.html 141 | 142 | 143 | include 144 | #embedded-code 145 | 146 | 147 | 148 | 149 | begin 150 | <! 151 | captures 152 | 153 | 0 154 | 155 | name 156 | punctuation.definition.tag.html 157 | 158 | 159 | end 160 | > 161 | name 162 | meta.tag.sgml.html 163 | patterns 164 | 165 | 166 | begin 167 | (?i:DOCTYPE) 168 | captures 169 | 170 | 1 171 | 172 | name 173 | entity.name.tag.doctype.html 174 | 175 | 176 | end 177 | (?=>) 178 | name 179 | meta.tag.sgml.doctype.html 180 | patterns 181 | 182 | 183 | match 184 | "[^">]*" 185 | name 186 | string.quoted.double.doctype.identifiers-and-DTDs.html 187 | 188 | 189 | 190 | 191 | begin 192 | \[CDATA\[ 193 | end 194 | ]](?=>) 195 | name 196 | constant.other.inline-data.html 197 | 198 | 199 | match 200 | (\s*)(?!--|>)\S(\s*) 201 | name 202 | invalid.illegal.bad-comments-or-CDATA.html 203 | 204 | 205 | 206 | 207 | include 208 | #embedded-code 209 | 210 | 211 | begin 212 | (?:^\s+)?(<)((?i:style))\b(?![^>]*/>) 213 | captures 214 | 215 | 1 216 | 217 | name 218 | punctuation.definition.tag.html 219 | 220 | 2 221 | 222 | name 223 | entity.name.tag.style.html 224 | 225 | 3 226 | 227 | name 228 | punctuation.definition.tag.html 229 | 230 | 231 | end 232 | (</)((?i:style))(>)(?:\s*\n)? 233 | name 234 | source.css.embedded.html 235 | patterns 236 | 237 | 238 | include 239 | #tag-stuff 240 | 241 | 242 | begin 243 | (>) 244 | beginCaptures 245 | 246 | 1 247 | 248 | name 249 | punctuation.definition.tag.html 250 | 251 | 252 | end 253 | (?=</(?i:style)) 254 | patterns 255 | 256 | 257 | include 258 | #embedded-code 259 | 260 | 261 | include 262 | source.css 263 | 264 | 265 | 266 | 267 | 268 | 269 | begin 270 | (?:^\s+)?(<)((?i:script))\b(?![^>]*/>) 271 | beginCaptures 272 | 273 | 1 274 | 275 | name 276 | punctuation.definition.tag.html 277 | 278 | 2 279 | 280 | name 281 | entity.name.tag.script.html 282 | 283 | 284 | end 285 | (?<=</(script|SCRIPT))(>)(?:\s*\n)? 286 | endCaptures 287 | 288 | 2 289 | 290 | name 291 | punctuation.definition.tag.html 292 | 293 | 294 | name 295 | source.js.embedded.html 296 | patterns 297 | 298 | 299 | include 300 | #tag-stuff 301 | 302 | 303 | begin 304 | (?<!</(?:script|SCRIPT))(>) 305 | captures 306 | 307 | 1 308 | 309 | name 310 | punctuation.definition.tag.html 311 | 312 | 2 313 | 314 | name 315 | entity.name.tag.script.html 316 | 317 | 318 | end 319 | (</)((?i:script)) 320 | patterns 321 | 322 | 323 | captures 324 | 325 | 1 326 | 327 | name 328 | punctuation.definition.comment.js 329 | 330 | 331 | match 332 | (//).*?((?=</script)|$\n?) 333 | name 334 | comment.line.double-slash.js 335 | 336 | 337 | begin 338 | /\* 339 | captures 340 | 341 | 0 342 | 343 | name 344 | punctuation.definition.comment.js 345 | 346 | 347 | end 348 | \*/|(?=</script) 349 | name 350 | comment.block.js 351 | 352 | 353 | include 354 | #php 355 | 356 | 357 | 358 | 359 | include 360 | #twig-print-tag 361 | 362 | 363 | include 364 | #twig-statement-tag 365 | 366 | 367 | include 368 | #twig-comment-tag 369 | 370 | 371 | 372 | 373 | include 374 | source.js 375 | 376 | 377 | 378 | 379 | 380 | 381 | begin 382 | (?ix) # Enable free spacing mode, case insensitive 383 | # Make sure our opening js tag has word boundaries 384 | (?<=\{\%\sjs\s\%\}|\{\%\sincludejs\s\%\}) 385 | 386 | comment 387 | Add JS support to set tags that use the pattern "css" in their name 388 | end 389 | (?ix)(?=\{\%\sendjs\s\%\}|\{\%\sendincludejs\s\%\}) 390 | name 391 | source.js.embedded.twig 392 | patterns 393 | 394 | 395 | include 396 | source.js 397 | 398 | 399 | 400 | 401 | begin 402 | (?ix) # Enable free spacing mode, case insensitive 403 | (?<=\{\%\scss\s\%\}|\{\%\sincludecss\s\%\}|\{\%\sincludehirescss\s\%\}) 404 | 405 | comment 406 | Add CSS support to set tags that use the pattern "css" in their name 407 | end 408 | (?ix)(?=\{\%\sendcss\s\%\}|\{\%\sendincludecss\s\%\}|\{\%\sendincludehirescss\s\%\}) 409 | name 410 | source.css.embedded.twig 411 | patterns 412 | 413 | 414 | include 415 | source.css 416 | 417 | 418 | 419 | 420 | begin 421 | (?ix) # Enable free spacing mode, case insensitive 422 | (?<=\{\%\sscss\s\%\}|\{\%\sincludescss\s\%\}|\{\%\sincludehiresscss\s\%\}) 423 | 424 | comment 425 | Add SCSS support to set tags that use the pattern "scss" in their name 426 | end 427 | (?ix)(?=\{\%\sendscss\s\%\}|\{\%\sendincludescss\s\%\}|\{\%\sendincludehiresscss\s\%\}) 428 | name 429 | source.css.scss.embedded.twig 430 | patterns 431 | 432 | 433 | include 434 | source.css.scss 435 | 436 | 437 | 438 | 439 | begin 440 | (</?)((?i:body|head|html)\b) 441 | captures 442 | 443 | 1 444 | 445 | name 446 | punctuation.definition.tag.html 447 | 448 | 2 449 | 450 | name 451 | entity.name.tag.structure.any.html 452 | 453 | 454 | end 455 | (>) 456 | name 457 | meta.tag.structure.any.html 458 | patterns 459 | 460 | 461 | include 462 | #tag-stuff 463 | 464 | 465 | 466 | 467 | begin 468 | (</?)((?i:address|blockquote|dd|div|dl|dt|fieldset|form|frame|frameset|h1|h2|h3|h4|h5|h6|iframe|noframes|object|ol|p|ul|applet|center|dir|hr|menu|pre)\b) 469 | beginCaptures 470 | 471 | 1 472 | 473 | name 474 | punctuation.definition.tag.begin.html 475 | 476 | 2 477 | 478 | name 479 | entity.name.tag.block.any.html 480 | 481 | 482 | end 483 | (>) 484 | endCaptures 485 | 486 | 1 487 | 488 | name 489 | punctuation.definition.tag.end.html 490 | 491 | 492 | name 493 | meta.tag.block.any.html 494 | patterns 495 | 496 | 497 | include 498 | #tag-stuff 499 | 500 | 501 | 502 | 503 | begin 504 | (</?)((?i:a|abbr|acronym|area|b|base|basefont|bdo|big|br|button|caption|cite|code|col|colgroup|del|dfn|em|font|head|html|i|img|input|ins|isindex|kbd|label|legend|li|link|map|meta|noscript|optgroup|option|param|q|s|samp|script|select|small|span|strike|strong|style|sub|sup|table|tbody|td|textarea|tfoot|th|thead|title|tr|tt|u|var)\b) 505 | beginCaptures 506 | 507 | 1 508 | 509 | name 510 | punctuation.definition.tag.begin.html 511 | 512 | 2 513 | 514 | name 515 | entity.name.tag.inline.any.html 516 | 517 | 518 | end 519 | ((?: ?/)?>) 520 | endCaptures 521 | 522 | 1 523 | 524 | name 525 | punctuation.definition.tag.end.html 526 | 527 | 528 | name 529 | meta.tag.inline.any.html 530 | patterns 531 | 532 | 533 | include 534 | #tag-stuff 535 | 536 | 537 | 538 | 539 | begin 540 | (</?)([a-zA-Z0-9:]+) 541 | beginCaptures 542 | 543 | 1 544 | 545 | name 546 | punctuation.definition.tag.begin.html 547 | 548 | 2 549 | 550 | name 551 | entity.name.tag.other.html 552 | 553 | 554 | end 555 | (>) 556 | endCaptures 557 | 558 | 1 559 | 560 | name 561 | punctuation.definition.tag.end.html 562 | 563 | 564 | name 565 | meta.tag.other.html 566 | patterns 567 | 568 | 569 | include 570 | #tag-stuff 571 | 572 | 573 | 574 | 575 | include 576 | #entities 577 | 578 | 579 | match 580 | <> 581 | name 582 | invalid.illegal.incomplete.html 583 | 584 | 585 | match 586 | < 587 | name 588 | invalid.illegal.bad-angle-bracket.html 589 | 590 | 591 | 592 | 593 | include 594 | #twig-print-tag 595 | 596 | 597 | include 598 | #twig-statement-tag 599 | 600 | 601 | include 602 | #twig-comment-tag 603 | 604 | 605 | 606 | repository 607 | 608 | embedded-code 609 | 610 | patterns 611 | 612 | 613 | include 614 | #ruby 615 | 616 | 617 | include 618 | #php 619 | 620 | 621 | 622 | 623 | include 624 | #twig-print-tag 625 | 626 | 627 | include 628 | #twig-statement-tag 629 | 630 | 631 | include 632 | #twig-comment-tag 633 | 634 | 635 | 636 | 637 | include 638 | #python 639 | 640 | 641 | 642 | entities 643 | 644 | patterns 645 | 646 | 647 | captures 648 | 649 | 1 650 | 651 | name 652 | punctuation.definition.entity.html 653 | 654 | 3 655 | 656 | name 657 | punctuation.definition.entity.html 658 | 659 | 660 | match 661 | (&)([a-zA-Z0-9]+|#[0-9]+|#x[0-9a-fA-F]+)(;) 662 | name 663 | constant.character.entity.html 664 | 665 | 666 | match 667 | & 668 | name 669 | invalid.illegal.bad-ampersand.html 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | twig-print-tag 678 | 679 | begin 680 | \{\{-? 681 | beginCaptures 682 | 683 | 0 684 | 685 | name 686 | punctuation.section.tag.twig 687 | 688 | 689 | end 690 | -?\}\} 691 | endCaptures 692 | 693 | 0 694 | 695 | name 696 | punctuation.section.tag.twig 697 | 698 | 699 | name 700 | meta.tag.template.value.twig 701 | patterns 702 | 703 | 704 | include 705 | #twig-constants 706 | 707 | 708 | include 709 | #twig-operators 710 | 711 | 712 | include 713 | #twig-functions-warg 714 | 715 | 716 | include 717 | #twig-functions 718 | 719 | 720 | include 721 | #twig-macros 722 | 723 | 724 | include 725 | #twig-objects 726 | 727 | 728 | include 729 | #twig-properties 730 | 731 | 732 | include 733 | #twig-filters-warg 734 | 735 | 736 | include 737 | #twig-filters 738 | 739 | 740 | include 741 | #twig-filters-warg-ud 742 | 743 | 744 | include 745 | #twig-filters-ud 746 | 747 | 748 | include 749 | #twig-strings 750 | 751 | 752 | include 753 | #twig-arrays 754 | 755 | 756 | include 757 | #twig-hashes 758 | 759 | 760 | 761 | 762 | 763 | twig-statement-tag 764 | 765 | begin 766 | \{%-? 767 | beginCaptures 768 | 769 | 0 770 | 771 | name 772 | punctuation.section.tag.twig 773 | 774 | 775 | end 776 | -?%\} 777 | endCaptures 778 | 779 | 0 780 | 781 | name 782 | punctuation.section.tag.twig 783 | 784 | 785 | name 786 | meta.tag.template.block.twig 787 | patterns 788 | 789 | 790 | include 791 | #twig-constants 792 | 793 | 794 | include 795 | #twig-keywords 796 | 797 | 798 | include 799 | #twig-operators 800 | 801 | 802 | include 803 | #twig-functions-warg 804 | 805 | 806 | include 807 | #twig-functions 808 | 809 | 810 | include 811 | #twig-macros 812 | 813 | 814 | include 815 | #twig-filters-warg 816 | 817 | 818 | include 819 | #twig-filters 820 | 821 | 822 | include 823 | #twig-filters-warg-ud 824 | 825 | 826 | include 827 | #twig-filters-ud 828 | 829 | 830 | include 831 | #twig-objects 832 | 833 | 834 | include 835 | #twig-properties 836 | 837 | 838 | include 839 | #twig-strings 840 | 841 | 842 | include 843 | #twig-arrays 844 | 845 | 846 | include 847 | #twig-hashes 848 | 849 | 850 | 851 | 852 | 853 | twig-comment-tag 854 | 855 | begin 856 | \{#-? 857 | beginCaptures 858 | 859 | 0 860 | 861 | name 862 | punctuation.definition.comment.begin.twig 863 | 864 | 865 | end 866 | -?#\} 867 | endCaptures 868 | 869 | 0 870 | 871 | name 872 | punctuation.definition.comment.end.twig 873 | 874 | 875 | name 876 | comment.block.twig 877 | 878 | 879 | 880 | twig-constants 881 | 882 | patterns 883 | 884 | 885 | 886 | match 887 | (?i)(?<=[\s\[\(\{:,])(?:true|false|null|none)(?=[\s\)\]\}\,]) 888 | name 889 | constant.language.twig 890 | 891 | 892 | 893 | match 894 | (?<=[\s\[\(\{:,]|\.\.|\*\*)[0-9]+(?:\.[0-9]+)?(?=[\s\)\]\}\,]|\.\.|\*\*) 895 | name 896 | constant.numeric.twig 897 | 898 | 899 | 900 | 901 | 902 | twig-operators 903 | 904 | patterns 905 | 906 | 907 | 908 | captures 909 | 910 | 1 911 | 912 | name 913 | keyword.operator.arithmetic.twig 914 | 915 | 916 | match 917 | (?<=\s)(\+|-|//?|%|\*\*?)(?=\s) 918 | 919 | 920 | 921 | 922 | captures 923 | 924 | 1 925 | 926 | name 927 | keyword.operator.assignment.twig 928 | 929 | 930 | match 931 | (?<=\s)(=|~)(?=\s) 932 | 933 | 934 | 935 | 936 | captures 937 | 938 | 1 939 | 940 | name 941 | keyword.operator.bitwise.twig 942 | 943 | 944 | match 945 | (?<=\s)(b-(?:and|or|xor))(?=\s) 946 | 947 | 948 | 949 | 950 | captures 951 | 952 | 1 953 | 954 | name 955 | keyword.operator.comparison.twig 956 | 957 | 958 | match 959 | (?<=\s)((?:!|=)=|<=?|>=?|(?:not )?in|is(?: not)?|(?:ends|starts) with|matches)(?=\s) 960 | 961 | 962 | 963 | 964 | captures 965 | 966 | 1 967 | 968 | name 969 | keyword.operator.logical.twig 970 | 971 | 972 | match 973 | (?<=\s)(\?|:|\?:|\?\?|and|not|or)(?=\s) 974 | 975 | 976 | 977 | 978 | captures 979 | 980 | 0 981 | 982 | name 983 | keyword.operator.other.twig 984 | 985 | 986 | match 987 | (?<=[a-zA-Z0-9_\x{7f}-\x{ff}\]\)'"])\.\.(?=[a-zA-Z0-9_\x{7f}-\x{ff}'"]) 988 | 989 | 990 | 991 | 992 | captures 993 | 994 | 0 995 | 996 | name 997 | keyword.operator.other.twig 998 | 999 | 1000 | match 1001 | (?<=[a-zA-Z0-9_\x{7f}-\x{ff}\]\}\)'"])\|(?=[a-zA-Z_\x{7f}-\x{ff}]) 1002 | 1003 | 1004 | 1005 | 1006 | 1007 | twig-objects 1008 | 1009 | captures 1010 | 1011 | 1 1012 | 1013 | name 1014 | variable.other.twig 1015 | 1016 | 1017 | match 1018 | (?<=[\s\{\[\(:,])([a-zA-Z_\x{7f}-\x{ff}][a-zA-Z0-9_\x{7f}-\x{ff}]*)(?=[\s\}\[\]\(\)\.\|,:]) 1019 | 1020 | 1021 | 1022 | twig-properties 1023 | 1024 | patterns 1025 | 1026 | 1027 | 1028 | captures 1029 | 1030 | 1 1031 | 1032 | name 1033 | punctuation.separator.property.twig 1034 | 1035 | 2 1036 | 1037 | name 1038 | variable.other.property.twig 1039 | 1040 | 1041 | match 1042 | (?x) 1043 | (?<=[a-zA-Z0-9_\x{7f}-\x{ff}]) 1044 | (\.)([a-zA-Z_\x{7f}-\x{ff}][a-zA-Z0-9_\x{7f}-\x{ff}]*) 1045 | (?=[\.\s\|\[\)\]\}:,]) 1046 | 1047 | 1048 | 1049 | 1050 | 1051 | begin 1052 | (?x) 1053 | (?<=[a-zA-Z0-9_\x{7f}-\x{ff}]) 1054 | (\.)([a-zA-Z_\x{7f}-\x{ff}][a-zA-Z0-9_\x{7f}-\x{ff}]*) 1055 | (\() 1056 | 1057 | beginCaptures 1058 | 1059 | 1 1060 | 1061 | name 1062 | punctuation.separator.property.twig 1063 | 1064 | 2 1065 | 1066 | name 1067 | variable.other.property.twig 1068 | 1069 | 3 1070 | 1071 | name 1072 | punctuation.definition.parameters.begin.twig 1073 | 1074 | 1075 | end 1076 | \) 1077 | endCaptures 1078 | 1079 | 0 1080 | 1081 | name 1082 | punctuation.definition.parameters.end.twig 1083 | 1084 | 1085 | patterns 1086 | 1087 | 1088 | include 1089 | #twig-constants 1090 | 1091 | 1092 | include 1093 | #twig-functions-warg 1094 | 1095 | 1096 | include 1097 | #twig-functions 1098 | 1099 | 1100 | include 1101 | #twig-macros 1102 | 1103 | 1104 | include 1105 | #twig-objects 1106 | 1107 | 1108 | include 1109 | #twig-properties 1110 | 1111 | 1112 | include 1113 | #twig-filters-warg 1114 | 1115 | 1116 | include 1117 | #twig-filters 1118 | 1119 | 1120 | include 1121 | #twig-filters-warg-ud 1122 | 1123 | 1124 | include 1125 | #twig-filters-ud 1126 | 1127 | 1128 | include 1129 | #twig-strings 1130 | 1131 | 1132 | include 1133 | #twig-arrays 1134 | 1135 | 1136 | contentName 1137 | meta.function.arguments.twig 1138 | 1139 | 1140 | 1141 | 1142 | captures 1143 | 1144 | 1 1145 | 1146 | name 1147 | punctuation.section.array.begin.twig 1148 | 1149 | 2 1150 | 1151 | name 1152 | variable.other.property.twig 1153 | 1154 | 3 1155 | 1156 | name 1157 | punctuation.section.array.end.twig 1158 | 1159 | 4 1160 | 1161 | name 1162 | punctuation.section.array.begin.twig 1163 | 1164 | 5 1165 | 1166 | name 1167 | variable.other.property.twig 1168 | 1169 | 6 1170 | 1171 | name 1172 | punctuation.section.array.end.twig 1173 | 1174 | 7 1175 | 1176 | name 1177 | punctuation.section.array.begin.twig 1178 | 1179 | 8 1180 | 1181 | name 1182 | variable.other.property.twig 1183 | 1184 | 9 1185 | 1186 | name 1187 | punctuation.section.array.end.twig 1188 | 1189 | 1190 | match 1191 | (?x) 1192 | (?<=[a-zA-Z0-9_\x{7f}-\x{ff}\]]) 1193 | (?: 1194 | (\[)('[a-zA-Z_\x{7f}-\x{ff}][a-zA-Z0-9_\x{7f}-\x{ff}]*')(\]) 1195 | |(\[)("[a-zA-Z_\x{7f}-\x{ff}][a-zA-Z0-9_\x{7f}-\x{ff}]*")(\]) 1196 | |(\[)([a-zA-Z_\x{7f}-\x{ff}][a-zA-Z0-9_\x{7f}-\x{ff}]*)(\]) 1197 | ) 1198 | 1199 | 1200 | 1201 | 1202 | 1203 | 1204 | twig-strings 1205 | 1206 | patterns 1207 | 1208 | 1209 | 1210 | begin 1211 | (?:(?<!\\)|(?<=\\\\))' 1212 | beginCaptures 1213 | 1214 | 0 1215 | 1216 | name 1217 | punctuation.definition.string.begin.twig 1218 | 1219 | 1220 | end 1221 | (?:(?<!\\)|(?<=\\\\))' 1222 | endCaptures 1223 | 1224 | 0 1225 | 1226 | name 1227 | punctuation.definition.string.end.twig 1228 | 1229 | 1230 | name 1231 | string.quoted.single.twig 1232 | 1233 | 1234 | 1235 | 1236 | begin 1237 | (?:(?<!\\)|(?<=\\\\))" 1238 | beginCaptures 1239 | 1240 | 0 1241 | 1242 | name 1243 | punctuation.definition.string.begin.twig 1244 | 1245 | 1246 | end 1247 | (?:(?<!\\)|(?<=\\\\))" 1248 | endCaptures 1249 | 1250 | 0 1251 | 1252 | name 1253 | punctuation.definition.string.end.twig 1254 | 1255 | 1256 | name 1257 | string.quoted.double.twig 1258 | 1259 | 1260 | 1261 | 1262 | 1263 | twig-arrays 1264 | 1265 | begin 1266 | (?<=[\s\(\{\[:,])\[ 1267 | beginCaptures 1268 | 1269 | 0 1270 | 1271 | name 1272 | punctuation.section.array.begin.twig 1273 | 1274 | 1275 | end 1276 | \] 1277 | endCaptures 1278 | 1279 | 0 1280 | 1281 | name 1282 | punctuation.section.array.end.twig 1283 | 1284 | 1285 | patterns 1286 | 1287 | 1288 | include 1289 | #twig-arrays 1290 | 1291 | 1292 | include 1293 | #twig-hashes 1294 | 1295 | 1296 | include 1297 | #twig-constants 1298 | 1299 | 1300 | include 1301 | #twig-operators 1302 | 1303 | 1304 | include 1305 | #twig-strings 1306 | 1307 | 1308 | include 1309 | #twig-functions-warg 1310 | 1311 | 1312 | include 1313 | #twig-functions 1314 | 1315 | 1316 | include 1317 | #twig-macros 1318 | 1319 | 1320 | include 1321 | #twig-objects 1322 | 1323 | 1324 | include 1325 | #twig-properties 1326 | 1327 | 1328 | include 1329 | #twig-filters-warg 1330 | 1331 | 1332 | include 1333 | #twig-filters 1334 | 1335 | 1336 | include 1337 | #twig-filters-warg-ud 1338 | 1339 | 1340 | include 1341 | #twig-filters-ud 1342 | 1343 | 1344 | match 1345 | , 1346 | name 1347 | punctuation.separator.object.twig 1348 | 1349 | 1350 | name 1351 | meta.array.twig 1352 | 1353 | 1354 | 1355 | twig-hashes 1356 | 1357 | begin 1358 | (?<=[\s\(\{\[:,])\{ 1359 | beginCaptures 1360 | 1361 | 0 1362 | 1363 | name 1364 | punctuation.section.hash.begin.twig 1365 | 1366 | 1367 | end 1368 | \} 1369 | endCaptures 1370 | 1371 | 0 1372 | 1373 | name 1374 | punctuation.section.hash.end.twig 1375 | 1376 | 1377 | patterns 1378 | 1379 | 1380 | include 1381 | #twig-hashes 1382 | 1383 | 1384 | include 1385 | #twig-arrays 1386 | 1387 | 1388 | include 1389 | #twig-constants 1390 | 1391 | 1392 | include 1393 | #twig-operators 1394 | 1395 | 1396 | include 1397 | #twig-strings 1398 | 1399 | 1400 | include 1401 | #twig-functions-warg 1402 | 1403 | 1404 | include 1405 | #twig-functions 1406 | 1407 | 1408 | include 1409 | #twig-macros 1410 | 1411 | 1412 | include 1413 | #twig-objects 1414 | 1415 | 1416 | include 1417 | #twig-properties 1418 | 1419 | 1420 | include 1421 | #twig-filters-warg 1422 | 1423 | 1424 | include 1425 | #twig-filters 1426 | 1427 | 1428 | include 1429 | #twig-filters-warg-ud 1430 | 1431 | 1432 | include 1433 | #twig-filters-ud 1434 | 1435 | 1436 | match 1437 | : 1438 | name 1439 | punctuation.separator.key-value.twig 1440 | 1441 | 1442 | match 1443 | , 1444 | name 1445 | punctuation.separator.object.twig 1446 | 1447 | 1448 | name 1449 | meta.hash.twig 1450 | 1451 | 1452 | 1453 | twig-keywords 1454 | 1455 | match 1456 | (?<=\s)((?:end)?(?:autoescape|block|embed|filter|for|if|macro|raw|sandbox|set|spaceless|trans|verbatim)|as|do|else|elseif|extends|flush|from|ignore missing|import|include|only|use|with)(?=\s) 1457 | name 1458 | keyword.control.twig 1459 | 1460 | 1461 | 1462 | twig-functions-warg 1463 | 1464 | begin 1465 | (?<=[\s\(\[\{:,])(attribute|block|constant|cycle|date|divisible by|dump|include|max|min|parent|random|range|same as|source|template_from_string)(\() 1466 | beginCaptures 1467 | 1468 | 1 1469 | 1470 | name 1471 | support.function.twig 1472 | 1473 | 2 1474 | 1475 | name 1476 | punctuation.definition.parameters.begin.twig 1477 | 1478 | 1479 | end 1480 | \) 1481 | endCaptures 1482 | 1483 | 0 1484 | 1485 | name 1486 | punctuation.definition.parameters.end.twig 1487 | 1488 | 1489 | patterns 1490 | 1491 | 1492 | include 1493 | #twig-constants 1494 | 1495 | 1496 | include 1497 | #twig-functions-warg 1498 | 1499 | 1500 | include 1501 | #twig-functions 1502 | 1503 | 1504 | include 1505 | #twig-macros 1506 | 1507 | 1508 | include 1509 | #twig-objects 1510 | 1511 | 1512 | include 1513 | #twig-properties 1514 | 1515 | 1516 | include 1517 | #twig-filters-warg 1518 | 1519 | 1520 | include 1521 | #twig-filters 1522 | 1523 | 1524 | include 1525 | #twig-filters-warg-ud 1526 | 1527 | 1528 | include 1529 | #twig-filters-ud 1530 | 1531 | 1532 | include 1533 | #twig-strings 1534 | 1535 | 1536 | include 1537 | #twig-arrays 1538 | 1539 | 1540 | contentName 1541 | meta.function.arguments.twig 1542 | 1543 | 1544 | 1545 | twig-functions 1546 | 1547 | captures 1548 | 1549 | 1 1550 | 1551 | name 1552 | support.function.twig 1553 | 1554 | 1555 | match 1556 | (?<=is\s)(defined|empty|even|iterable|odd) 1557 | 1558 | 1559 | 1560 | twig-macros 1561 | 1562 | begin 1563 | (?x) 1564 | (?<=[\s\(\[\{:,]) 1565 | ([a-zA-Z_\x{7f}-\x{ff}][a-zA-Z0-9_\x{7f}-\x{ff}]*) 1566 | (?: 1567 | (\.)([a-zA-Z_\x{7f}-\x{ff}][a-zA-Z0-9_\x{7f}-\x{ff}]*) 1568 | )? 1569 | (\() 1570 | 1571 | beginCaptures 1572 | 1573 | 1 1574 | 1575 | name 1576 | meta.function-call.twig 1577 | 1578 | 2 1579 | 1580 | name 1581 | punctuation.separator.property.twig 1582 | 1583 | 3 1584 | 1585 | name 1586 | variable.other.property.twig 1587 | 1588 | 4 1589 | 1590 | name 1591 | punctuation.definition.parameters.begin.twig 1592 | 1593 | 1594 | end 1595 | \) 1596 | endCaptures 1597 | 1598 | 0 1599 | 1600 | name 1601 | punctuation.definition.parameters.end.twig 1602 | 1603 | 1604 | patterns 1605 | 1606 | 1607 | include 1608 | #twig-constants 1609 | 1610 | 1611 | include 1612 | #twig-operators 1613 | 1614 | 1615 | include 1616 | #twig-functions-warg 1617 | 1618 | 1619 | include 1620 | #twig-functions 1621 | 1622 | 1623 | include 1624 | #twig-macros 1625 | 1626 | 1627 | include 1628 | #twig-objects 1629 | 1630 | 1631 | include 1632 | #twig-properties 1633 | 1634 | 1635 | include 1636 | #twig-filters-warg 1637 | 1638 | 1639 | include 1640 | #twig-filters 1641 | 1642 | 1643 | include 1644 | #twig-filters-warg-ud 1645 | 1646 | 1647 | include 1648 | #twig-filters-ud 1649 | 1650 | 1651 | include 1652 | #twig-strings 1653 | 1654 | 1655 | include 1656 | #twig-arrays 1657 | 1658 | 1659 | include 1660 | #twig-hashes 1661 | 1662 | 1663 | contentName 1664 | meta.function.arguments.twig 1665 | 1666 | 1667 | 1668 | 1669 | twig-filters-warg 1670 | 1671 | begin 1672 | (?<=(?:[a-zA-Z0-9_\x{7f}-\x{ff}\]\)\'\"]\|)|\{%\sfilter\s)(batch|convert_encoding|date|date_modify|default|e(?:scape)?|format|join|merge|number_format|replace|round|slice|split|trim)(\() 1673 | beginCaptures 1674 | 1675 | 1 1676 | 1677 | name 1678 | support.function.twig 1679 | 1680 | 2 1681 | 1682 | name 1683 | punctuation.definition.parameters.begin.twig 1684 | 1685 | 1686 | end 1687 | \) 1688 | endCaptures 1689 | 1690 | 0 1691 | 1692 | name 1693 | punctuation.definition.parameters.end.twig 1694 | 1695 | 1696 | patterns 1697 | 1698 | 1699 | include 1700 | #twig-constants 1701 | 1702 | 1703 | include 1704 | #twig-operators 1705 | 1706 | 1707 | include 1708 | #twig-functions-warg 1709 | 1710 | 1711 | include 1712 | #twig-functions 1713 | 1714 | 1715 | include 1716 | #twig-macros 1717 | 1718 | 1719 | include 1720 | #twig-objects 1721 | 1722 | 1723 | include 1724 | #twig-properties 1725 | 1726 | 1727 | include 1728 | #twig-filters-warg 1729 | 1730 | 1731 | include 1732 | #twig-filters 1733 | 1734 | 1735 | include 1736 | #twig-filters-warg-ud 1737 | 1738 | 1739 | include 1740 | #twig-filters-ud 1741 | 1742 | 1743 | include 1744 | #twig-strings 1745 | 1746 | 1747 | include 1748 | #twig-arrays 1749 | 1750 | 1751 | include 1752 | #twig-hashes 1753 | 1754 | 1755 | contentName 1756 | meta.function.arguments.twig 1757 | 1758 | 1759 | 1760 | twig-filters 1761 | 1762 | captures 1763 | 1764 | 1 1765 | 1766 | name 1767 | support.function.twig 1768 | 1769 | 1770 | match 1771 | (?<=(?:[a-zA-Z0-9_\x{7f}-\x{ff}\]\)\'\"]\|)|\{%\sfilter\s)(abs|capitalize|e(?:scape)?|first|join|(?:json|url)_encode|keys|last|length|lower|nl2br|number_format|raw|reverse|round|sort|striptags|title|trim|upper)(?=[\s\|\]\}\):,]|\.\.|\*\*) 1772 | 1773 | 1774 | 1775 | twig-filters-warg-ud 1776 | 1777 | begin 1778 | (?<=(?:[a-zA-Z0-9_\x{7f}-\x{ff}\]\)\'\"]\|)|\{%\sfilter\s)([a-zA-Z_\x{7f}-\x{ff}][a-zA-Z0-9_\x{7f}-\x{ff}]*)(\() 1779 | beginCaptures 1780 | 1781 | 1 1782 | 1783 | name 1784 | meta.function-call.other.twig 1785 | 1786 | 2 1787 | 1788 | name 1789 | punctuation.definition.parameters.begin.twig 1790 | 1791 | 1792 | end 1793 | \) 1794 | endCaptures 1795 | 1796 | 0 1797 | 1798 | name 1799 | punctuation.definition.parameters.end.twig 1800 | 1801 | 1802 | patterns 1803 | 1804 | 1805 | include 1806 | #twig-constants 1807 | 1808 | 1809 | include 1810 | #twig-functions-warg 1811 | 1812 | 1813 | include 1814 | #twig-functions 1815 | 1816 | 1817 | include 1818 | #twig-macros 1819 | 1820 | 1821 | include 1822 | #twig-objects 1823 | 1824 | 1825 | include 1826 | #twig-properties 1827 | 1828 | 1829 | include 1830 | #twig-filters-warg 1831 | 1832 | 1833 | include 1834 | #twig-filters 1835 | 1836 | 1837 | include 1838 | #twig-filters-warg-ud 1839 | 1840 | 1841 | include 1842 | #twig-filters-ud 1843 | 1844 | 1845 | include 1846 | #twig-strings 1847 | 1848 | 1849 | include 1850 | #twig-arrays 1851 | 1852 | 1853 | include 1854 | #twig-hashes 1855 | 1856 | 1857 | contentName 1858 | meta.function.arguments.twig 1859 | 1860 | 1861 | 1862 | twig-filters-ud 1863 | 1864 | captures 1865 | 1866 | 1 1867 | 1868 | name 1869 | meta.function-call.other.twig 1870 | 1871 | 1872 | match 1873 | (?<=(?:[a-zA-Z0-9_\x{7f}-\x{ff}\]\)\'\"]\|)|\{%\sfilter\s)([a-zA-Z_\x{7f}-\x{ff}][a-zA-Z0-9_\x{7f}-\x{ff}]*) 1874 | 1875 | 1876 | 1877 | 1878 | php 1879 | 1880 | begin 1881 | (?=(^\s*)?<\?) 1882 | end 1883 | (?!(^\s*)?<\?) 1884 | patterns 1885 | 1886 | 1887 | include 1888 | source.php 1889 | 1890 | 1891 | 1892 | python 1893 | 1894 | begin 1895 | (?:^\s*)<\?python(?!.*\?>) 1896 | end 1897 | \?>(?:\s*$\n)? 1898 | name 1899 | source.python.embedded.html 1900 | patterns 1901 | 1902 | 1903 | include 1904 | source.python 1905 | 1906 | 1907 | 1908 | ruby 1909 | 1910 | patterns 1911 | 1912 | 1913 | begin 1914 | <%+# 1915 | captures 1916 | 1917 | 0 1918 | 1919 | name 1920 | punctuation.definition.comment.erb 1921 | 1922 | 1923 | end 1924 | %> 1925 | name 1926 | comment.block.erb 1927 | 1928 | 1929 | begin 1930 | <%+(?!>)=? 1931 | captures 1932 | 1933 | 0 1934 | 1935 | name 1936 | punctuation.section.embedded.ruby 1937 | 1938 | 1939 | end 1940 | -?%> 1941 | name 1942 | source.ruby.embedded.html 1943 | patterns 1944 | 1945 | 1946 | captures 1947 | 1948 | 1 1949 | 1950 | name 1951 | punctuation.definition.comment.ruby 1952 | 1953 | 1954 | match 1955 | (#).*?(?=-?%>) 1956 | name 1957 | comment.line.number-sign.ruby 1958 | 1959 | 1960 | include 1961 | source.ruby 1962 | 1963 | 1964 | 1965 | 1966 | begin 1967 | <\?r(?!>)=? 1968 | captures 1969 | 1970 | 0 1971 | 1972 | name 1973 | punctuation.section.embedded.ruby.nitro 1974 | 1975 | 1976 | end 1977 | -?\?> 1978 | name 1979 | source.ruby.nitro.embedded.html 1980 | patterns 1981 | 1982 | 1983 | captures 1984 | 1985 | 1 1986 | 1987 | name 1988 | punctuation.definition.comment.ruby.nitro 1989 | 1990 | 1991 | match 1992 | (#).*?(?=-?\?>) 1993 | name 1994 | comment.line.number-sign.ruby.nitro 1995 | 1996 | 1997 | include 1998 | source.ruby 1999 | 2000 | 2001 | 2002 | 2003 | 2004 | string-double-quoted 2005 | 2006 | begin 2007 | " 2008 | beginCaptures 2009 | 2010 | 0 2011 | 2012 | name 2013 | punctuation.definition.string.begin.html 2014 | 2015 | 2016 | end 2017 | " 2018 | endCaptures 2019 | 2020 | 0 2021 | 2022 | name 2023 | punctuation.definition.string.end.html 2024 | 2025 | 2026 | name 2027 | string.quoted.double.html 2028 | patterns 2029 | 2030 | 2031 | include 2032 | #embedded-code 2033 | 2034 | 2035 | include 2036 | #entities 2037 | 2038 | 2039 | 2040 | string-single-quoted 2041 | 2042 | begin 2043 | ' 2044 | beginCaptures 2045 | 2046 | 0 2047 | 2048 | name 2049 | punctuation.definition.string.begin.html 2050 | 2051 | 2052 | end 2053 | ' 2054 | endCaptures 2055 | 2056 | 0 2057 | 2058 | name 2059 | punctuation.definition.string.end.html 2060 | 2061 | 2062 | name 2063 | string.quoted.single.html 2064 | patterns 2065 | 2066 | 2067 | include 2068 | #embedded-code 2069 | 2070 | 2071 | include 2072 | #entities 2073 | 2074 | 2075 | 2076 | tag-generic-attribute 2077 | 2078 | match 2079 | \b([a-zA-Z\-:]+) 2080 | name 2081 | entity.other.attribute-name.html 2082 | 2083 | tag-id-attribute 2084 | 2085 | begin 2086 | \b(id)\b\s*(=) 2087 | captures 2088 | 2089 | 1 2090 | 2091 | name 2092 | entity.other.attribute-name.id.html 2093 | 2094 | 2 2095 | 2096 | name 2097 | punctuation.separator.key-value.html 2098 | 2099 | 2100 | end 2101 | (?<='|") 2102 | name 2103 | meta.attribute-with-value.id.html 2104 | patterns 2105 | 2106 | 2107 | begin 2108 | " 2109 | beginCaptures 2110 | 2111 | 0 2112 | 2113 | name 2114 | punctuation.definition.string.begin.html 2115 | 2116 | 2117 | contentName 2118 | meta.toc-list.id.html 2119 | end 2120 | " 2121 | endCaptures 2122 | 2123 | 0 2124 | 2125 | name 2126 | punctuation.definition.string.end.html 2127 | 2128 | 2129 | name 2130 | string.quoted.double.html 2131 | patterns 2132 | 2133 | 2134 | include 2135 | #embedded-code 2136 | 2137 | 2138 | include 2139 | #entities 2140 | 2141 | 2142 | 2143 | 2144 | begin 2145 | ' 2146 | beginCaptures 2147 | 2148 | 0 2149 | 2150 | name 2151 | punctuation.definition.string.begin.html 2152 | 2153 | 2154 | contentName 2155 | meta.toc-list.id.html 2156 | end 2157 | ' 2158 | endCaptures 2159 | 2160 | 0 2161 | 2162 | name 2163 | punctuation.definition.string.end.html 2164 | 2165 | 2166 | name 2167 | string.quoted.single.html 2168 | patterns 2169 | 2170 | 2171 | include 2172 | #embedded-code 2173 | 2174 | 2175 | include 2176 | #entities 2177 | 2178 | 2179 | 2180 | 2181 | 2182 | tag-stuff 2183 | 2184 | patterns 2185 | 2186 | 2187 | include 2188 | #tag-id-attribute 2189 | 2190 | 2191 | include 2192 | #tag-generic-attribute 2193 | 2194 | 2195 | include 2196 | #string-double-quoted 2197 | 2198 | 2199 | include 2200 | #string-single-quoted 2201 | 2202 | 2203 | include 2204 | #embedded-code 2205 | 2206 | 2207 | 2208 | 2209 | scopeName 2210 | text.html.twig 2211 | uuid 2212 | C220B028-86FF-44CB-8A59-27937FC83730 2213 | 2214 | 2215 | --------------------------------------------------------------------------------