Jinja html templates formatting with ALE and Prettier in Vim - vim

I am using NVIM v0.3.2-208-g2841e89 on Ubuntu 16.04 LTS and using ALE as my Linting Engine plugin. I am having issue with formatting for jinja template html files with prettier.
The html files which start with <html> tag and contains jinja code are not being formatted at all. When i run ALEFix on these files nothing happens.
The html files that start with {% extends %} line are getting formatted but not the correct way. When i run ALEFix on these files, this is how the code starts to look.
Original File
{% extends "home.html" %}
{% block body %}
<div class="jumbotron">
<p>Thank you {{ session['username'] }} for signing up !!</p>
</div>
{% endblock %}
Formatted File
{% extends "home.html" %} {% block body %}
<div class="jumbotron">
<p>Thank you {{ session['username'] }} for signing up !!</p>
</div>
{% endblock %}
Here is another example.
Original File
{% extends "home.html" %}
{% block body %}
<form method="POST">
{{ form.hidden_tag() }}
{{ form.username.label }} {{ form.username }}
{{ form.password.label }} {{ form.password }}
{{ form.submit }}
</form>
{% endblock %}
Formatted File
{% extends "home.html" %} {% block body %}
<form method="POST">
{{ form.hidden_tag() }} {{ form.username.label }} {{ form.username }} {{
form.password.label }} {{ form.password }} {{ form.submit }}
</form>
{% endblock %}
I am not sure if this is the correct formatting of the jinja file but it does not look very readable.
This is how my config looks
let g:ale_fixers = {
\ '*': ['remove_trailing_lines', 'trim_whitespace'],
\ 'html': ['prettier'],
\ 'javascript': ['eslint', 'prettier'],
\ 'css' : ['stylelint', 'prettier'],
\ 'python' : ['yapf', 'isort', 'autopep8']
\ }
Below is what ALEInfo reports for a jinja template file.
Current Filetype: jinja.html
Available Linters: ['alex', 'htmlhint', 'proselint', 'stylelint', 'tidy', 'writegood']
Linter Aliases:
'writegood' -> ['write-good']
Enabled Linters: ['alex', 'htmlhint', 'proselint', 'stylelint', 'tidy', 'writegood']
Suggested Fixers:
'prettier' - Apply prettier to a file.
'remove_trailing_lines' - Remove all blank lines at the end of a file.
'tidy' - Fix HTML files with tidy.
'trim_whitespace' - Remove all trailing whitespace characters at the end of every line.
Linter Variables:
let g:ale_html_htmlhint_executable = 'htmlhint'
let g:ale_html_htmlhint_options = ''
let g:ale_html_htmlhint_use_global = 0
let g:ale_html_stylelint_executable = 'stylelint'
let g:ale_html_stylelint_options = ''
let g:ale_html_stylelint_use_global = 0
let g:ale_html_tidy_executable = 'tidy'
let g:ale_html_tidy_options = '-q -e -language en'
Global Variables:
let g:ale_cache_executable_check_failures = v:null
let g:ale_change_sign_column_color = 0
let g:ale_command_wrapper = ''
let g:ale_completion_delay = v:null
let g:ale_completion_enabled = 0
let g:ale_completion_max_suggestions = v:null
let g:ale_echo_cursor = 1
let g:ale_echo_msg_error_str = 'E'
let g:ale_echo_msg_format = '[%linter%] %s [%severity%]'
let g:ale_echo_msg_info_str = 'Info'
let g:ale_echo_msg_warning_str = 'W'
let g:ale_enabled = 1
let g:ale_fix_on_save = 1
let g:ale_fixers = {'html': ['prettier'], '*': ['remove_trailing_lines', 'trim_whitespace'], 'javascript': ['eslint', 'prettier'], 'css': ['stylelint', 'prettier'], 'python': ['yapf', 'isort', 'autopep8']}
let g:ale_history_enabled = 1
let g:ale_history_log_output = 1
let g:ale_keep_list_window_open = 0
let g:ale_lint_delay = 200
let g:ale_lint_on_enter = 1
let g:ale_lint_on_filetype_changed = 1
let g:ale_lint_on_insert_leave = 0
let g:ale_lint_on_save = 1
let g:ale_lint_on_text_changed = 'always'
let g:ale_linter_aliases = {}
let g:ale_linters = {'css': ['stylelint'], 'python': ['flake8']}
let g:ale_linters_explicit = 0

This isn't supported by prettier. Somebody needs to step up and write a plugin for it.
prettier issue: https://github.com/prettier/prettier/issues/5581
Note: It says Django but it's basically the same in this context.

Related

The current path, chat/room/1/, didn't match any of these

I am practicing with Django 3 and I have a chat project with the name of educa . I try to run the project by python manage.py runserver and access http://127.0.0.1:8000/chat/room/1/ . I always get the following error messages:
“Page not found (404)
Request Method: GET
Request URL: http://127.0.0.1:8000/chat/room/1/
Using the URLconf defined in educa.urls, Django tried these URL patterns, in this order:
1.accounts/login/ [name='login']
2.accounts/logout/ [name='logout']
3.admin/
4. course/
…
** The current path, chat/room/1/, didn't match any of these.” **
I really don’t know what’s wrong. Please someone help me .Thank you.
The following are the files :
educa/ruls.py :
urlpatterns = [
path('chat/', include('chat.urls', namespace='chat')),
]
chat/urls.py:
app_name = 'chat'
urlpatterns = [
path('room/<int:course_id>/', views.course_chat_room, name='course_chat_room'),
]
chat/views.py:
#login_required
def course_chat_room(request, course_id):
...
return render(request,'chat/room.html', {'course': course})
chat/templates/chat/room.html:
{% extends "base.html" %}
{% block title %}Chat room for "{{ course.title }}"{% endblock %}
{% block content %}
….
{% endblock %}
{% block domready %}
...
{% endblock %}
educa/settings.py:
INSTALLED_APPS = [
...
'chat',
'channels',
]
try this
urlpatterns = [
path('room/<int:course_id>/', views.course_chat_room, name='course_chat_room'),
]
more about URLs https://docs.djangoproject.com/en/3.1/ref/urls/#path
I have tried:
" path('room/<int:course_id>/', views.course_chat_room, name='course_chat_room'),
but the result is all the same. I think it doesn't solve my problem.
**html that I used to render the link to the chatroom:**
{% extends "base.html" %}
{% block title %}Chat room for "{{ course.title }}"{% endblock %}
{% block content %}
<div id="chat">
</div>
<div id="chat-input">
<input id="chat-message-input" type="text">
<input id="chat-message-submit" type="submit" value="Send">
</div>
{% endblock %}
{% block domready %}
var url = 'ws://' + window.location.host +
'/ws/chat/room/' + '{{ course.id }}/';
var chatSocket = new WebSocket(url);
chatSocket.onmessage = function(e) {
var data = JSON.parse(e.data);
var message = data.message;
var dateOptions = {hour: 'numeric', minute: 'numeric', hour12: true};
var datetime = new Date(data.datetime).toLocaleString('en', dateOptions);
var isMe = data.user === '{{ request.user }}';
var source = isMe ? 'me' : 'other';
var name = isMe ? 'Me' : data.user;
var $chat = $('#chat');
$chat.append('<div class="message ' + source + '">' +
'<strong>' + name + '</strong> ' +
'<span class="date">' + datetime + '</span><br>' +
message +
'</div>');
$chat.scrollTop($chat[0].scrollHeight);
};
chatSocket.onclose = function(e) {
console.error('Chat socket closed unexpectedly');
};
var $input = $('#chat-message-input');
var $submit = $('#chat-message-submit');
$submit.click(function() {
var message = $input.val();
if(message) {
// send message in JSON format
chatSocket.send(JSON.stringify({'message': message}));
// clear input
$input.val('');
// return focus
$input.focus();
}
});
$input.focus();
$input.keyup(function(e) {
if (e.which === 13) {
// submit with enter / return key
$submit.click();
}
});
{% endblock %}

TWIG - include variables in different template

I would like to include the same variables in different templates
vars_catchphrase.twig
{% set catchphrase_size = '' %}
{% if var.tile_catchphrase|length <= 4 %}
{% set catchphrase_size = 'size-lg' %}
{% elseif var.tile_catchphrase|length >= 5 and var.tile_catchphrase|length <= 8 %}
{% set catchphrase_size = 'size-md' %}
{% elseif var.tile_catchphrase|length >= 9 and var.tile_catchphrase|length <= 12 %}
{% set catchphrase_size = 'size-sm' %}
{% elseif var.tile_catchphrase|length >= 13 %}
{% set catchphrase_size = 'size-xs' %}
{% endif %}
I tried to include with this (because the context is sometime different) :
{% include 'vars_catchphrase.twig' with { 'var' : post } %}
When the context is different from post I use another one :
{% include 'vars_catchphrase.twig' with { 'var' : item } %}
example.twig
{% for item in list %}
{% include 'vars_catchphrase.twig' with { 'var' : item } %}
<p class="catchphrase {{ catchphrase_size }}">{{ item.title }}</p>
{% endfor %}
The variable is empty. Can I have some help please ?
Templates you include have their own variable scope, this means variables defined inside this template will not be known out the template. This said, included templates also can't alter the parent's context (by default), this is due to twig passing the context array by value, not by reference.
foo.twig
{% set foo = 'foo' %}
{% include 'bar.twig' %}
{{ foo }}
bar.twig
{% set foo = 'bar' %}
The example above will still output foo
In order to solve your problem, I'd suggest adding a custom filter to twig
<?php
$twig->addFilter(new \Twig\TwigFilter('catchphrase_size', function($value) {
switch(true) {
case strlen($value->tile_catchphrase) >= 13: return 'size-xs';
case strlen($value->tile_catchphrase) >= 9: return 'size-sm';
case strlen($value->tile_catchphrase) >= 5: return 'size-md';
default: return 'size-lg';
}
});
This way you can use the filter where ever,
{% for item in list %}
<p class="catchphrase {{ item|catchphrase_size }}">{{ item.title }}</p>
{% endfor %}

Symfony & Twig: how to get vars in twig by DB data?

One question please.
{{ dump(app.user.slugName) }}
If I do the above snippet in Twig, I get the slugName of the user loged ("my-user-2", i.e.) in the app (SlugName is an atribute of the entity user). Ok & Correct. But... I want to order this action from a var (var from BD data)
I have a variable named option which is set like this:
{% set option = 'app.user.slugName' %}
But when I'm trying output this variable with {{ dump(option)}} it returns app.user.slugName as literal. It does not return my-user-2.
Is there are any way in twig to solve this? It's a function to generate a menu, but some links needs some parameters.
I see what you mean, but Twig can't evaluate expression like that.
To achieve something like that you would need a snippet like this,
{% set value_methods = 'app.user.slugname' %}
{% set option_value = _context %}
{% for method in (value_methods|split('.')) if method != '' %}
{% set option_value = attribute(option_value, (method|replace({'()': '', }))) %}
{% endfor %}
{{ option_value }}
twigfiddle
(edit)
Remember you can create a macro to achieve some reusability for this snippet,
{% import _self as macros %}
{{ macros.evaluate(_context, 'app.user.slugname') }}
{% macro evaluate(context, value_methods) %}
{% set option_value = context %}
{% for method in (value_methods|split('.')) if method != '' %}
{% set option_value = attribute(option_value, (method|replace({'()': '', }))) %}
{% endfor %}
{{ option_value }}
{% endmacro %}

Navigation for pages (not for posts) in Jekyll

I'm building a website with Jekyll, just with pages.
I want to find a way to generate previous and next links for the pages, with an attribute for the pages like order.
Is there something that can do the job (without plugin)? I could only find something about posts.
{% assign sortedPages = site.pages | sort:'order' | where: 'published', true %}
{% for p in sortedPages %}
{% if p.url == page.url %}
{% if forloop.first == false %}
{% assign prevIndex = forloop.index0 | minus: 1 %}
<a href="{{site.baseurl}}{{sortedPages[prevIndex].url}}">
previous : {{sortedPages[prevIndex].title}}
</a>
{% endif %}
{% if forloop.last == false %}
{% assign nextIndex = forloop.index0 | plus: 1 %}
<a href="{{site.baseurl}}{{sortedPages[nextIndex].url}}">
next : {{sortedPages[nextIndex].title}}
</a>
{% endif %}
{% endif %}
{% endfor %}
This will do the job.
In order to filter which page you publish, you can add a published variable in pages front matter.
setting the variable
published: true -> this is a boolean
published: 'true' -> this is a string
using where filter
| where: 'published', true will test for boolean
| where: 'published', 'true' will test for string

What is auto escape used for in Swig templating for Node.js?

I'm trying to write an itinerary app built on Express. Swig is the template engine. I'm confused by Swig's autoescape feature. What exactly does it do?
Swig documentation example:
"Control auto-escaping of variable output from within your templates."
// myvar = '<foo>';
{% autoescape true %}{{ myvar }}{% endautoescape %}
// => <foo>
{% autoescape false %}{{ myvar }}{% endautoescape %}
// => <foo>
My code:
<script>
{% autoescape false %}
var all_hotels = {{ hotels | json }};
var all_restaurants = {{ restaurants | json }};
var all_things_to_do = {{ things_to_do | json }};
{% endautoescape %}
</script>
Thank you.
The documentation should read like this:
"Control auto-escaping of variable output from within your templates."
// myvar = '<foo>';
{% autoescape true %}{{ myvar }}{% endautoescape %}
// => <foo>
{% autoescape false %}{{ myvar }}{% endautoescape %}
// => <foo>
So when autoescape is true, it will HTML-escape variable content. I think this is the default setting for Swig.
Since you want to render JSON-variables, your code should work okay (turning off autoescaping to prevent HTML-escaping of the JSON content). Alternatively, you could use the safe filter:
var all_hotels = {{ hotels | safe | json }};
var all_restaurants = {{ restaurants | safe | json }};
...

Resources