Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Missing indentation level after multiline tag #115

Open
pawamoy opened this issue Apr 21, 2024 · 5 comments
Open

Missing indentation level after multiline tag #115

pawamoy opened this issue Apr 21, 2024 · 5 comments

Comments

@pawamoy
Copy link

pawamoy commented Apr 21, 2024

Input:

...
    {% filter heading(
        heading_level,
        role="data" if attribute.parent.kind.value == "module" else "attr",
        id=html_id,
        class="doc doc-heading",
        toc_label=('<code class="doc-symbol doc-symbol-toc doc-symbol-attribute"></code>&nbsp;'|safe if config.show_symbol_type_toc else '') + attribute.name,
    ) %}

      {% block heading scoped %}
        ...
      {% endblock heading %}

      {% block labels scoped %}
        ...
      {% endblock labels %}

    {% endfilter %}
...

Output:

...
    {% filter heading(
    heading_level,
    role="data" if attribute.parent.kind.value == "module" else "attr",
    id=html_id,
    class="doc doc-heading",
    toc_label=('<code class="doc-symbol doc-symbol-toc doc-symbol-attribute"></code>&nbsp;'|safe if config.show_symbol_type_toc else '') + attribute.name,
    ) %}

    {% block heading scoped %}
      ...
    {% endblock heading %}

    {% block labels scoped %}
      ...
    {% endblock labels %}

  {% endfilter %}
...

Expected (regardless of how the opening filter tag is indented):

...
    {% filter heading(
    heading_level,
    role="data" if attribute.parent.kind.value == "module" else "attr",
    id=html_id,
    class="doc doc-heading",
    toc_label=('<code class="doc-symbol doc-symbol-toc doc-symbol-attribute"></code>&nbsp;'|safe if config.show_symbol_type_toc else '') + attribute.name,
    ) %}

      {% block heading scoped %}
        ...
      {% endblock heading %}
  
      {% block labels scoped %}
        ...
      {% endblock labels %}
  
    {% endfilter %}
...

Even better (indent continuation lines twice, and ending ) %} only once):

...
    {% filter heading(
        heading_level,
        role="data" if attribute.parent.kind.value == "module" else "attr",
        id=html_id,
        class="doc doc-heading",
        toc_label=('<code class="doc-symbol doc-symbol-toc doc-symbol-attribute"></code>&nbsp;'|safe if config.show_symbol_type_toc else '') + attribute.name,
      ) %}

      {% block heading scoped %}
        ...
      {% endblock heading %}
  
      {% block labels scoped %}
        ...
      {% endblock labels %}
  
    {% endfilter %}
...

Reasoning: the nesting seems visually more correct, while keeping the continuation lines (heading_level, role=..., etc.) indented compared to opening and closing markers.

@pawamoy
Copy link
Author

pawamoy commented Apr 21, 2024

I'm able to at least fix detection of opening tags with this change: OPENING_TAG = r"{%[-+]? *[#/]?(\w+).*?(?:[-+]?%})?" (in DjTXT).

@pawamoy
Copy link
Author

pawamoy commented Apr 21, 2024

Here's a partial patch:

diff --git a/djhtml/modes.py b/djhtml/modes.py
index d017da3..69a5a34 100644
--- a/djhtml/modes.py
+++ b/djhtml/modes.py
@@ -56,6 +56,8 @@ class BaseMode:
         mode = self
         src = self.source
 
+        closing_marker = True
+
         while True:
             if src.find("\n") > mode.MAX_LINE_LENGTH:
                 raise MaxLineLengthExceeded
@@ -77,6 +79,14 @@ class BaseMode:
                 # Create a token from the head.
                 token, mode = mode.create_token(head, raw_token + tail, line)
                 line.append(token)
+                if isinstance(token, Token.Open):
+                    if not token.text.endswith("%}"):
+                        closing_marker = False
+                elif isinstance(token, Token.Text) and not closing_marker:
+                    if token.text.endswith("%}"):
+                        closing_marker = True
+                    else:
+                        token.relative += 1
 
             if raw_token == "\n":
                 self.lines.append(line)
@@ -209,7 +219,7 @@ class DjTXT(BaseMode):
         "video": (" as ", None),
         "placeholder": (" or ", None),
     }
-    OPENING_TAG = r"{%[-+]? *[#/]?(\w+).*?[-+]?%}"
+    OPENING_TAG = r"{%[-+]? *[#/]?(\w+).*?(?:[-+]?%})?"
 
     def create_token(self, raw_token, src, line):
         mode = self

Partial because it indents like this:

{% filter hello(
        param1,
        param2,
    ) %}

    {% block world %}
        ...
    {% endblock world %}

{% endfilter %}

{% with hello(
        param1,
    param2) %}

    {{ world }}

{% endwith %}

First case good (filter), second case not so good (with). Not sure how to fix it.

@pawamoy pawamoy changed the title Missing indentation level after multiline filter tag Missing indentation level after multiline tag Apr 23, 2024
@pawamoy
Copy link
Author

pawamoy commented Apr 23, 2024

Reproducible with if and set too:

{%- if predicate1
    and predicate2
    and predicate3
  %}
  hello
{%- endif -%}
{%- set ns = namespace(
    has_pos_only=False,
    render_pos_only_separator=True,
    render_kw_only_separator=True,
    annotation="",
    equal="=",
  ) -%}

(set is not handled by my patch above, because it's probably not detected as an opening tag)

Changed the title accordingly.

@pawamoy
Copy link
Author

pawamoy commented Apr 23, 2024

Running djhtml twice with my patch formats the input a first time as I expect it, then formats it again as if the patch wasn't there: I'm not sure if this is an issue with my patch or with djhtml more generally (non-predictable results?).

@anentropic
Copy link

Some more examples:

        {% do item_kwargs.update({
        "checkbox_kwargs": {
        "name": _checkboxes_name,
        "value": item.value,
        "id": _checkboxes_name + "--id-" + loop.index|str,
        }
        }) %}
    {{ mdc_textfield(
    name + "--filter",
    label="Filter",
    attrs={
    "@input.debounce": "(e)=>$data.filterValue=e.target.value",
    "x-init": "filteredCheckboxListFilterInit"
    }
    ) }}

I would love if there was something like a 'python' mode inside the multiline tags, akin to current js/css modes, so that function/macro calls could be formatted nicely, ideally with dict/list literals indented too

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants