Skip to content

Commit 6801fd5

Browse files
committed
Force a specific mode using {# fmt:mode #}
1 parent b560343 commit 6801fd5

File tree

4 files changed

+87
-67
lines changed

4 files changed

+87
-67
lines changed

README.md

+33-58
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,28 @@
22

33
***A pure-Python Django/Jinja template indenter without dependencies.***
44

5+
```jinja
6+
{% block content %}
7+
<blockquote
8+
cite="Guido Van Rossum"
9+
class="pythonic"
10+
>
11+
Don't you hate code that's not properly indented?
12+
</blockquote>
13+
{% endblock %}
14+
15+
<style>
16+
.pythonic {
17+
font-style: italic;
18+
19+
{% if dark_mode %}
20+
background: black;
21+
color: white;
22+
{% endif %}
23+
}
24+
</style>
25+
```
26+
527
DjHTML indents mixed HTML/CSS/JavaScript templates that contain
628
[Django](https://docs.djangoproject.com/en/stable/ref/templates/language/)
729
or [Jinja](https://jinja.palletsprojects.com/templates/) template
@@ -15,64 +37,6 @@ other characters. The goal is to correctly indent already
1537
well-structured templates, not to fix broken ones.
1638

1739

18-
### New! Multi-line HTML elements
19-
20-
As of version 3, DjHTML indents multi-line HTML elements and
21-
multi-line attribute values like this:
22-
23-
```jinja
24-
<blockquote cite="Guido Van Rossum"
25-
style="font-style: italic;
26-
{% if dark_mode %}
27-
background: black;
28-
{% endif %}
29-
">
30-
Don't you hate code that's not properly indented?
31-
</blockquote>
32-
```
33-
34-
35-
### New! Multi-line CSS indentation
36-
37-
Multi-line CSS values are now continued at the same indentation level:
38-
39-
```jinja
40-
<style>
41-
@font-face {
42-
font-family: Helvetica;
43-
src: {% for format, filename in licensed_fonts %}
44-
url('{% static filename %}') format('{{ format }}'),
45-
{% endfor %}
46-
url('Arial.woff2') format('woff2'),
47-
url('Arial.woff') format('woff');
48-
}
49-
</style>
50-
```
51-
52-
53-
### New! Improved JavaScript indentation
54-
55-
Many new JavaScript indention rules have been added, such as the
56-
indentation of method chaining:
57-
58-
```jinja
59-
<script>
60-
window.fetch('/test.html')
61-
.then((html) => {
62-
document.body.innerHTML = html;
63-
{% block extra_statements %}
64-
{% endblock %}
65-
});
66-
</script>
67-
```
68-
69-
70-
### New! Tabwidth guessing
71-
72-
Without the `-t` / `--tabwidth` argument, DjHTML no longer defaults to
73-
a tabwidth of 4 but instead guesses the correct tabwidth.
74-
75-
7640
## Installation
7741

7842
DjHTML requires Python 3.8 or higher and is compatible with all
@@ -123,6 +87,17 @@ You can exclude specific lines from being processed with the
12387
{# fmt:on #}
12488
```
12589

90+
You can also force a specific mode with `fmt:html`, `fmt:css` or `fmt:js`:
91+
92+
```jinja
93+
{% block extra_css %}
94+
{# fmt:css #}
95+
a {
96+
color: red;
97+
}
98+
{% endblock %}
99+
```
100+
126101
Contents inside `<pre> ... </pre>`, `<!-- ... --->`, `/* ... */`, and
127102
`{% comment %} ... {% endcomment %}` tags are also ignored (depending
128103
on the current mode).

djhtml/modes.py

+14-5
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,10 @@ class DjTXT(BaseMode):
189189
RAW_TOKENS = [
190190
r"\n",
191191
r"{%[-+]?.*?[-+]?%}",
192+
r"{# fmt:off #}",
193+
r"{# fmt:html #}",
194+
r"{# fmt:css #}",
195+
r"{# fmt:js #}",
192196
r"{#",
193197
r"{{.*?}}",
194198
]
@@ -228,13 +232,18 @@ def create_token(self, raw_token, src, line):
228232
token = Token.CloseAndOpen(raw_token, mode=DjTXT, **self.offsets)
229233
else:
230234
token = Token.Text(raw_token, mode=DjTXT, **self.offsets)
231-
elif raw_token == "{#":
232-
token, mode = Token.Open(raw_token, mode=DjTXT, ignore=True), Comment(
235+
elif raw_token == "{# fmt:off #}":
236+
token, mode = Token.Text(raw_token, mode=DjTXT, ignore=True), Comment(
233237
"{# fmt:on #}", mode=DjTXT, return_mode=self
234-
) if src.startswith(" fmt:off #}") else Comment(
235-
"#}", mode=DjTXT, return_mode=self
236238
)
237-
239+
elif raw_token == "{# fmt:html #}":
240+
token, mode = Token.Text(raw_token, mode=DjHTML, ignore=True), DjHTML(return_mode=self)
241+
elif raw_token == "{# fmt:css #}":
242+
token, mode = Token.Text(raw_token, mode=DjCSS, ignore=True), DjCSS(return_mode=self)
243+
elif raw_token == "{# fmt:js #}":
244+
token, mode = Token.Text(raw_token, mode=DjJS, ignore=True), DjJS(return_mode=self)
245+
elif raw_token == "{#":
246+
token, mode = Token.Open(raw_token, mode=DjTXT, ignore=True), Comment("#}", mode=DjTXT, return_mode=self)
238247
else:
239248
token = Token.Text(raw_token, mode=self.__class__, **self.offsets)
240249

tests/suite/django.html

+18
Original file line numberDiff line numberDiff line change
@@ -195,3 +195,21 @@ <h1>Welcome, {{ request.user }}</h1>
195195
{% customtag %}
196196
<div></div>
197197
{% endcustomtag %}
198+
199+
200+
<!-- Force specific modes -->
201+
{# fmt:css #}
202+
a {
203+
text-decoration: none;
204+
&:hover {
205+
text-decoration: underline;
206+
}
207+
}
208+
{# fmt:js #}
209+
function f() {
210+
return 42;
211+
}
212+
{# fmt:html #}
213+
<ul>
214+
<li/>
215+
</ul>

tests/suite/django.tokens

+22-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
Line([Open('<!--', mode=DjHTML, ignore=True), Text(' The example from the README ', mode=Comment, ignore=True), Close('-->', mode=DjHTML, ignore=True)], ignore=True)
22
Line([Text('<', mode=DjHTML), Text('div ', mode=InsideHTMLTag, absolute=5), Text('class=', mode=InsideHTMLTag, absolute=5), Text('"', mode=InsideHTMLTag, absolute=12)])
3-
Line([Text(' ', mode=InsideHTMLTag, absolute=12), Open('{#', mode=DjTXT, ignore=True), Text(' fmt:off #}', mode=Comment, ignore=True)], ignore=True)
4-
Line([Text(' ,-._|\\', mode=Comment, ignore=True)], level=1, ignore=True)
5-
Line([Text(' / .\\', mode=Comment, ignore=True)], level=1, ignore=True)
6-
Line([Text(' \\_,--._/', mode=Comment, ignore=True)], level=1, ignore=True)
3+
Line([Text(' ', mode=InsideHTMLTag, absolute=12), Text('{# fmt:off #}', mode=DjTXT, ignore=True)], ignore=True)
4+
Line([Text(' ,-._|\\', mode=Comment, ignore=True)], ignore=True)
5+
Line([Text(' / .\\', mode=Comment, ignore=True)], ignore=True)
6+
Line([Text(' \\_,--._/', mode=Comment, ignore=True)], ignore=True)
77
Line([Text(' ', mode=Comment, ignore=True), Close('{# fmt:on #}', mode=DjTXT, ignore=True)], ignore=True)
88
Line([Text(' ', mode=InsideHTMLTag, absolute=12), Text('"', mode=InsideHTMLTag, absolute=11), Text('/>', mode=DjHTML)], offset=11)
99
Line([])
@@ -195,4 +195,22 @@ Line([Open('<!--', mode=DjHTML, ignore=True), Text(' Custom tag ', mode=Comment,
195195
Line([Open('{% customtag %}', mode=DjTXT)])
196196
Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('div', mode=InsideHTMLTag, absolute=5), Open('>', mode=DjHTML, level=1), Close('</div>', mode=DjHTML)], level=1)
197197
Line([Close('{% endcustomtag %}', mode=DjTXT)])
198+
Line([])
199+
Line([])
200+
Line([Open('<!--', mode=DjHTML, ignore=True), Text(' Force specific modes ', mode=Comment, ignore=True), Close('-->', mode=DjHTML, ignore=True)], ignore=True)
201+
Line([Text('{# fmt:css #}', mode=DjCSS, ignore=True)], ignore=True)
202+
Line([Text('a ', mode=DjCSS), Open('{', mode=DjCSS)])
203+
Line([Text(' ', mode=DjCSS), Text('text-decoration: ', mode=DjCSS), Text('none', mode=DjCSS, absolute=17), Text(';', mode=DjCSS)], level=1)
204+
Line([Text(' &:hover ', mode=DjCSS), Open('{', mode=DjCSS, level=1)], level=1)
205+
Line([Text(' ', mode=DjCSS), Text('text-decoration: ', mode=DjCSS), Text('underline', mode=DjCSS, absolute=17), Text(';', mode=DjCSS)], level=2)
206+
Line([Text(' ', mode=DjCSS), Close('}', mode=DjCSS)], level=1)
207+
Line([Close('}', mode=DjCSS)])
208+
Line([Text('{# fmt:js #}', mode=DjJS, ignore=True)], ignore=True)
209+
Line([Text('function f', mode=DjJS), Open('(', mode=DjJS), Close(')', mode=DjJS), Text(' ', mode=DjJS), Open('{', mode=DjJS)])
210+
Line([Text(' return 42;', mode=DjJS)], level=1)
211+
Line([Close('}', mode=DjJS)])
212+
Line([Text('{# fmt:html #}', mode=DjHTML, ignore=True)], ignore=True)
213+
Line([Text('<', mode=DjHTML), Text('ul', mode=InsideHTMLTag, absolute=4), Open('>', mode=DjHTML)])
214+
Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('li', mode=InsideHTMLTag, absolute=4), Text('/>', mode=DjHTML)], level=1)
215+
Line([Close('</ul>', mode=DjHTML)])
198216
Line([])

0 commit comments

Comments
 (0)