From 383008363441d058812eaa057e0cf73b091b8f02 Mon Sep 17 00:00:00 2001 From: Ashwin Shenoy Date: Wed, 12 Aug 2020 15:47:47 +0530 Subject: [PATCH] The initial commit of the project. This commit adds all the files that have been developed so far for the project BetterJinja. --- .gitignore | 0 CHANGELOG.md | 13 + LICENSE.md | 9 + README.md | 76 ++++ messages.json | 3 + messages/install.txt | 47 ++ .../BetterJinja (Filters).sublime-completions | 55 +++ ...etterJinja (Functions).sublime-completions | 11 + .../BetterJinja (Loops).sublime-completions | 18 + .../BetterJinja (Tags).sublime-completions | 35 ++ .../BetterJinja (Tests).sublime-completions | 33 ++ resources/keymaps/Default.sublime-keymap | 28 ++ resources/menus/Main.sublime-menu | 48 ++ resources/metadata/Comments.tmPreferences | 36 ++ .../metadata/Indentation Rules.tmPreferences | 16 + .../settings/BetterJinja.sublime-settings | 0 resources/snippets/autoescape.sublime-snippet | 10 + resources/snippets/block.sublime-snippet | 10 + resources/snippets/call.sublime-snippet | 10 + .../snippets/expression_block.sublime-snippet | 7 + resources/snippets/extends.sublime-snippet | 8 + resources/snippets/filter.sublime-snippet | 10 + resources/snippets/for.sublime-snippet | 10 + resources/snippets/if.sublime-snippet | 10 + resources/snippets/if_else.sublime-snippet | 12 + resources/snippets/macro.sublime-snippet | 10 + resources/snippets/raw.sublime-snippet | 10 + resources/snippets/with.sublime-snippet | 10 + resources/syntax/Jinja.sublime-syntax | 427 ++++++++++++++++++ .../syntax/tests/syntax_test_expression.jinja | 99 ++++ .../tests/syntax_test_statement_blocks.jinja | 108 +++++ 31 files changed, 1179 insertions(+) create mode 100644 .gitignore create mode 100644 CHANGELOG.md create mode 100644 LICENSE.md create mode 100644 README.md create mode 100644 messages.json create mode 100644 messages/install.txt create mode 100644 resources/completions/BetterJinja (Filters).sublime-completions create mode 100644 resources/completions/BetterJinja (Functions).sublime-completions create mode 100644 resources/completions/BetterJinja (Loops).sublime-completions create mode 100644 resources/completions/BetterJinja (Tags).sublime-completions create mode 100644 resources/completions/BetterJinja (Tests).sublime-completions create mode 100644 resources/keymaps/Default.sublime-keymap create mode 100644 resources/menus/Main.sublime-menu create mode 100644 resources/metadata/Comments.tmPreferences create mode 100644 resources/metadata/Indentation Rules.tmPreferences create mode 100644 resources/settings/BetterJinja.sublime-settings create mode 100644 resources/snippets/autoescape.sublime-snippet create mode 100644 resources/snippets/block.sublime-snippet create mode 100644 resources/snippets/call.sublime-snippet create mode 100644 resources/snippets/expression_block.sublime-snippet create mode 100644 resources/snippets/extends.sublime-snippet create mode 100644 resources/snippets/filter.sublime-snippet create mode 100644 resources/snippets/for.sublime-snippet create mode 100644 resources/snippets/if.sublime-snippet create mode 100644 resources/snippets/if_else.sublime-snippet create mode 100644 resources/snippets/macro.sublime-snippet create mode 100644 resources/snippets/raw.sublime-snippet create mode 100644 resources/snippets/with.sublime-snippet create mode 100644 resources/syntax/Jinja.sublime-syntax create mode 100644 resources/syntax/tests/syntax_test_expression.jinja create mode 100644 resources/syntax/tests/syntax_test_statement_blocks.jinja diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..48b703e --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,13 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [1.0.0] - 2020-08-12 +### Added +- Indentation for Jinja2 code blocks. +- Snippets for commonly used Jinja2 blocks. +- The main syntax file along with syntax test for the scopes. +- Auto completions for builtin tags, filters, tests and functions. +- Abiility to use ctrl + / for Jinja2 line comments & ctrl + shift + / for block comments. diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..2580bb4 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,9 @@ +The MIT License (MIT) + +Copyright 2020 © Ashwin Shenoy + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..bdbccbc --- /dev/null +++ b/README.md @@ -0,0 +1,76 @@ +# BetterJinja + +![LICENSE](https://img.shields.io/badge/LICENSE-MIT-green?style=for-the-badge) ![LICENSE](https://img.shields.io/badge/ST-Build%203092+-orange?style=for-the-badge&logo=sublime-text) ![Tag](https://img.shields.io/github/v/tag/Sublime-Instincts/BetterJinja?style=for-the-badge&logo=github&sort=semver) + +A Sublime Text package that offers enhanced syntax highlighting, snippets, completions and much more for [Jinja2](https://jinja.palletsprojects.com/en/2.11.x/) templates. Read more for the full documentation. + +## Features + +- Indentation for code blocks. +- Snippets for common code blocks. +- Enhanced syntax highlighting for Jinja2 templates. +- Autocompletions for built in tags, filters, functions, tests & loop variables. + +## Installation + +#### Package Control +The best way is to install it via [Package Control](https://packagecontrol.io/). Once you have Package Control setup in Sublime Text, open the command palette and search for `Package Control: Install Package`. Search for `BetterJinja` and install it. Package Control will take care for of automatically updating the package for you if there are new releases. + +You can also use `Package Control: Add Repository`. Copy the github url (without the `.git` at the end) and enter it into the input panel that pops up at the bottom when you select `Package Control: Add Repository`. Now use `Package Control: Install Package` and search for `BetterJinja` and install it. + +## Documentation + +### Key bindings + +- The key bindings are configured so that pressing shift + { **twice** will automatically add spaces on both sides for the inner brace expression block & place the cursor in the center, like so `{{ | }}`. +- |||ly pressing shift + % within `{}` will add spaces on both sides of the inner `%` like so `{% | %}` +- You can use ctrl + / for inserting Jinja2 style line comments (`## This is a line comment`) +- Similarly, use ctrl + shift + / for block style comments (`{# This is a block comment #}`) + +### Auto completions +In order to get the auto completions, go to `Preferences: Settings` from the command palette and paste the following in the `Preferences.sublime-settings -- User` (the right hand window) + +```json +"auto_complete_selector": "text.jinja, meta.tag - punctuation.definition.tag.begin, source - comment - string.quoted.double.block - string.quoted.single.block - string.unquoted.heredoc", +"auto_complete_triggers": +[ + {"characters": "<", "selector": "text.html"}, + {"selector": "text.jinja, text.html.basic"}, +] +``` + +If you already have these in your user settings, then just copy the Twig related portions into them. + +### Snippets + +| **Tab Trigger** | **Jinja2 Code Block** | +|-------------------|-------------------------------------------| +| ```jwith``` | ```{% with %}{% endwith %}``` | +| ```jraw``` | ```{% raw %}{% endraw %}``` | +| ```jmacro``` | ```{% macro %}{% endmacro %}``` | +| ```jifelse``` | ```{% if %}{% else %}{% endif %}``` | +| ```jif``` | ```{% if %}{% endif %}``` | +| ```jfor``` | ```{% for %}{% endfor %}``` | +| ```jfilter``` | ```{% filter %}{% endfilter %}``` | +| ```jextends``` | ```{% extends %}``` | +| ```jexp``` | ```{% %}``` | +| ```jcall``` | ```{% call %}{% endcall %}``` | +| ```jblock``` | ```{% block %}{% endblock %}``` | +| ```jautoescape``` | ```{% autoescape %}{% endautoescape %}``` | + +## Issues & Feature requests. + +There is always scope for improvements so please do report any bug(s) that you encounter or request for feature(s) that this package should support. + +Please follow the issue & feature request templates that have been setup while reporting any bug(s) or requesting for feature(s) (So as to stay as organised as possible). + +## License +The MIT License (MIT) + +Copyright 2020 © Ashwin Shenoy + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/messages.json b/messages.json new file mode 100644 index 0000000..d04c6d8 --- /dev/null +++ b/messages.json @@ -0,0 +1,3 @@ +{ + "install": "messages/install.txt" +} \ No newline at end of file diff --git a/messages/install.txt b/messages/install.txt new file mode 100644 index 0000000..03fd690 --- /dev/null +++ b/messages/install.txt @@ -0,0 +1,47 @@ + ____ _ _ _ _ _ +| _ \ | | | | | (_) (_) +| |_) | ___| |_| |_ ___ _ __ | |_ _ __ _ __ _ +| _ < / _ \ __| __/ _ \ '__| | | | '_ \| |/ _` | +| |_) | __/ |_| || __/ | | |__| | | | | | | (_| | +|____/ \___|\__|\__\___|_| \____/|_|_| |_| |\__,_| + _/ | + |__/ +====================================================================== + +BetterJinja is an enhanced syntax highlighting package for Jinja2 +templates for Sublime Text. It also provides snippets, completions, +automatic indentation for Jinja2 code blocks and more ! + +Quick start +----------- + +If you are seeing this messages, that means you have already installed +BetterJinja, which means any of your jinja files will already be +receiving syntax highlighting. + +The following file extensions are supported :- + - .j2 + - .jinja + - .jinja2 + - .htm.j2 + - .htm.jinja + - .htm.jinja2 + - .html.j2 + - .html.jinja + - .html.jinja2 + +Having Problems ? +----------------- + +If you encounter any problems with BetterJinja, or you think that it +can be improved to make your work easier, please log an issue with the +issue tracker: + + https://github.com/Sublime-Instincts/BetterJinja/issues + +Get in Touch +------------ + +BetterJinja is developed & maintained by Ashwin Shenoy. If you have +any feedback regarding BetterJinja, just send a mail on +ashwinshenoy05@gmail.com . \ No newline at end of file diff --git a/resources/completions/BetterJinja (Filters).sublime-completions b/resources/completions/BetterJinja (Filters).sublime-completions new file mode 100644 index 0000000..e771d90 --- /dev/null +++ b/resources/completions/BetterJinja (Filters).sublime-completions @@ -0,0 +1,55 @@ +{ + "scope": "text.jinja text.html.basic & (meta.placeholder.jinja | meta.statement.jinja)", + "completions": [ + { "trigger": "abs\tJinja2 Filter", "contents": "abs()", }, + { "trigger": "attr\tJinja2 Filter", "contents": "attr()", }, + { "trigger": "batch\tJinja2 Filter", "contents": "batch()", }, + { "trigger": "capitalize\tJinja2 Filter", "contents": "capitalize()", }, + { "trigger": "center\tJinja2 Filter", "contents": "center()", }, + { "trigger": "default\tJinja2 Filter", "contents": "default()", }, + { "trigger": "dictsort\tJinja2 Filter", "contents": "dictsort()", }, + { "trigger": "escape\tJinja2 Filter", "contents": "escape()", }, + { "trigger": "filesizeformat\tJinja2 Filter", "contents": "filesizeformat()", }, + { "trigger": "first\tJinja2 Filter", "contents": "first()", }, + { "trigger": "float\tJinja2 Filter", "contents": "float()", }, + { "trigger": "forceescape\tJinja2 Filter", "contents": "forceescape()", }, + { "trigger": "format\tJinja2 Filter", "contents": "format()", }, + { "trigger": "groupby\tJinja2 Filter", "contents": "groupby()", }, + { "trigger": "indent\tJinja2 Filter", "contents": "indent()", }, + { "trigger": "int\tJinja2 Filter", "contents": "int()", }, + { "trigger": "join\tJinja2 Filter", "contents": "join()", }, + { "trigger": "last\tJinja2 Filter", "contents": "last()", }, + { "trigger": "length\tJinja2 Filter", "contents": "length()", }, + { "trigger": "list\tJinja2 Filter", "contents": "list()", }, + { "trigger": "lower\tJinja2 Filter", "contents": "lower()", }, + { "trigger": "max\tJinja2 Filter", "contents": "max()", }, + { "trigger": "min\tJinja2 Filter", "contents": "min()", }, + { "trigger": "map\tJinja2 Filter", "contents": "map()", }, + { "trigger": "pprint\tJinja2 Filter", "contents": "pprint()", }, + { "trigger": "random\tJinja2 Filter", "contents": "random()", }, + { "trigger": "reject\tJinja2 Filter", "contents": "reject()", }, + { "trigger": "rejectattr\tJinja2 Filter", "contents": "rejectattr()", }, + { "trigger": "replace\tJinja2 Filter", "contents": "replace()", }, + { "trigger": "reverse\tJinja2 Filter", "contents": "reverse()", }, + { "trigger": "round\tJinja2 Filter", "contents": "round()", }, + { "trigger": "safe\tJinja2 Filter", "contents": "safe()", }, + { "trigger": "select\tJinja2 Filter", "contents": "select()", }, + { "trigger": "selectattr\tJinja2 Filter", "contents": "selectattr()", }, + { "trigger": "slice\tJinja2 Filter", "contents": "slice()", }, + { "trigger": "sort\tJinja2 Filter", "contents": "sort()", }, + { "trigger": "string\tJinja2 Filter", "contents": "string()", }, + { "trigger": "striptags\tJinja2 Filter", "contents": "striptags()", }, + { "trigger": "sum\tJinja2 Filter", "contents": "sum()", }, + { "trigger": "title\tJinja2 Filter", "contents": "title()", }, + { "trigger": "tojson\tJinja2 Filter", "contents": "tojson()", }, + { "trigger": "trim\tJinja2 Filter", "contents": "trim()", }, + { "trigger": "truncate\tJinja2 Filter", "contents": "truncate()", }, + { "trigger": "unique\tJinja2 Filter", "contents": "unique()", }, + { "trigger": "upper\tJinja2 Filter", "contents": "upper()", }, + { "trigger": "urlencode\tJinja2 Filter", "contents": "urlencode()", }, + { "trigger": "urlize\tJinja2 Filter", "contents": "urlize()", }, + { "trigger": "wordcount\tJinja2 Filter", "contents": "wordcount()", }, + { "trigger": "wordwrap\tJinja2 Filter", "contents": "wordwrap()", }, + { "trigger": "xmlattr\tJinja2 Filter", "contents": "xmlattr()", }, + ], +} \ No newline at end of file diff --git a/resources/completions/BetterJinja (Functions).sublime-completions b/resources/completions/BetterJinja (Functions).sublime-completions new file mode 100644 index 0000000..21e22af --- /dev/null +++ b/resources/completions/BetterJinja (Functions).sublime-completions @@ -0,0 +1,11 @@ +{ + "scope": "text.jinja text.html.basic & (meta.placeholder.jinja | meta.statement.jinja)", + "completions": [ + { "trigger": "range\tJinja2 Function", "contents": "range()", }, + { "trigger": "lipsum\tJinja2 Function", "contents": "lipsum()", }, + { "trigger": "dict\tJinja2 Function", "contents": "dict()", }, + { "trigger": "cycler\tJinja2 Function", "contents": "cycler()", }, + { "trigger": "joiner\tJinja2 Function", "contents": "joiner()", }, + { "trigger": "namespace\tJinja2 Function", "contents": "namespace()", }, + ], +} \ No newline at end of file diff --git a/resources/completions/BetterJinja (Loops).sublime-completions b/resources/completions/BetterJinja (Loops).sublime-completions new file mode 100644 index 0000000..6a598ac --- /dev/null +++ b/resources/completions/BetterJinja (Loops).sublime-completions @@ -0,0 +1,18 @@ +{ + "scope": "text.jinja text.html.basic & (meta.placeholder.jinja | meta.statement.jinja)", + "completions": [ + { "trigger": "loop.index\tJinja2 Loop Variable", "contents": "loop.index", }, + { "trigger": "loop.index0\tJinja2 Loop Variable", "contents": "loop.index0", }, + { "trigger": "loop.revindex\tJinja2 Loop Variable", "contents": "loop.revindex", }, + { "trigger": "loop.revindex0\tJinja2 Loop Variable", "contents": "loop.revindex0", }, + { "trigger": "loop.first\tJinja2 Loop Variable", "contents": "loop.first", }, + { "trigger": "loop.last\tJinja2 Loop Variable", "contents": "loop.last", }, + { "trigger": "loop.length\tJinja2 Loop Variable", "contents": "loop.length", }, + { "trigger": "loop.cycle\tJinja2 Loop Variable", "contents": "loop.cycle", }, + { "trigger": "loop.depth\tJinja2 Loop Variable", "contents": "loop.depth", }, + { "trigger": "loop.depth0\tJinja2 Loop Variable", "contents": "loop.depth0", }, + { "trigger": "loop.previtem\tJinja2 Loop Variable", "contents": "loop.previtem", }, + { "trigger": "loop.nextitem\tJinja2 Loop Variable", "contents": "loop.nextitem", }, + { "trigger": "loop.changed\tJinja2 Loop Variable", "contents": "loop.changed()", }, + ], +} \ No newline at end of file diff --git a/resources/completions/BetterJinja (Tags).sublime-completions b/resources/completions/BetterJinja (Tags).sublime-completions new file mode 100644 index 0000000..3631282 --- /dev/null +++ b/resources/completions/BetterJinja (Tags).sublime-completions @@ -0,0 +1,35 @@ +{ + "scope": "text.jinja text.html.basic & (meta.placeholder.jinja | meta.statement.jinja)", + "completions": [ + // Completions for blocks + { "trigger": "for\tJinja2 Block", "contents": "for", }, + { "trigger": "if\tJinja2 Block", "contents": "if", }, + { "trigger": "raw\tJinja2 Block", "contents": "raw", }, + { "trigger": "block\tJinja2 Block", "contents": "block", }, + { "trigger": "extends\tJinja2 Block", "contents": "extends", }, + { "trigger": "macro\tJinja2 Block", "contents": "macro", }, + { "trigger": "call\tJinja2 Block", "contents": "call", }, + { "trigger": "filter\tJinja2 Block", "contents": "filter", }, + { "trigger": "set\tJinja2 Block", "contents": "set", }, + { "trigger": "include\tJinja2 Block", "contents": "include", }, + { "trigger": "pluralize\tJinja2 Block", "contents": "pluralize", }, + { "trigger": "trans\tJinja2 Block", "contents": "trans", }, + { "trigger": "do\tJinja2 Block", "contents": "do", }, + { "trigger": "debug\tJinja2 Block", "contents": "debug", }, + { "trigger": "with\tJinja2 Block", "contents": "with", }, + { "trigger": "autoescape\tJinja2 Block", "contents": "autoescape", }, + + // Completions for endblocks + { "trigger": "endautoescape\tJinja2 Block", "contents": "endautoescape", }, + { "trigger": "endwith\tJinja2 Block", "contents": "endwith", }, + { "trigger": "endtrans\tJinja2 Block", "contents": "endtrans", }, + { "trigger": "endset\tJinja2 Block", "contents": "endset", }, + { "trigger": "endfilter\tJinja2 Block", "contents": "endfilter", }, + { "trigger": "endcall\tJinja2 Block", "contents": "endcall", }, + { "trigger": "endmacro\tJinja2 Block", "contents": "endmacro", }, + { "trigger": "endblock\tJinja2 endblock", "contents": "endblock", }, + { "trigger": "endraw\tJinja2 Block", "contents": "endraw", }, + { "trigger": "endif\tJinja2 Block", "contents": "endif", }, + { "trigger": "endfor\tJinja2 EndBlock", "contents": "endfor", }, + ], +} \ No newline at end of file diff --git a/resources/completions/BetterJinja (Tests).sublime-completions b/resources/completions/BetterJinja (Tests).sublime-completions new file mode 100644 index 0000000..a7c014a --- /dev/null +++ b/resources/completions/BetterJinja (Tests).sublime-completions @@ -0,0 +1,33 @@ +{ + "scope": "text.jinja text.html.basic & (meta.placeholder.jinja | meta.statement.jinja)", + "completions": [ + { "trigger": "boolean\tJinja2 Test", "contents": "boolean()", }, + { "trigger": "callable\tJinja2 Test", "contents": "callable()", }, + { "trigger": "defined\tJinja2 Test", "contents": "defined()", }, + { "trigger": "divisibleby\tJinja2 Test", "contents": "divisibleby()", }, + { "trigger": "eq\tJinja2 Test", "contents": "eq()", }, + { "trigger": "escaped\tJinja2 Test", "contents": "escaped()", }, + { "trigger": "even\tJinja2 Test", "contents": "even()", }, + { "trigger": "false\tJinja2 Test", "contents": "false()", }, + { "trigger": "float\tJinja2 Test", "contents": "float()", }, + { "trigger": "ge\tJinja2 Test", "contents": "ge()", }, + { "trigger": "gt\tJinja2 Test", "contents": "gt()", }, + { "trigger": "in\tJinja2 Test", "contents": "in()", }, + { "trigger": "integer\tJinja2 Test", "contents": "integer()", }, + { "trigger": "iterable\tJinja2 Test", "contents": "iterable()", }, + { "trigger": "le\tJinja2 Test", "contents": "le()", }, + { "trigger": "lower\tJinja2 Test", "contents": "lower()", }, + { "trigger": "lt\tJinja2 Test", "contents": "lt()", }, + { "trigger": "mapping\tJinja2 Test", "contents": "mapping()", }, + { "trigger": "ne\tJinja2 Test", "contents": "ne()", }, + { "trigger": "none\tJinja2 Test", "contents": "none()", }, + { "trigger": "number\tJinja2 Test", "contents": "number()", }, + { "trigger": "odd\tJinja2 Test", "contents": "odd()", }, + { "trigger": "sameas\tJinja2 Test", "contents": "sameas()", }, + { "trigger": "sequence\tJinja2 Test", "contents": "sequence()", }, + { "trigger": "string\tJinja2 Test", "contents": "string()", }, + { "trigger": "true\tJinja2 Test", "contents": "true()", }, + { "trigger": "undefined\tJinja2 Test", "contents": "undefined()", }, + { "trigger": "upper\tJinja2 Test", "contents": "upper()", }, + ], +} \ No newline at end of file diff --git a/resources/keymaps/Default.sublime-keymap b/resources/keymaps/Default.sublime-keymap new file mode 100644 index 0000000..f6c47c3 --- /dev/null +++ b/resources/keymaps/Default.sublime-keymap @@ -0,0 +1,28 @@ +[ + { + "keys": ["%"], + "command": "insert_snippet", + "args": { + "contents": "% ${0} %" + }, + "context": [ + { "key": "selector", "operator": "equal", "operand": "text.jinja" }, + { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true }, + { "key": "preceding_text", "operator": "regex_contains", "operand": "{$", "match_all": true }, + { "key": "following_text", "operator": "regex_contains", "operand": "}$", "match_all": true }, + ], + }, + { + "keys": ["{"], + "command": "insert_snippet", + "args": { + "contents": "{ ${0} }" + }, + "context": [ + { "key": "selector", "operator": "equal", "operand": "text.jinja" }, + { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true }, + { "key": "preceding_text", "operator": "regex_contains", "operand": "{$", "match_all": true }, + { "key": "following_text", "operator": "regex_contains", "operand": "}$", "match_all": true }, + ], + } +] \ No newline at end of file diff --git a/resources/menus/Main.sublime-menu b/resources/menus/Main.sublime-menu new file mode 100644 index 0000000..97a6697 --- /dev/null +++ b/resources/menus/Main.sublime-menu @@ -0,0 +1,48 @@ +[ + { + "caption": "Preferences", + "mnemonic": "n", + "id": "preferences", + "children": + [ + { + "caption": "Package Settings", + "mnemonic": "P", + "id": "package-settings", + "children": + [ + { + "caption": "BetterJinja", + "children": [ + { + "caption": "Documentation", + "command": "open_url", + "args": { + "url": "https://github.com/Sublime-Instincts/BetterJinja/blob/master/README.md" + }, + }, + { "caption": "-", }, + { + "caption": "Settings", + "command": "edit_settings", + "args": { + "base_file": "${packages}/BetterJinja/resources/settings/BetterJinja.sublime-settings", + "default": "{\n\t${0}\n}\n", + }, + }, + { "caption": "-", }, + { + "caption": "Key Bindings", + "command": "edit_settings", + "args": { + "base_file": "${packages}/BetterJinja/resources/keymaps/Default.sublime-settings", + "default": "[\n\t${0}\n]\n", + }, + } + ], + } + ] + } + ] + } +] \ No newline at end of file diff --git a/resources/metadata/Comments.tmPreferences b/resources/metadata/Comments.tmPreferences new file mode 100644 index 0000000..e4fe956 --- /dev/null +++ b/resources/metadata/Comments.tmPreferences @@ -0,0 +1,36 @@ + + + + + name + Comments + scope + text.jinja text.html.basic + settings + + shellVariables + + + name + TM_COMMENT_START + value + ## + + + name + TM_COMMENT_START_2 + value + {# + + + name + TM_COMMENT_END_2 + value + #} + + + + uuid + 4c6e13fa-e457-4ede-b2f8-7e8f03dc8048 + + \ No newline at end of file diff --git a/resources/metadata/Indentation Rules.tmPreferences b/resources/metadata/Indentation Rules.tmPreferences new file mode 100644 index 0000000..6be74aa --- /dev/null +++ b/resources/metadata/Indentation Rules.tmPreferences @@ -0,0 +1,16 @@ + + + + scope + text.jinja text.html.basic + settings + + decreaseIndentPattern + ^\s*\{\%[-]?\s*(endfor|endif|else|endblock|endmacro|endcall|endfilter|endset|endtrans|endwith|endautoescape)\b.*\s*\%\}\s*$ + increaseIndentPattern + ^\s*\{\%-?\s*\b(if|else|for|block|elif|macro|call|filter|set|trans|pluralize|with|autoescape)\b.*%}\s*$ + disableIndentNextLinePattern + + + + \ No newline at end of file diff --git a/resources/settings/BetterJinja.sublime-settings b/resources/settings/BetterJinja.sublime-settings new file mode 100644 index 0000000..e69de29 diff --git a/resources/snippets/autoescape.sublime-snippet b/resources/snippets/autoescape.sublime-snippet new file mode 100644 index 0000000..7b3eebe --- /dev/null +++ b/resources/snippets/autoescape.sublime-snippet @@ -0,0 +1,10 @@ + + + jautoescape + text.jinja + Jinja2 autoescape + \ No newline at end of file diff --git a/resources/snippets/block.sublime-snippet b/resources/snippets/block.sublime-snippet new file mode 100644 index 0000000..241942e --- /dev/null +++ b/resources/snippets/block.sublime-snippet @@ -0,0 +1,10 @@ + + + jblock + text.jinja + Jinja2 block + \ No newline at end of file diff --git a/resources/snippets/call.sublime-snippet b/resources/snippets/call.sublime-snippet new file mode 100644 index 0000000..f20bfd9 --- /dev/null +++ b/resources/snippets/call.sublime-snippet @@ -0,0 +1,10 @@ + + + jcall + text.jinja + Jinja2 call + \ No newline at end of file diff --git a/resources/snippets/expression_block.sublime-snippet b/resources/snippets/expression_block.sublime-snippet new file mode 100644 index 0000000..c612204 --- /dev/null +++ b/resources/snippets/expression_block.sublime-snippet @@ -0,0 +1,7 @@ + + + jexp + text.jinja + \ No newline at end of file diff --git a/resources/snippets/extends.sublime-snippet b/resources/snippets/extends.sublime-snippet new file mode 100644 index 0000000..a9b5684 --- /dev/null +++ b/resources/snippets/extends.sublime-snippet @@ -0,0 +1,8 @@ + + + jextends + text.jinja + Jinja2 extends + \ No newline at end of file diff --git a/resources/snippets/filter.sublime-snippet b/resources/snippets/filter.sublime-snippet new file mode 100644 index 0000000..25750ac --- /dev/null +++ b/resources/snippets/filter.sublime-snippet @@ -0,0 +1,10 @@ + + + jfilter + text.jinja + Jinja2 filter + \ No newline at end of file diff --git a/resources/snippets/for.sublime-snippet b/resources/snippets/for.sublime-snippet new file mode 100644 index 0000000..abd5bc4 --- /dev/null +++ b/resources/snippets/for.sublime-snippet @@ -0,0 +1,10 @@ + + + jfor + text.jinja + Jinja2 for loop + \ No newline at end of file diff --git a/resources/snippets/if.sublime-snippet b/resources/snippets/if.sublime-snippet new file mode 100644 index 0000000..ac6df8e --- /dev/null +++ b/resources/snippets/if.sublime-snippet @@ -0,0 +1,10 @@ + + + jif + text.jinja + Jinja2 if statement + diff --git a/resources/snippets/if_else.sublime-snippet b/resources/snippets/if_else.sublime-snippet new file mode 100644 index 0000000..a4686e7 --- /dev/null +++ b/resources/snippets/if_else.sublime-snippet @@ -0,0 +1,12 @@ + + + jifelse + text.jinja + Jinja2 if else statement + diff --git a/resources/snippets/macro.sublime-snippet b/resources/snippets/macro.sublime-snippet new file mode 100644 index 0000000..ae5f2d5 --- /dev/null +++ b/resources/snippets/macro.sublime-snippet @@ -0,0 +1,10 @@ + + + jmacro + text.jinja + Jinja2 macro + \ No newline at end of file diff --git a/resources/snippets/raw.sublime-snippet b/resources/snippets/raw.sublime-snippet new file mode 100644 index 0000000..a9e34bd --- /dev/null +++ b/resources/snippets/raw.sublime-snippet @@ -0,0 +1,10 @@ + + + jraw + text.jinja + Jinja2 raw block + \ No newline at end of file diff --git a/resources/snippets/with.sublime-snippet b/resources/snippets/with.sublime-snippet new file mode 100644 index 0000000..4e6b1d9 --- /dev/null +++ b/resources/snippets/with.sublime-snippet @@ -0,0 +1,10 @@ + + + jwith + text.jinja + Jinja2 with statement + \ No newline at end of file diff --git a/resources/syntax/Jinja.sublime-syntax b/resources/syntax/Jinja.sublime-syntax new file mode 100644 index 0000000..21e4a48 --- /dev/null +++ b/resources/syntax/Jinja.sublime-syntax @@ -0,0 +1,427 @@ +%YAML 1.2 +--- +file_extensions: + - j2 + - jinja + - jinja2 + - html.j2 + - html.jinja + - html.jinja2 + - htm.j2 + - htm.jinja + - htm.jinja2 +scope: text.jinja + +variables: + digit: '[0-9]' + integers: '(?:{{digit}}*_)?{{digit}}+' + floats: '(?:(?:{{digit}}*_?)*)?(\.){{digit}}+(?:[eE]{{digit}}*)?' + identifiers: '[a-zA-Z_]+(?:{{digit}}*)?' + + trim_block: '(?:[+-])' + logical_operators: \b(?:and|or|not|in|is)\b + builtin_tags: |- + (?x: + \b(?: + block|recursive|macro + |call|filter|set|extends|include|raw|debug|with + |autoescape|trans|pluralize|scoped|as|do + )\b + ) + end_tags: |- + (?x: + \b(?: + endblock|endfor|endmacro|endif + |endautoescape|endverbatim|endapply|endembed + |endsandbox|endcall|endset|endraw|endtrans + |endfilter + )\b + ) + +contexts: + main: + - match: "" + push: "Packages/HTML/HTML.sublime-syntax" + with_prototype: + - include: statement_blocks + - include: expression_blocks + - include: comments + - include: line_statements + + ###[ Line Statements ]################################################################## + + # TODO: Can we do something about the negative look behind ? The token is too simple. This will cause + # sregex to fall back to oniguruma, thus affecting performance. + line_statements: + - match: (?= , scope: keyword.operator.comparison.jinja}, + {match: \~ , scope: keyword.operator.concatenation.jinja}, + {match: \<= , scope: keyword.operator.comparison.jinja}, + {match: \== , scope: keyword.operator.comparison.jinja}, + {match: \= , scope: keyword.operator.assignment.jinja}, + {match: \+ , scope: keyword.operator.arithmetic.jinja}, + {match: \- , scope: keyword.operator.arithmetic.jinja}, + {match: \** , scope: keyword.operator.arithmetic.jinja}, + {match: \* , scope: keyword.operator.arithmetic.jinja}, + {match: \/\/ , scope: keyword.operator.arithmetic.jinja}, + {match: \/ , scope: keyword.operator.arithmetic.jinja}, + {match: \% , scope: keyword.operator.arithmetic.jinja}, + {match: \!= , scope: keyword.operator.comparison.jinja}, + {match: \> , scope: keyword.operator.comparison.jinja}, + {match: \< , scope: keyword.operator.comparison.jinja}, + ] + + ###[ Constants ]################################################################## + + constants: + - match: \b([Tt]rue|[Ff]alse|[Nn]one)\b + scope: constant.language.jinja + + ###[ Numbers ]################################################################## + + match_numbers: + - include: floats + - include: integers + + integers: + - match: '{{integers}}' + scope: constant.numeric.integer.jinja + + floats: + - match: '{{floats}}' + captures: + 0: constant.numeric.float.jinja + 1: punctuation.separator.decimal.jinja \ No newline at end of file diff --git a/resources/syntax/tests/syntax_test_expression.jinja b/resources/syntax/tests/syntax_test_expression.jinja new file mode 100644 index 0000000..5083af8 --- /dev/null +++ b/resources/syntax/tests/syntax_test_expression.jinja @@ -0,0 +1,99 @@ +## SYNTAX TEST "Packages/BetterJinja/resources/syntax/Jinja.sublime-syntax" + + {{ }} +## ^^meta.placeholder.jinja punctuation.definition.placeholder.begin.jinja +## ^^ meta.placeholder.jinja punctuation.definition.placeholder.end.jinja +## ^^^^^^ meta.placeholder.jinja + + {{ + - * / ** // % }} +## ^ keyword.operator.arithmetic.jinja +## ^ keyword.operator.arithmetic.jinja +## ^ keyword.operator.arithmetic.jinja +## ^ keyword.operator.arithmetic.jinja +## ^^ keyword.operator.arithmetic.jinja +## ^^ keyword.operator.arithmetic.jinja +## ^ keyword.operator.arithmetic.jinja + + {{ >= <= == != < > }} +## ^^ keyword.operator.comparison.jinja +## ^^ keyword.operator.comparison.jinja +## ^^ keyword.operator.comparison.jinja +## ^^ keyword.operator.comparison.jinja +## ^ keyword.operator.comparison.jinja +## ^ keyword.operator.comparison.jinja + + {{ = ~ }} +## ^ keyword.operator.assignment.jinja +## ^ keyword.operator.concatenation.jinja + + {{ 1234567890 123.456789 123.456e789 }} +## ^^^^^^^^^^ constant.numeric.integer.jinja +## ^^^^^^^^^^ constant.numeric.float.jinja +## ^ punctuation.separator.decimal.jinja +## ^^^^^^^^^^^ constant.numeric.float.jinja + + {{ "Hello, World" 'Hello, World' }} +## ^^^^^^^^^^^^^^ string.quoted.double.jinja +## ^^^^^^^^^^^^^^ string.quoted.single.jinja +## ^ punctuation.definition.string.begin.jinja +## ^ punctuation.definition.string.end.jinja +## ^ punctuation.definition.string.begin.jinja +## ^ punctuation.definition.string.end.jinja + + {{ [1, 2, 3, 4, 12.34] }} +## ^ punctuation.section.sequence.begin.jinja +## ^ punctuation.section.sequence.end.jinja +## ^^^^^^^^^^^^^^^^^^^ meta.sequence.list.jinja +## ^ constant.numeric.integer.jinja +## ^^^^^ constant.numeric.float.jinja + + {{ ["a", 'c'] }} +## ^^^ string.quoted.double.jinja +## ^^^ string.quoted.single.jinja + + {{ (1, 0.5, 'a', "b") }} +## ^^^^^^^^^^^^^^^^^^ meta.sequence.tuple.jinja +## ^ constant.numeric.integer.jinja +## ^^^ constant.numeric.float.jinja +## ^^^ string.quoted.single.jinja +## ^^^ string.quoted.double.jinja +## ^ punctuation.section.sequence.begin.jinja +## ^ punctuation.section.sequence.end.jinja + + {{ { "a": "b", 'c': 'd', "e": 123, "f": 123.456 } }} +## ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.mapping.jinja +## ^ punctuation.section.mapping.begin.jinja +## ^ punctuation.section.mapping.end.jinja +## ^^^ string.quoted.double.jinja +## ^^^ string.quoted.single.jinja +## ^ punctuation.separator.mapping.key-value.jinja +## ^ punctuation.separator.mapping.jinja +## ^^^ string.quoted.single.jinja +## ^^^ constant.numeric.integer.jinja +## ^^^^^^^ constant.numeric.float.jinja + + {{ not in is and or }} +## ^^^ keyword.operator.word.jinja +## ^^ keyword.operator.word.jinja +## ^^ keyword.operator.word.jinja +## ^^^ keyword.operator.word.jinja +## ^^ keyword.operator.word.jinja + + {{ "foo {bar} baz" }} +## ^^^^^ constant.other.placeholder.jinja +## ^ punctuation.definition.placeholder.begin.jinja +## ^ punctuation.definition.placeholder.end.jinja +## ^^^ variable.other.jinja + + {{ "foo {1 + 2.3} baz" }} +## ^ constant.numeric.integer.jinja +## ^^^ constant.numeric.float.jinja +## ^ keyword.operator.arithmetic.jinja + + {# #} +## ^^ punctuation.definition.comment.begin.jinja +## ^^ punctuation.definition.comment.end.jinja +## ^^^^^ comment.block.jinja + + {{ foo.bar }} +## ^ punctuation.accessor.dot.jinja \ No newline at end of file diff --git a/resources/syntax/tests/syntax_test_statement_blocks.jinja b/resources/syntax/tests/syntax_test_statement_blocks.jinja new file mode 100644 index 0000000..14ee9f3 --- /dev/null +++ b/resources/syntax/tests/syntax_test_statement_blocks.jinja @@ -0,0 +1,108 @@ +## SYNTAX TEST "Packages/BetterJinja/resources/syntax/Jinja.sublime-syntax" + + {% %} +## ^^^^^^ meta.statement.jinja +## ^^ text.html.basic meta.statement.jinja punctuation.definition.statement.begin.jinja +## ^^ meta.statement.jinja punctuation.definition.statement.end.jinja + + {%+ +%} +## ^^^^^^^^ meta.statement.jinja +## ^^^ meta.statement.jinja punctuation.definition.statement.begin.jinja +## ^^^ meta.statement.jinja punctuation.definition.statement.end.jinja + + {%- -%} +## ^^^^^^^^ meta.statement.jinja +## ^^^ meta.statement.jinja punctuation.definition.statement.begin.jinja +## ^^^ meta.statement.jinja punctuation.definition.statement.end.jinja + + {% if elif else endif is scoped %} +## ^^ keyword.control.conditional.if.jinja +## ^^^^ keyword.control.conditional.elseif.jinja +## ^^^^ keyword.control.conditional.else.jinja +## ^^^^^ keyword.other.endtag.jinja +## ^^ keyword.operator.word.jinja +## ^^^^^^ keyword.other.tag.jinja + + {% for item in items endfor %} +## ^^^ keyword.control.loop.for.jinja +## ^^ keyword.operator.word.jinja +## ^^^^^^ keyword.other.endtag.jinja +## ^^^^ variable.other.jinja + + {% macro endmacro %} +## ^^^^^ keyword.other.tag.jinja +## ^^^^^^^^ keyword.other.endtag.jinja + + {% raw endraw %} +## ^^^ keyword.other.tag.jinja +## ^^^^^^ keyword.other.endtag.jinja + + {% block endblock %} +## ^^^^^ keyword.other.tag.jinja +## ^^^^^^^^ keyword.other.endtag.jinja + + {% autoescape endautoescape %} +## ^^^^^^^^^^ keyword.other.tag.jinja +## ^^^^^^^^^^^^^ keyword.other.endtag.jinja + + {% call endcall %} +## ^^^^ keyword.other.tag.jinja +## ^^^^^^^ keyword.other.endtag.jinja + + {% filter endfilter %} +## ^^^^^^ keyword.other.tag.jinja +## ^^^^^^^^^ keyword.other.endtag.jinja + + {% set endset %} +## ^^^ keyword.other.tag.jinja +## ^^^^^^ keyword.other.endtag.jinja + + {% trans endtrans %} +## ^^^^^ keyword.other.tag.jinja +## ^^^^^^^^ keyword.other.endtag.jinja + + {% set endset %} +## ^^^ keyword.other.tag.jinja +## ^^^^^^ keyword.other.endtag.jinja + + {% extends "index.html" %} +## ^^^^^^^ keyword.other.tag.jinja +## ^^^^^^^^^^^^ string.quoted.double.jinja +## ^ string.quoted.double.jinja punctuation.definition.string.begin.jinja +## ^ string.quoted.double.jinja punctuation.definition.string.end.jinja + + {% include "sidebar.html" ignore missing with context %} +## ^^^^^^^ keyword.other.tag.jinja +## ^^^^^^ keyword.other.jinja +## ^^^^^^^ keyword.other.jinja +## ^^^^ keyword.other.jinja +## ^^^^^^^ keyword.other.jinja + + {% include "sidebar.html" ignore missing without context %} +## ^^^^^^^ keyword.other.jinja + + {% include ['special_sidebar.html', 'sidebar.html'] ignore missing %} +## ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.sequence.list.jinja +## ^ meta.sequence.list.jinja punctuation.section.sequence.begin.jinja +## ^ meta.sequence.list.jinja punctuation.section.sequence.end.jinja +## ^^^^^^^^^^^^^^^^^^^^^^ meta.sequence.list.jinja string.quoted.single.jinja +## ^ meta.sequence.list.jinja string.quoted.single.jinja punctuation.definition.string.begin.jinja +## ^ meta.sequence.list.jinja string.quoted.single.jinja punctuation.definition.string.end.jinja + + + {% - -%} +## ^^ invalid.illegal.jinja + + {%- - %} +## ^ invalid.illegal.jinja + + {% | %} +## ^ keyword.operator.logical.pipe.jinja + + {% function(arg1 = value1, arg2 = value2) %} +## ^^^^^^^^ variable.function.jinja +## ^ punctuation.section.arguments.begin.jinja +## ^^^^ variable.parameter.jinja +## ^ keyword.operator.assignment.jinja +## ^ punctuation.separator.parameters.twig +## ^ punctuation.section.arguments.end.jinja \ No newline at end of file