├── .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 | "vscode-journal-view.expanded": true 4 | } 5 | -------------------------------------------------------------------------------- /.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 | - Option to disable formatter 63 | 64 | ### Changed 65 | 66 | - Experiment with activation events 67 | - Fix configuration options 68 | 69 | ## [0.1.5] - 2017-11-13 70 | 71 | ### Added 72 | 73 | - Add options for configuration in VS Code 74 | - Format selection functionality 75 | - Add Prettty Diff 2 as an NPM package 76 | - Create hover features for VS Code 77 | 78 | ### Changed 79 | 80 | - Update readme 81 | - Fix gitignore 82 | - Change extension.js to add configuration to Pretty Diff 83 | 84 | ### Removed 85 | 86 | - Remove Pretty Diff 2 as a library 87 | 88 | ## [0.1.1] - 2017-11-12 89 | 90 | ### Added 91 | 92 | - Create a comprehensive readme file 93 | - Initial changelog 94 | - Add Craft/Twig snippets 95 | - Syntax highlighting for twig files 96 | - Initialise VS Code extension using Yeoman 97 | - Add icon for Twig Language extension 98 | - Use Pretty Diff 2 as the primary Twig formatter 99 | - Create extension.js file 100 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ### VSCode Twig Language 6 | 7 | - Syntax highlighting 8 | - Snippets 9 | - Emmet 10 | - Pretty Diff Formatting 11 | - Hover 12 | - HTML intellisense 13 | 14 | ## Installation 15 | 16 | Install through Visual Studio Code extensions. Search for `Twig Language` 17 | 18 | [Visual Studio Code Market Place: Twig Language](https://marketplace.visualstudio.com/items?itemName=mblode.twig-language) 19 | 20 | ## Documentation 21 | 22 | Twig Language is a Visual Studio Code extension that provides snippets, syntax highlighting, hover, and formatting for the Twig file format. 23 | 24 | ### Twig syntax highlighting and language support 25 | 26 | This extension provides language support for the Twig syntax. 27 | 28 | ### Code formatter/beautifier for Twig files 29 | 30 | Using PrettyDiff, this extension implements the only working code formatter for Twig files in VSCode. 31 | 32 | ### Information about Twig code on hover 33 | 34 | VSCode Twig language shows information about the symbol/object that's below the mouse cursor when you hover within Twig files. 35 | 36 | ### Craft CMS/Twig code snippets 37 | 38 | Adds a set of Craft CMS/Twig code snippets to use in your Twig templates. 39 | 40 | ### Generic Triggers 41 | 42 | ```twig 43 | 44 | do {% do ... %} 45 | extends {% extends 'template' %} 46 | from {% from 'template' import 'macro' %} 47 | import {% import 'template' as name %} 48 | importself {% import _self as name %} 49 | inc, include {% include 'template' %} 50 | incp {% include 'template' with params %} 51 | inckv {% include 'template' with { key: value } %} 52 | use {% use 'template' %} 53 | 54 | autoescape {% autoescape 'type' %}...{% endautoescape %} 55 | block, blockb {% block name %} ... {% endblock %} 56 | blockf {{ block('...') }} 57 | embed {% embed "template" %}...{% endembed %} 58 | filter, filterb {% filter name %} ... {% endfilter %} 59 | macro {% macro name(params) %}...{% endmacro %} 60 | set, setb {% set var = value %} 61 | spaceless {% spaceless %}...{% endspaceless %} 62 | verbatim {% verbatim %}...{% endverbatim %} 63 | 64 | if, ifb {% if condition %} ... {% endif %} 65 | ife {% if condition %} ... {% else %} ... {% endif %} 66 | for {% for item in seq %} ... {% endfor %} 67 | fore {% for item in seq %} ... {% else %} ... {% endfor %} 68 | 69 | else {% else %} 70 | endif {% endif %} 71 | endfor {% endfor %} 72 | endset {% endset %} 73 | endblock {% endblock %} 74 | endfilter {% endfilter %} 75 | endautoescape {% endautoescape %} 76 | endembed {% endembed %} 77 | endfilter {% endfilter %} 78 | endmacro {% endmacro %} 79 | endspaceless {% endspaceless %} 80 | endverbatim {% endverbatim %} 81 | 82 | ``` 83 | 84 | ### Craft Triggers 85 | 86 | ```twig 87 | asset craft.assets.one() 88 | assets, assetso craft.assets loop 89 | categories, categorieso craft.categories loop 90 | entries, entrieso craft.entries loop 91 | feed craft.app.feeds.getFeedItems loop 92 | t | t 93 | replace | replace('search', 'replace') 94 | replacex | replace('/(search)/i', 'replace') 95 | split | split('\n') 96 | tags, tagso craft.tags loop 97 | users, userso craft.users loop 98 | 99 | cache {% cache %}...{% endcache %} 100 | children {% children %} 101 | exit {% exit 404 %} 102 | ifchildren {% ifchildren %}...{% endifchildren %} 103 | css {% css %}...{% endcss %} 104 | registercssfile {% do view.registerCssFile("/resources/css/global.css") %} 105 | js {% js %}...{% endjs %} 106 | registerjsfile {% do view.registerJsFile("/resources/js/global.js") %} 107 | matrix, matrixif Basic Matrix field loop using if statements 108 | matrixifelse Basic Matrix field loop using if/elseif 109 | matrixswitch Basic Matrix field loop using switch 110 | nav {% nav item in items %}...{% endnav %} 111 | paginate Outputs example of pagination and prev/next links 112 | redirect {% redirect 'login' %} 113 | requirelogin {% requireLogin %} 114 | requirepermission {% requirePermission "spendTheNight" %} 115 | switch {% switch variable %}...{% endswitch %} 116 | 117 | csrf {{ csrfInput() }} 118 | endbody {{ endBody() }} 119 | head {{ head() }} 120 | 121 | getparam craft.app.request.getParam() 122 | getbodyparam craft.app.request.getBodyParam() 123 | getqueryparam craft.app.request.getQueryParam() 124 | getsegment craft.app.request.getSegment() 125 | 126 | case {% case "value" %} 127 | endcache {% endcache %} 128 | endifchildren {% endifchildren %} 129 | endcss {% endcss %} 130 | endjs {% endjs %} 131 | endnav {% endnav %} 132 | 133 | ceil ceil() 134 | floor floor() 135 | max max() 136 | min min() 137 | shuffle shuffle() 138 | random random() 139 | round num | round() 140 | url, urla url('path'), url('path', params, 'http', false) 141 | 142 | rss Example rss feed 143 | 144 | dd
{{ dump() }}
{% exit %} 145 | dump
{{ dump() }}
146 | ``` 147 | 148 | ### Example Forms 149 | 150 | ```twig 151 | 152 | formlogin Example login form 153 | formuserprofile Example user profile form 154 | formuserregistration Example user registration form 155 | formforgotpassword Example forgot password form 156 | formsetpassword Example set password form 157 | formsearch Example search form 158 | formsearchresults Example search form results 159 | 160 | ``` 161 | 162 | ### Reference Hints 163 | 164 | ```twig 165 | 166 | info All craft.assets properties and template tags 167 | info All craft.crategories properties and template tags 168 | info All craft.config properties and template tags 169 | info All craft.entries properties and template tags 170 | info All craft.feeds properties and template tags 171 | info All craft.fields properties and template tags 172 | info All craft.globals properties and template tags 173 | info All craft.request properties and template tags 174 | info All craft.sections properties and template tags 175 | info All craft.session properties and template tags 176 | info All craft.tags properties and template tags 177 | info All craft.users properties and template tags 178 | info All craft globals (site info, date, users, template tags) 179 | 180 | ``` 181 | -------------------------------------------------------------------------------- /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'); 19 | 20 | function createHover(snippet, type) { 21 | const example = 22 | typeof snippet.example == 'undefined' ? '' : snippet.example; 23 | const description = 24 | typeof snippet.description == 'undefined' ? '' : snippet.description; 25 | return new vscode__default['default'].Hover({ 26 | language: type, 27 | value: description + '\n\n' + example 28 | }) 29 | } 30 | 31 | function prettyDiff(document, range) { 32 | const result = []; 33 | let output = ""; 34 | let options = prettydiff__default['default'].options; 35 | 36 | let tabSize = editor.tabSize; 37 | let indentChar = " "; 38 | 39 | if (config.tabSize > 0) { 40 | tabSize = config.tabSize; 41 | } 42 | 43 | if (config.indentStyle == "tab") { 44 | tabSize = 0; 45 | indentChar = "\t"; 46 | } 47 | 48 | options.source = document.getText(range); 49 | options.mode = 'beautify'; 50 | options.language = 'html'; 51 | options.lexer = 'markup'; 52 | options.brace_line = config.braceLine; 53 | options.brace_padding = config.bracePadding; 54 | options.brace_style = config.braceStyle; 55 | options.braces = config.braces; 56 | options.comment_line = config.commentLine; 57 | options.comments = config.comments; 58 | options.compressed_css = config.compressedCss; 59 | options.correct = config.correct; 60 | options.cssInsertLines = config.cssInsertLines; 61 | options.else_line = config.elseLine; 62 | options.end_comma = config.endComma; 63 | options.force_attribute = config.forceAttribute; 64 | options.force_indent = config.forceIndent; 65 | options.format_array = config.formatArray; 66 | options.format_object = config.formatObject; 67 | options.function_name = config.functionName; 68 | options.indent_level = config.indentLevel; 69 | options.indent_char = indentChar; 70 | options.indent_size = tabSize; 71 | options.method_chain = config.methodChain; 72 | options.never_flatten = config.neverFlatten; 73 | options.new_line = config.newLine; 74 | options.no_case_indent = config.noCaseIndent; 75 | options.no_lead_zero = config.noLeadZero; 76 | options.object_sort = config.objectSort; 77 | options.preserve = config.preserve; 78 | options.preserve_comment = config.preserveComment; 79 | options.quote_convert = config.quoteConvert; 80 | options.space = config.space; 81 | options.space_close = config.spaceSlose; 82 | options.tag_merge = config.tagMerge; 83 | options.tag_sort = config.tagSort; 84 | options.ternary_line = config.ternaryLine; 85 | options.unformatted = config.unformatted; 86 | options.variable_list = config.variableList; 87 | options.vertical = config.vertical; 88 | options.wrap = config.wrap; 89 | 90 | output = prettydiff__default['default'](); 91 | 92 | options.end = 0; 93 | options.start = 0; 94 | 95 | result.push(vscode__default['default'].TextEdit.replace(range, output)); 96 | return result; 97 | } 98 | function activate(context) { 99 | const active = vscode__default['default'].window.activeTextEditor; 100 | if (!active || !active.document) return 101 | 102 | registerDocType('html'); 103 | 104 | function registerDocType(type) { 105 | if (config.hover === true) { 106 | context.subscriptions.push( 107 | vscode__default['default'].languages.registerHoverProvider(type, { 108 | provideHover(document, position) { 109 | const range = document.getWordRangeAtPosition(position); 110 | const word = document.getText(range); 111 | 112 | for (const snippet in snippetsArr) { 113 | if ( 114 | snippetsArr[snippet].prefix == word || 115 | snippetsArr[snippet].hover == word 116 | ) { 117 | return createHover(snippetsArr[snippet], type) 118 | } 119 | } 120 | 121 | for (const snippet in functionsArr) { 122 | if ( 123 | functionsArr[snippet].prefix == word || 124 | functionsArr[snippet].hover == word 125 | ) { 126 | return createHover(functionsArr[snippet], type) 127 | } 128 | } 129 | 130 | for (const snippet in twigArr) { 131 | if ( 132 | twigArr[snippet].prefix == word || 133 | twigArr[snippet].hover == word 134 | ) { 135 | return createHover(twigArr[snippet], type) 136 | } 137 | } 138 | } 139 | }) 140 | ); 141 | } 142 | 143 | if (config.formatting === true) { 144 | context.subscriptions.push( 145 | vscode__default['default'].languages.registerDocumentFormattingEditProvider(type, { 146 | provideDocumentFormattingEdits: function ( 147 | document 148 | ) { 149 | const start = new vscode__default['default'].Position(0, 0); 150 | const end = new vscode__default['default'].Position( 151 | document.lineCount - 1, 152 | document.lineAt(document.lineCount - 1).text.length 153 | ); 154 | const rng = new vscode__default['default'].Range(start, end); 155 | return prettyDiff(document, rng); 156 | } 157 | }) 158 | ); 159 | 160 | context.subscriptions.push( 161 | vscode__default['default'].languages.registerDocumentRangeFormattingEditProvider( 162 | type, 163 | { 164 | provideDocumentRangeFormattingEdits: function ( 165 | document, 166 | range 167 | ) { 168 | let end = range.end; 169 | 170 | if (end.character === 0) { 171 | end = end.translate(-1, Number.MAX_VALUE); 172 | } else { 173 | end = end.translate(0, Number.MAX_VALUE); 174 | } 175 | 176 | const rng = new vscode__default['default'].Range(new vscode__default['default'].Position(range.start.line, 0), end); 177 | return prettyDiff(document, rng); 178 | } 179 | } 180 | ) 181 | ); 182 | } 183 | } 184 | } 185 | 186 | exports.activate = activate; 187 | -------------------------------------------------------------------------------- /images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mblode/vscode-twig-language/a5ad3064e3512911e2e74c518228a809e3546474/images/icon.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "twig-language", 3 | "displayName": "Twig Language", 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", 14 | "bugs": { 15 | "url": "https://github.com/mblode/vscode-twig-language/issues" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "https://github.com/mblode/vscode-twig-language.git" 20 | }, 21 | "icon": "images/icon.png", 22 | "engines": { 23 | "vscode": "^1.30.0" 24 | }, 25 | "categories": [ 26 | "Programming Languages", 27 | "Snippets", 28 | "Other" 29 | ], 30 | "keywords": [ 31 | "php", 32 | "twig", 33 | "snippets", 34 | "craft", 35 | "beautify" 36 | ], 37 | "activationEvents": [ 38 | "*" 39 | ], 40 | "main": "./extension/index", 41 | "contributes": { 42 | "languages": [ 43 | { 44 | "id": "html", 45 | "aliases": [ 46 | "HTML", 47 | "twig" 48 | ], 49 | "extensions": [ 50 | ".twig", 51 | ".html", 52 | ".html.twig" 53 | ], 54 | "configuration": "./src/languages/twig.configuration.json" 55 | } 56 | ], 57 | "grammars": [ 58 | { 59 | "language": "html", 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": "html", 74 | "path": "./src/snippets/snippets.json" 75 | } 76 | ], 77 | "configuration": { 78 | "type": "object", 79 | "title": "Twig Language", 80 | "properties": { 81 | "twig-language.hover": { 82 | "type": "boolean", 83 | "default": true, 84 | "description": "Whether to enable/disable Twig hover." 85 | }, 86 | "twig-language.formatting": { 87 | "type": "boolean", 88 | "default": true, 89 | "description": "Whether to enable/disable Twig PrettyDiff formatting." 90 | }, 91 | "twig-language.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.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.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.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.commentLine": { 118 | "type": "boolean", 119 | "default": false, 120 | "description": "If a blank new line should be forced above comments." 121 | }, 122 | "twig-language.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.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.correct": { 133 | "type": "boolean", 134 | "default": false, 135 | "description": "Automatically correct some sloppiness in code." 136 | }, 137 | "twig-language.cssInsertLines": { 138 | "type": "boolean", 139 | "default": false, 140 | "description": "Inserts new line characters between every CSS code block." 141 | }, 142 | "twig-language.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.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.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.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.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.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.functionName": { 188 | "type": "boolean", 189 | "default": false, 190 | "description": "If a space should follow a JavaScript function name." 191 | }, 192 | "twig-language.indentStyle": { 193 | "type": "string", 194 | "enum": [ 195 | "space", 196 | "tab" 197 | ], 198 | "default": "tab", 199 | "description": "Choose to indent using tabs or spaces." 200 | }, 201 | "twig-language.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.tabSize": { 207 | "type": "integer", 208 | "default": 0, 209 | "description": "0 will default to the editor's tab size. Stores the number of 'inchar' values to comprise a single indentation." 210 | }, 211 | "twig-language.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.neverFlatten": { 217 | "type": "boolean", 218 | "default": false, 219 | "description": "If destructured lists in script should never be flattend." 220 | }, 221 | "twig-language.newLine": { 222 | "type": "boolean", 223 | "default": true, 224 | "description": "Insert an empty line at the end of output." 225 | }, 226 | "twig-language.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.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.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.preserve": { 242 | "type": "integer", 243 | "default": 2, 244 | "description": "The maximum number of consecutive empty lines to retain." 245 | }, 246 | "twig-language.preserveComment": { 247 | "type": "boolean", 248 | "default": false, 249 | "description": "Prevent comment reformatting due to option wrap." 250 | }, 251 | "twig-language.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.space": { 262 | "type": "boolean", 263 | "default": true, 264 | "description": "Inserts a space following the function keyword for anonymous functions." 265 | }, 266 | "twig-language.spaceClose": { 267 | "type": "boolean", 268 | "default": false, 269 | "description": "Markup self-closing tags end will end with ' />' instead of '/>'." 270 | }, 271 | "twig-language.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.tagSort": { 277 | "type": "boolean", 278 | "default": false, 279 | "description": "Sort child items of each respective markup parent element." 280 | }, 281 | "twig-language.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.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.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.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.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 | 4 | import snippetsArr from './hover/filters.json' 5 | import functionsArr from './hover/functions.json' 6 | import twigArr from './hover/twig.json' 7 | 8 | const editor = vscode.workspace.getConfiguration('editor'); 9 | const config = vscode.workspace.getConfiguration('twig-language'); 10 | 11 | function createHover(snippet, type) { 12 | const example = 13 | typeof snippet.example == 'undefined' ? '' : snippet.example 14 | const description = 15 | typeof snippet.description == 'undefined' ? '' : snippet.description 16 | return new vscode.Hover({ 17 | language: type, 18 | value: description + '\n\n' + example 19 | }) 20 | } 21 | 22 | function prettyDiff(document, range) { 23 | const result = []; 24 | let output = ""; 25 | let options = prettydiff.options; 26 | 27 | let tabSize = editor.tabSize; 28 | let indentChar = " "; 29 | 30 | if (config.tabSize > 0) { 31 | tabSize = config.tabSize; 32 | } 33 | 34 | if (config.indentStyle == "tab") { 35 | tabSize = 0; 36 | indentChar = "\t"; 37 | } 38 | 39 | options.source = document.getText(range); 40 | options.mode = 'beautify'; 41 | options.language = 'html'; 42 | options.lexer = 'markup'; 43 | options.brace_line = config.braceLine; 44 | options.brace_padding = config.bracePadding; 45 | options.brace_style = config.braceStyle; 46 | options.braces = config.braces; 47 | options.comment_line = config.commentLine; 48 | options.comments = config.comments; 49 | options.compressed_css = config.compressedCss; 50 | options.correct = config.correct; 51 | options.cssInsertLines = config.cssInsertLines; 52 | options.else_line = config.elseLine; 53 | options.end_comma = config.endComma; 54 | options.force_attribute = config.forceAttribute; 55 | options.force_indent = config.forceIndent; 56 | options.format_array = config.formatArray; 57 | options.format_object = config.formatObject; 58 | options.function_name = config.functionName; 59 | options.indent_level = config.indentLevel; 60 | options.indent_char = indentChar; 61 | options.indent_size = tabSize; 62 | options.method_chain = config.methodChain; 63 | options.never_flatten = config.neverFlatten; 64 | options.new_line = config.newLine; 65 | options.no_case_indent = config.noCaseIndent; 66 | options.no_lead_zero = config.noLeadZero; 67 | options.object_sort = config.objectSort; 68 | options.preserve = config.preserve; 69 | options.preserve_comment = config.preserveComment; 70 | options.quote_convert = config.quoteConvert; 71 | options.space = config.space; 72 | options.space_close = config.spaceSlose; 73 | options.tag_merge = config.tagMerge; 74 | options.tag_sort = config.tagSort; 75 | options.ternary_line = config.ternaryLine; 76 | options.unformatted = config.unformatted; 77 | options.variable_list = config.variableList; 78 | options.vertical = config.vertical; 79 | options.wrap = config.wrap; 80 | 81 | output = prettydiff(); 82 | 83 | options.end = 0; 84 | options.start = 0; 85 | 86 | result.push(vscode.TextEdit.replace(range, output)); 87 | return result; 88 | }; 89 | 90 | function activate(context) { 91 | const active = vscode.window.activeTextEditor 92 | if (!active || !active.document) return 93 | 94 | registerDocType('html') 95 | 96 | function registerDocType(type) { 97 | if (config.hover === true) { 98 | context.subscriptions.push( 99 | vscode.languages.registerHoverProvider(type, { 100 | provideHover(document, position) { 101 | const range = document.getWordRangeAtPosition(position) 102 | const word = document.getText(range) 103 | 104 | for (const snippet in snippetsArr) { 105 | if ( 106 | snippetsArr[snippet].prefix == word || 107 | snippetsArr[snippet].hover == word 108 | ) { 109 | return createHover(snippetsArr[snippet], type) 110 | } 111 | } 112 | 113 | for (const snippet in functionsArr) { 114 | if ( 115 | functionsArr[snippet].prefix == word || 116 | functionsArr[snippet].hover == word 117 | ) { 118 | return createHover(functionsArr[snippet], type) 119 | } 120 | } 121 | 122 | for (const snippet in twigArr) { 123 | if ( 124 | twigArr[snippet].prefix == word || 125 | twigArr[snippet].hover == word 126 | ) { 127 | return createHover(twigArr[snippet], type) 128 | } 129 | } 130 | } 131 | }) 132 | ) 133 | } 134 | 135 | if (config.formatting === true) { 136 | context.subscriptions.push( 137 | vscode.languages.registerDocumentFormattingEditProvider(type, { 138 | provideDocumentFormattingEdits: function ( 139 | document 140 | ) { 141 | const start = new vscode.Position(0, 0) 142 | const end = new vscode.Position( 143 | document.lineCount - 1, 144 | document.lineAt(document.lineCount - 1).text.length 145 | ) 146 | const rng = new vscode.Range(start, end) 147 | return prettyDiff(document, rng); 148 | } 149 | }) 150 | ) 151 | 152 | context.subscriptions.push( 153 | vscode.languages.registerDocumentRangeFormattingEditProvider( 154 | type, 155 | { 156 | provideDocumentRangeFormattingEdits: function ( 157 | document, 158 | range 159 | ) { 160 | let end = range.end 161 | 162 | if (end.character === 0) { 163 | end = end.translate(-1, Number.MAX_VALUE); 164 | } else { 165 | end = end.translate(0, Number.MAX_VALUE); 166 | } 167 | 168 | const rng = new vscode.Range(new vscode.Position(range.start.line, 0), end) 169 | return prettyDiff(document, rng); 170 | } 171 | } 172 | ) 173 | ) 174 | } 175 | } 176 | } 177 | 178 | exports.activate = activate 179 | -------------------------------------------------------------------------------- /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 | ], 11 | "surroundingPairs": [ 12 | { "open": "'", "close": "'" }, 13 | { "open": "\"", "close": "\"" }, 14 | { "open": "{{", "close": "}}"}, 15 | { "open": "{%", "close": "%}"}, 16 | { "open": "[", "close": "]"}, 17 | { "open": "(", "close": ")" }, 18 | { "open": "<", "close": ">" } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /src/snippets/snippets.json: -------------------------------------------------------------------------------- 1 | { 2 | "asset": { 3 | "prefix": "asset", 4 | "body": 5 | "{% set asset = ${1:entry.assetFieldHandle}.one() %}\n\n{% if asset %}\n\t\"{{\n{% endif %}", 6 | "description": "asset", 7 | "scope": "text.html.twig" 8 | }, 9 | "assets": { 10 | "prefix": "assets", 11 | "body": 12 | "{% 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", 13 | "description": "craft.assets", 14 | "scope": "text.html.twig" 15 | }, 16 | "autoescape": { 17 | "prefix": "autoescape", 18 | "body": "{% autoescape \"${1:type}\" %}\n\t$0\n{% endautoescape %}", 19 | "description": "autoescape", 20 | "scope": "text.html.twig" 21 | }, 22 | "blockb": { 23 | "prefix": "blockb", 24 | "body": "{% block ${1:name} %}\n\t$0\n{% endblock %}", 25 | "description": "block (block)", 26 | "scope": "text.html.twig" 27 | }, 28 | "block": { 29 | "prefix": "block", 30 | "body": "{% block ${1:name} %}$0{% endblock %}", 31 | "description": "block", 32 | "scope": "text.html.twig" 33 | }, 34 | "blockf": { 35 | "prefix": "blockf", 36 | "body": "{{ block(\"${1:name}\") }}$0", 37 | "description": "blockf", 38 | "scope": "text.html.twig" 39 | }, 40 | "cache": { 41 | "prefix": "cache", 42 | "body": "{% cache %}\n\t$1\n{% endcache %}\n$0", 43 | "description": "cache", 44 | "scope": "text.html.twig" 45 | }, 46 | "case": { 47 | "prefix": "case", 48 | "body": "{% case \"${1:value}\" %}\n\t$0", 49 | "description": "case", 50 | "scope": "text.html.twig" 51 | }, 52 | "children": { 53 | "prefix": "children", 54 | "body": "{% children %}$0", 55 | "description": "children", 56 | "scope": "text.html.twig" 57 | }, 58 | "ceil": { 59 | "prefix": "ceil", 60 | "body": "ceil($1)$0", 61 | "description": "ceil", 62 | "scope": "text.html.twig" 63 | }, 64 | "formlogin": { 65 | "prefix": "formlogin", 66 | "body": 67 | "
\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?

", 68 | "description": "craft.user - example login form", 69 | "scope": "text.html.twig" 70 | }, 71 | "formuserprofile": { 72 | "prefix": "formuserprofile", 73 | "body": 74 | "
\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
", 75 | "description": "craft.user - example user profile form", 76 | "scope": "text.html.twig" 77 | }, 78 | 79 | "formuserregistration": { 80 | "prefix": "formuserregistration", 81 | "body": 82 | "
\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
", 83 | "description": "craft.user - example user registration form", 84 | "scope": "text.html.twig" 85 | }, 86 | "formforgotpassword": { 87 | "prefix": "formforgotpassword", 88 | "body": 89 | "
\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
", 90 | "description": "craft.user - example forgot password form", 91 | "scope": "text.html.twig" 92 | }, 93 | "formsetpassword": { 94 | "prefix": "formsetpassword", 95 | "body": 96 | "
\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
", 97 | "description": "craft.user - example set password form", 98 | "scope": "text.html.twig" 99 | }, 100 | "formsearch": { 101 | "prefix": "formsearch", 102 | "body": 103 | "
\n\t\n\t\n
", 104 | "description": "craft.entries - example search form", 105 | "scope": "text.html.twig" 106 | }, 107 | "formsearchresults": { 108 | "prefix": "formsearchresults", 109 | "body": 110 | "

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