|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* Twigfield for Craft CMS |
|
4
|
|
|
* |
|
5
|
|
|
* Provides a twig editor field with Twig & Craft API autocomplete |
|
6
|
|
|
* |
|
7
|
|
|
* @link https://nystudio107.com |
|
|
|
|
|
|
8
|
|
|
* @copyright Copyright (c) 2022 nystudio107 |
|
|
|
|
|
|
9
|
|
|
*/ |
|
|
|
|
|
|
10
|
|
|
|
|
11
|
|
|
namespace nystudio107\twigfield\autocompletes; |
|
12
|
|
|
|
|
13
|
|
|
use Craft; |
|
14
|
|
|
use nystudio107\twigfield\base\Autocomplete; |
|
15
|
|
|
use nystudio107\twigfield\models\CompleteItem; |
|
16
|
|
|
use nystudio107\twigfield\types\AutocompleteTypes; |
|
17
|
|
|
use nystudio107\twigfield\types\CompleteItemKind; |
|
18
|
|
|
use Twig\Environment; |
|
19
|
|
|
|
|
20
|
|
|
/** |
|
|
|
|
|
|
21
|
|
|
* @author nystudio107 |
|
|
|
|
|
|
22
|
|
|
* @package twigfield |
|
|
|
|
|
|
23
|
|
|
* @since 1.0.0 |
|
|
|
|
|
|
24
|
|
|
*/ |
|
|
|
|
|
|
25
|
|
|
class TwigLanguageAutocomplete extends Autocomplete |
|
26
|
|
|
{ |
|
27
|
|
|
// Constants |
|
28
|
|
|
// ========================================================================= |
|
29
|
|
|
|
|
30
|
|
|
const CRAFT_FILTER_DOCS_URL = 'https://craftcms.com/docs/4.x/dev/filters.html'; |
|
31
|
|
|
const FILTER_DOCS = [ |
|
32
|
|
|
'abs' => '[abs](https://twig.symfony.com/doc/3.x/filters/abs.html) | Returns the absolute value of a number.', |
|
33
|
|
|
'address' => '[address](#address) | Formats an address.', |
|
34
|
|
|
'append' => '[append](#append) | Appends HTML to the end of another element.', |
|
35
|
|
|
'ascii' => '[ascii](#ascii) | Converts a string to ASCII characters.', |
|
36
|
|
|
'atom' => '[atom](#atom) | Converts a date to an ISO-8601 timestamp.', |
|
37
|
|
|
'attr' => '[attr](#attr) | Modifies an HTML tag’s attributes.', |
|
38
|
|
|
'batch' => '[batch](https://twig.symfony.com/doc/3.x/filters/batch.html) | Batches items in an array.', |
|
39
|
|
|
'camel' => '[camel](#camel) | Formats a string into camelCase.', |
|
40
|
|
|
'capitalize' => '[capitalize](https://twig.symfony.com/doc/3.x/filters/capitalize.html) | Capitalizes the first character of a string.', |
|
41
|
|
|
'column' => '[column](#column) | Returns the values from a single property or key in an array.', |
|
42
|
|
|
'contains' => '[contains](#contains) | Returns whether an array contains a nested item with a given key-value pair.', |
|
43
|
|
|
'convert_encoding' => '[convert_encoding](https://twig.symfony.com/doc/3.x/filters/convert_encoding.html) | Converts a string from one encoding to another.', |
|
44
|
|
|
'currency' => '[currency](#currency) | Formats a number as currency.', |
|
45
|
|
|
'date' => '[date](#date) | Formats a date.', |
|
46
|
|
|
'date_modify' => '[date_modify](https://twig.symfony.com/doc/3.x/filters/date_modify.html) | Modifies a date.', |
|
47
|
|
|
'datetime' => '[datetime](#datetime) | Formats a date with its time.', |
|
48
|
|
|
'default' => '[default](https://twig.symfony.com/doc/3.x/filters/default.html) | Returns the value or a default value if empty.', |
|
49
|
|
|
'diff' => '[diff](#diff) | Returns the difference between arrays.', |
|
50
|
|
|
'duration' => '[duration](#duration) | Returns a `DateInterval` object.', |
|
51
|
|
|
'e' => '[e](https://twig.symfony.com/doc/3.x/filters/escape.html) | Escapes a string.', |
|
52
|
|
|
'encenc' => '[encenc](#encenc) | Encrypts and base64-encodes a string.', |
|
53
|
|
|
'escape' => '[escape](https://twig.symfony.com/doc/3.x/filters/escape.html) | Escapes a string.', |
|
54
|
|
|
'explodeClass' => '[explodeClass](#explodeclass) | Converts a `class` attribute value into an array of class names.', |
|
55
|
|
|
'explodeStyle' => '[explodeStyle](#explodestyle) | Converts a `style` attribute value into an array of property name/value pairs.', |
|
56
|
|
|
'filesize' => '[filesize](#filesize) | Formats a number of bytes into something else.', |
|
57
|
|
|
'filter' => '[filter](#filter) | Filters the items in an array.', |
|
58
|
|
|
'first' => '[first](https://twig.symfony.com/doc/3.x/filters/first.html) | Returns the first character/item of a string/array.', |
|
59
|
|
|
'format' => '[format](https://twig.symfony.com/doc/3.x/filters/format.html) | Formats a string by replacing placeholders.', |
|
60
|
|
|
'group' => '[group](#group) | Groups items in an array.', |
|
61
|
|
|
'hash' => '[hash](#hash) | Prefixes a string with a keyed-hash message authentication code (HMAC).', |
|
62
|
|
|
'httpdate' => '[httpdate](#httpdate) | Converts a date to the HTTP format.', |
|
63
|
|
|
'id' => '[id](#id) | Normalizes an element ID into only alphanumeric characters, underscores, and dashes.', |
|
64
|
|
|
'index' => '[index](#index) | Indexes the items in an array.', |
|
65
|
|
|
'indexOf' => '[indexOf](#indexof) | Returns the index of a given value within an array, or the position of a passed-in string within another string.', |
|
66
|
|
|
'intersect' => '[intersect](#intersect) | Returns the intersecting items of two arrays.', |
|
67
|
|
|
'join' => '[join](https://twig.symfony.com/doc/3.x/filters/join.html) | Concatenates multiple strings into one.', |
|
68
|
|
|
'json_decode' => '[json_decode](#json_decode) | JSON-decodes a value.', |
|
69
|
|
|
'json_encode' => '[json_encode](#json_encode) | JSON-encodes a value.', |
|
70
|
|
|
'kebab' => '[kebab](#kebab) | Formats a string into “kebab-case”.', |
|
71
|
|
|
'keys' => '[keys](https://twig.symfony.com/doc/3.x/filters/keys.html) | Returns the keys of an array.', |
|
72
|
|
|
'last' => '[last](https://twig.symfony.com/doc/3.x/filters/last.html) | Returns the last character/item of a string/array.', |
|
73
|
|
|
'lcfirst' => '[lcfirst](#lcfirst) | Lowercases the first character of a string.', |
|
74
|
|
|
'length' => '[length](https://twig.symfony.com/doc/3.x/filters/length.html) | Returns the length of a string or array.', |
|
75
|
|
|
'literal' => '[literal](#literal) | Escapes an untrusted string for use with element query params.', |
|
76
|
|
|
'lower' => '[lower](https://twig.symfony.com/doc/3.x/filters/lower.html) | Lowercases a string.', |
|
77
|
|
|
'map' => '[map](https://twig.symfony.com/doc/3.x/filters/map.html) | Applies an arrow function to the items in an array.', |
|
78
|
|
|
'markdown' => '[markdown](#markdown-or-md) | Processes a string as Markdown.', |
|
79
|
|
|
'md' => '[md](#markdown-or-md) | Processes a string as Markdown.', |
|
80
|
|
|
'merge' => '[merge](#merge) | Merges an array with another one.', |
|
81
|
|
|
'money' => '[money](#money) | Outputs a value from a Money object.', |
|
82
|
|
|
'multisort' => '[multisort](#multisort) | Sorts an array by one or more keys within its sub-arrays.', |
|
83
|
|
|
'namespace' => '[namespace](#namespace) | Namespaces input names and other HTML attributes, as well as CSS selectors.', |
|
84
|
|
|
'namespaceAttributes' => '', |
|
85
|
|
|
'namespaceInputId' => '[namespaceInputId](#namespaceinputid) | Namespaces an element ID.', |
|
86
|
|
|
'namespaceInputName' => '[namespaceInputName](#namespaceinputname) | Namespaces an input name.', |
|
87
|
|
|
'nl2br' => '[nl2br](https://twig.symfony.com/doc/3.x/filters/nl2br.html) | Replaces newlines with `<br>` tags.', |
|
88
|
|
|
'ns' => '[ns](#namespace) | Namespaces input names and other HTML attributes, as well as CSS selectors.', |
|
89
|
|
|
'number' => '[number](#number) | Formats a number.', |
|
90
|
|
|
'number_format' => '[number_format](https://twig.symfony.com/doc/3.x/filters/number_format.html) | Formats numbers.', |
|
91
|
|
|
'parseAttr' => '', |
|
92
|
|
|
'parseRefs' => '[parseRefs](#parserefs) | Parses a string for reference tags.', |
|
93
|
|
|
'pascal' => '[pascal](#pascal) | Formats a string into “PascalCase”.', |
|
94
|
|
|
'percentage' => '[percentage](#percentage) | Formats a percentage.', |
|
95
|
|
|
'prepend' => '[prepend](#prepend) | Prepends HTML to the beginning of another element.', |
|
96
|
|
|
'purify' => '[purify](#purify) | Runs HTML code through HTML Purifier.', |
|
97
|
|
|
'push' => '[push](#push) | Appends one or more items onto the end of an array.', |
|
98
|
|
|
'raw' => '[raw](https://twig.symfony.com/doc/3.x/filters/raw.html) | Marks as value as safe for the current escaping strategy.', |
|
99
|
|
|
'reduce' => '[reduce](https://twig.symfony.com/doc/3.x/filters/reduce.html) | Iteratively reduces a sequence or mapping to a single value.', |
|
100
|
|
|
'removeClass' => '[removeClass](#removeclass) | Removes a class (or classes) from the given HTML tag.', |
|
101
|
|
|
'replace' => '[replace](#replace) | Replaces parts of a string with other things.', |
|
102
|
|
|
'reverse' => '[reverse](https://twig.symfony.com/doc/3.x/filters/reverse.html) | Reverses a string or array.', |
|
103
|
|
|
'round' => '[round](https://twig.symfony.com/doc/3.x/filters/round.html) | Rounds a number.', |
|
104
|
|
|
'rss' => '[rss](#rss) | Converts a date to RSS date format.', |
|
105
|
|
|
'slice' => '[slice](https://twig.symfony.com/doc/3.x/filters/slice.html) | Extracts a slice of a string or array.', |
|
106
|
|
|
'snake' => '[snake](#snake) | Formats a string into “snake_case”.', |
|
107
|
|
|
'sort' => '[sort](https://twig.symfony.com/doc/3.x/filters/sort.html) | Sorts an array.', |
|
108
|
|
|
'spaceless' => '[spaceless](https://twig.symfony.com/doc/3.x/filters/spaceless.html) | Removes whitespace between HTML tags.', |
|
109
|
|
|
'split' => '[split](https://twig.symfony.com/doc/3.x/filters/split.html) | Splits a string by a delimiter.', |
|
110
|
|
|
'striptags' => '[striptags](https://twig.symfony.com/doc/3.x/filters/striptags.html) | Strips SGML/XML tags from a string.', |
|
111
|
|
|
't' => '[t](#translate-or-t) | Translates a message.', |
|
112
|
|
|
'time' => '[time](#time) | Formats a time.', |
|
113
|
|
|
'timestamp' => '[timestamp](#timestamp) | Formats a human-readable timestamp.', |
|
114
|
|
|
'title' => '[title](https://twig.symfony.com/doc/3.x/filters/title.html) | Formats a string into “Title Case”.', |
|
115
|
|
|
'translate' => '[translate](#translate-or-t) | Translates a message.', |
|
116
|
|
|
'trim' => '[trim](https://twig.symfony.com/doc/3.x/filters/trim.html) | Strips whitespace from the beginning and end of a string.', |
|
117
|
|
|
'truncate' => '[truncate](#truncate) | Truncates a string to a given length, while ensuring that it does not split words.', |
|
118
|
|
|
'ucfirst' => '[ucfirst](#ucfirst) | Capitalizes the first character of a string.', |
|
119
|
|
|
'ucwords' => '', |
|
120
|
|
|
'unique' => '[unique](#unique) | Removes duplicate values from an array.', |
|
121
|
|
|
'unshift' => '[unshift](#unshift) | Prepends one or more items to the beginning of an array.', |
|
122
|
|
|
'upper' => '[upper](https://twig.symfony.com/doc/3.x/filters/upper.html) | Formats a string into “UPPER CASE”.', |
|
123
|
|
|
'url_encode' => '[url_encode](https://twig.symfony.com/doc/3.x/filters/url_encode.html) | Percent-encodes a string as a URL segment or an array as a query string.', |
|
124
|
|
|
'values' => '[values](#values) | Returns all the values in an array, resetting its keys.', |
|
125
|
|
|
'where' => '[where](#where) | Filters an array by key-value pairs.', |
|
126
|
|
|
'widont' => '', |
|
127
|
|
|
'without' => '[without](#without) | Returns an array without the specified element(s).', |
|
128
|
|
|
'withoutKey' => '[withoutKey](#withoutkey) | Returns an array without the specified key.', |
|
129
|
|
|
]; |
|
130
|
|
|
|
|
131
|
|
|
const CRAFT_FUNCTION_DOCS_URL = 'https://craftcms.com/docs/4.x/dev/functions.html'; |
|
132
|
|
|
const FUNCTION_DOCS = [ |
|
133
|
|
|
'actionInput' => '[actionInput](#actioninput) | Outputs a hidden `action` input.', |
|
134
|
|
|
'actionUrl' => '[actionUrl](#actionurl) | Generates a controller action URL.', |
|
135
|
|
|
'alias' => '[alias](#alias) | Parses a string as an alias.', |
|
136
|
|
|
'attr' => '[attr](#attr) | Generates HTML attributes.', |
|
137
|
|
|
'beginBody' => '[beginBody](#beginbody) | Outputs scripts and styles that were registered for the “begin body” position.', |
|
138
|
|
|
'ceil' => '[ceil](#ceil) | Rounds a number up.', |
|
139
|
|
|
'className' => '[className](#classname) | Returns the fully qualified class name of a given object.', |
|
140
|
|
|
'clone' => '[clone](#clone) | Clones an object.', |
|
141
|
|
|
'collect' => '[collect](#collect) | Returns a new collection.', |
|
142
|
|
|
'combine' => '[combine](#combine) | Combines two arrays into one.', |
|
143
|
|
|
'configure' => '[configure](#configure) | Sets attributes on the passed object.', |
|
144
|
|
|
'constant' => '[constant](https://twig.symfony.com/doc/3.x/functions/constant.html) | Returns the constant value for a given string.', |
|
145
|
|
|
'cpUrl' => '[cpUrl](#cpurl) | Generates a control panel URL.', |
|
146
|
|
|
'create' => '[create](#create) | Creates a new object.', |
|
147
|
|
|
'csrfInput' => '[csrfInput](#csrfinput) | Returns a hidden CSRF token input.', |
|
148
|
|
|
'cycle' => '[cycle](https://twig.symfony.com/doc/3.x/functions/cycle.html) | Cycles on an array of values.', |
|
149
|
|
|
'dataUrl' => '[dataUrl](#dataurl) | Outputs an asset or file as a base64-encoded data URL.', |
|
150
|
|
|
'date' => '[date](#date) | Creates a date.', |
|
151
|
|
|
'dump' => '[dump](https://twig.symfony.com/doc/3.x/functions/dump.html) | Dumps information about a variable.', |
|
152
|
|
|
'endBody' => '[endBody](#endbody) | Outputs scripts and styles that were registered for the “end body” position.', |
|
153
|
|
|
'expression' => '[expression](#expression) | Creates a database expression object.', |
|
154
|
|
|
'failMessageInput' => '[failMessageInput](#failmessageinput) | Outputs a hidden `failMessage` input.', |
|
155
|
|
|
'floor' => '[floor](#floor) | Rounds a number down.', |
|
156
|
|
|
'getenv' => '[getenv](#getenv) | Returns the value of an environment variable.', |
|
157
|
|
|
'gql' => '[gql](#gql) | Executes a GraphQL query against the full schema.', |
|
158
|
|
|
'head' => '[head](#head) | Outputs scripts and styles that were registered for the “head” position.', |
|
159
|
|
|
'hiddenInput' => '[hiddenInput](#hiddeninput) | Outputs a hidden input.', |
|
160
|
|
|
'include' => '[include](https://twig.symfony.com/doc/3.x/functions/include.html) | Returns the rendered content of a template.', |
|
161
|
|
|
'input' => '[input](#input) | Outputs an HTML input.', |
|
162
|
|
|
'max' => '[max](https://twig.symfony.com/doc/3.x/functions/max.html) | Returns the biggest value in an array.', |
|
163
|
|
|
'min' => '[min](https://twig.symfony.com/doc/3.x/functions/min.html) | Returns the lowest value in an array.', |
|
164
|
|
|
'ol' => '[ol](#ol) | Outputs an array of items as an ordered list.', |
|
165
|
|
|
'parseBooleanEnv' => '[parseBooleanEnv](#parsebooleanenv) | Parses a string as an environment variable or alias having a boolean value.', |
|
166
|
|
|
'parseEnv' => '[parseEnv](#parseenv) | Parses a string as an environment variable or alias.', |
|
167
|
|
|
'plugin' => '[plugin](#plugin) | Returns a plugin instance by its handle.', |
|
168
|
|
|
'random' => '[random](https://twig.symfony.com/doc/3.x/functions/random.html) | Returns a random value.', |
|
169
|
|
|
'range' => '[range](https://twig.symfony.com/doc/3.x/functions/range.html) | Returns a list containing an arithmetic progression of integers.', |
|
170
|
|
|
'raw' => '[raw](#raw) | Wraps the given string in a `Twig\Markup` object to prevent it from getting HTML-encoded when output.', |
|
171
|
|
|
'redirectInput' => '[redirectInput](#redirectinput) | Outputs a hidden `redirect` input.', |
|
172
|
|
|
'renderObjectTemplate' => '', |
|
173
|
|
|
'seq' => '[seq](#seq) | Outputs the next or current number in a sequence.', |
|
174
|
|
|
'shuffle' => '[shuffle](#shuffle) | Randomizes the order of the items in an array.', |
|
175
|
|
|
'siteUrl' => '[siteUrl](#siteurl) | Generates a front-end URL.', |
|
176
|
|
|
'source' => '[source](https://twig.symfony.com/doc/3.x/functions/source.html) | Returns the content of a template without rendering it.', |
|
177
|
|
|
'successMessageInput' => '[successMessageInput](#successmessageinput) | Outputs a hidden `successMessage` input.', |
|
178
|
|
|
'svg' => '[svg](#svg) | Outputs an SVG document.', |
|
179
|
|
|
'tag' => '[tag](#tag) | Outputs an HTML tag.', |
|
180
|
|
|
'template_from_string' => '[template_from_string](https://twig.symfony.com/doc/3.x/functions/template_from_string.html) | Loads a template from a string.', |
|
181
|
|
|
'ul' => '[ul](#ul) | Outputs an array of items as an unordered list.', |
|
182
|
|
|
'url' => '[url](#url) | Generates a URL.', |
|
183
|
|
|
]; |
|
184
|
|
|
|
|
185
|
|
|
const CRAFT_TAG_DOCS_URL = 'https://craftcms.com/docs/4.x/dev/tags.html'; |
|
186
|
|
|
const TAG_DOCS = [ |
|
187
|
|
|
'apply' => '[apply](https://twig.symfony.com/doc/3.x/tags/apply.html) | Applies Twig filters to the nested template code.', |
|
188
|
|
|
'autoescape' => '[autoescape](https://twig.symfony.com/doc/3.x/tags/autoescape.html) | Controls the escaping strategy for the nested template code.', |
|
189
|
|
|
'block' => '[block](https://twig.symfony.com/doc/3.x/tags/block.html) | Defines a template block.', |
|
190
|
|
|
'cache' => '[cache](#cache) | Caches a portion of your template.', |
|
191
|
|
|
'css' => '[css](#css) | Registers a `<style>` tag on the page.', |
|
192
|
|
|
'dd' => '[dd](#dd) | Dump and die.', |
|
193
|
|
|
'deprecated' => '[deprecated](https://twig.symfony.com/doc/3.x/tags/deprecated.html) | Triggers a PHP deprecation error.', |
|
194
|
|
|
'do' => '[do](https://twig.symfony.com/doc/3.x/tags/do.html) | Does.', |
|
195
|
|
|
'else' => '[else](https://twig.symfony.com/doc/3.x/tags/if.html) | Else conditional.', |
|
196
|
|
|
'elseif' => '[else](https://twig.symfony.com/doc/3.x/tags/if.html) | Else if conditional.', |
|
197
|
|
|
'embed' => '[embed](https://twig.symfony.com/doc/3.x/tags/embed.html) | Embeds another template.', |
|
198
|
|
|
'endblock' => '[endblock](https://twig.symfony.com/doc/3.x/tags/block.html) | End a template block.', |
|
199
|
|
|
'endif' => '[endif](https://twig.symfony.com/doc/3.x/tags/if.html) | End a conditional if block.', |
|
200
|
|
|
'exit' => '[exit](#exit) | Ends the request.', |
|
201
|
|
|
'extends' => '[extends](https://twig.symfony.com/doc/3.x/tags/extends.html) | Extends another template.', |
|
202
|
|
|
'flush' => '', |
|
203
|
|
|
'for' => '[for](https://twig.symfony.com/doc/3.x/tags/for.html) | Loops through an array.', |
|
204
|
|
|
'from' => '[from](https://twig.symfony.com/doc/3.x/tags/from.html) | Imports macros from a template.', |
|
205
|
|
|
'header' => '[header](#header) | Sets an HTTP header on the response.', |
|
206
|
|
|
'hook' => '[hook](#hook) | Invokes a template hook.', |
|
207
|
|
|
'html' => '[html](#html) | Registers arbitrary HTML code on the page.', |
|
208
|
|
|
'if' => '[if](https://twig.symfony.com/doc/3.x/tags/if.html) | Conditionally executes the nested template code.', |
|
209
|
|
|
'import' => '[import](https://twig.symfony.com/doc/3.x/tags/import.html) | Imports macros from a template.', |
|
210
|
|
|
'include' => '[include](https://twig.symfony.com/doc/3.x/tags/include.html) | Includes another template.', |
|
211
|
|
|
'js' => '[js](#js) | Registers a `<script>` tag on the page.', |
|
212
|
|
|
'macro' => '[macro](https://twig.symfony.com/doc/3.x/tags/macro.html) | Defines a macro.', |
|
213
|
|
|
'namespace' => '[namespace](#namespace) | Namespaces input names and other HTML attributes, as well as CSS selectors.', |
|
214
|
|
|
'nav' => '[nav](#nav) | Creates a hierarchical nav menu.', |
|
215
|
|
|
'paginate' => '[paginate](#paginate) | Paginates an element query.', |
|
216
|
|
|
'redirect' => '[redirect](#redirect) | Redirects the browser.', |
|
217
|
|
|
'requireAdmin' => '', |
|
218
|
|
|
'requireEdition' => '', |
|
219
|
|
|
'requireGuest' => '[requireGuest](#requireguest) | Requires that no user is logged-in.', |
|
220
|
|
|
'requireLogin' => '[requireLogin](#requirelogin) | Requires that a user is logged-in.', |
|
221
|
|
|
'requirePermission' => '[requirePermission](#requirepermission) | Requires that a user is logged-in with a given permission.', |
|
222
|
|
|
'script' => '[script](#script) | Renders an HTML script tag on the page.', |
|
223
|
|
|
'set' => '[set](https://twig.symfony.com/doc/3.x/tags/set.html) | Sets a variable.', |
|
224
|
|
|
'switch' => '[switch](#switch) | Switch the template output based on a give value.', |
|
225
|
|
|
'tag' => '[tag](#tag) | Renders an HTML tag on the page.', |
|
226
|
|
|
'use' => '[use](https://twig.symfony.com/doc/3.x/tags/use.html) | Inherits from another template horizontally.', |
|
227
|
|
|
'with' => '[with](https://twig.symfony.com/doc/3.x/tags/with.html) | Creates a nested template scope.', |
|
228
|
|
|
]; |
|
229
|
|
|
|
|
230
|
|
|
const ADDITIONAL_TAGS = [ |
|
231
|
|
|
'else', |
|
232
|
|
|
'elseif', |
|
233
|
|
|
'endblock', |
|
234
|
|
|
'endif', |
|
235
|
|
|
]; |
|
236
|
|
|
|
|
237
|
|
|
// Public Properties |
|
238
|
|
|
// ========================================================================= |
|
239
|
|
|
|
|
240
|
|
|
/** |
|
|
|
|
|
|
241
|
|
|
* @var string The name of the autocomplete |
|
242
|
|
|
*/ |
|
243
|
|
|
public $name = 'TwigLanguageAutocomplete'; |
|
244
|
|
|
|
|
245
|
|
|
/** |
|
|
|
|
|
|
246
|
|
|
* @var string The type of the autocomplete |
|
247
|
|
|
*/ |
|
248
|
|
|
public $type = AutocompleteTypes::TwigExpressionAutocomplete; |
|
249
|
|
|
|
|
250
|
|
|
/** |
|
|
|
|
|
|
251
|
|
|
* @var string Whether the autocomplete should be parsed with . -delimited nested sub-properties |
|
252
|
|
|
*/ |
|
253
|
|
|
public $hasSubProperties = false; |
|
254
|
|
|
|
|
255
|
|
|
/** |
|
|
|
|
|
|
256
|
|
|
* @var ?Environment The Twig environment to parse for functions/filters/tags |
|
257
|
|
|
*/ |
|
258
|
|
|
public $twig; |
|
259
|
|
|
|
|
260
|
|
|
// Public Methods |
|
261
|
|
|
// ========================================================================= |
|
262
|
|
|
|
|
263
|
|
|
/** |
|
|
|
|
|
|
264
|
|
|
* @inerhitDoc |
|
265
|
|
|
*/ |
|
|
|
|
|
|
266
|
|
|
public function init(): void |
|
267
|
|
|
{ |
|
268
|
|
|
if (empty($this->twig)) { |
|
269
|
|
|
$this->twig = Craft::$app->getView()->getTwig(); |
|
270
|
|
|
} |
|
271
|
|
|
} |
|
272
|
|
|
|
|
273
|
|
|
/** |
|
|
|
|
|
|
274
|
|
|
* @inerhitDoc |
|
275
|
|
|
*/ |
|
|
|
|
|
|
276
|
|
|
public function generateCompleteItems(): void |
|
277
|
|
|
{ |
|
278
|
|
|
$twig = $this->twig; |
|
279
|
|
|
// Twig Filters |
|
280
|
|
|
$filters = array_keys($twig->getFilters()); |
|
|
|
|
|
|
281
|
|
|
foreach ($filters as $filter) { |
|
282
|
|
|
$docs = self::FILTER_DOCS[$filter] ?? ''; |
|
283
|
|
|
$docs = str_replace('(#', '(' . self::CRAFT_FILTER_DOCS_URL . '#', $docs); |
|
284
|
|
|
CompleteItem::create() |
|
285
|
|
|
->label($filter) |
|
286
|
|
|
->insertText($filter) |
|
287
|
|
|
->detail(Craft::t('twigfield', 'Twig Filter')) |
|
288
|
|
|
->documentation($docs) |
|
289
|
|
|
->kind(CompleteItemKind::MethodKind) |
|
290
|
|
|
->add($this); |
|
291
|
|
|
} |
|
292
|
|
|
// Twig Functions |
|
293
|
|
|
$functions = array_keys($twig->getFunctions()); |
|
294
|
|
|
foreach ($functions as $function) { |
|
295
|
|
|
$functionLabel = $function . '()'; |
|
296
|
|
|
$docs = self::FUNCTION_DOCS[$function] ?? ''; |
|
297
|
|
|
$docs = str_replace('(#', '(' . self::CRAFT_FUNCTION_DOCS_URL . '#', $docs); |
|
298
|
|
|
CompleteItem::create() |
|
299
|
|
|
->label($functionLabel) |
|
300
|
|
|
->insertText($functionLabel) |
|
301
|
|
|
->detail(Craft::t('twigfield', 'Twig Function')) |
|
302
|
|
|
->documentation($docs) |
|
303
|
|
|
->kind(CompleteItemKind::FunctionKind) |
|
304
|
|
|
->add($this); |
|
305
|
|
|
} |
|
306
|
|
|
// Twig Tags |
|
307
|
|
|
$tags = array_merge(self::ADDITIONAL_TAGS, array_keys($twig->getTokenParsers())); |
|
308
|
|
|
foreach ($tags as $tag) { |
|
309
|
|
|
$docs = self::TAG_DOCS[$tag] ?? ''; |
|
310
|
|
|
$docs = str_replace('(#', '(' . self::CRAFT_TAG_DOCS_URL . '#', $docs); |
|
311
|
|
|
CompleteItem::create() |
|
312
|
|
|
->label($tag) |
|
313
|
|
|
->insertText($tag) |
|
314
|
|
|
->detail(Craft::t('twigfield', 'Twig Tag')) |
|
315
|
|
|
->documentation($docs) |
|
316
|
|
|
->kind(CompleteItemKind::FieldKind) |
|
317
|
|
|
->add($this); |
|
318
|
|
|
} |
|
319
|
|
|
} |
|
320
|
|
|
} |
|
321
|
|
|
|