linter: Make multiline handlebar singleton tags use 2 space indentation.

This commit is contained in:
Aditya Bansal
2018-04-03 13:39:00 +05:30
committed by Tim Abbott
parent 2fe012ffff
commit 550222dede
6 changed files with 128 additions and 80 deletions

View File

@@ -8,23 +8,23 @@
<p>{{t "Unless I say otherwise for a particular stream, I want:" }}</p> <p>{{t "Unless I say otherwise for a particular stream, I want:" }}</p>
{{partial "settings_checkbox" {{partial "settings_checkbox"
"setting_name" "enable_stream_desktop_notifications" "setting_name" "enable_stream_desktop_notifications"
"is_checked" page_params.enable_stream_desktop_notifications "is_checked" page_params.enable_stream_desktop_notifications
"label" settings_label.enable_stream_desktop_notifications "label" settings_label.enable_stream_desktop_notifications
"end_content" '<div class="propagate_stream_notifications_change"></div>'}} "end_content" '<div class="propagate_stream_notifications_change"></div>'}}
{{partial "settings_checkbox" {{partial "settings_checkbox"
"setting_name" "enable_stream_sounds" "setting_name" "enable_stream_sounds"
"is_checked" page_params.enable_stream_sounds "is_checked" page_params.enable_stream_sounds
"label" settings_label.enable_stream_sounds "label" settings_label.enable_stream_sounds
"end_content" '<div class="propagate_stream_notifications_change"></div>'}} "end_content" '<div class="propagate_stream_notifications_change"></div>'}}
{{partial "settings_checkbox" {{partial "settings_checkbox"
"setting_name" "enable_stream_push_notifications" "setting_name" "enable_stream_push_notifications"
"is_checked" page_params.enable_stream_push_notifications "is_checked" page_params.enable_stream_push_notifications
"label" settings_label.enable_stream_push_notifications "label" settings_label.enable_stream_push_notifications
"end_content" '<div class="propagate_stream_notifications_change"></div>'}} "end_content" '<div class="propagate_stream_notifications_change"></div>'}}
<p class="notification-settings-note"> <p class="notification-settings-note">
{{#tr this}}Change notification settings for individual streams on your <a href="/#streams">Streams page</a>.{{/tr}} {{#tr this}}Change notification settings for individual streams on your <a href="/#streams">Streams page</a>.{{/tr}}
@@ -37,9 +37,9 @@
<p>{{t "I want:" }}</p> <p>{{t "I want:" }}</p>
{{partial "settings_checkbox" {{partial "settings_checkbox"
"setting_name" "enable_desktop_notifications" "setting_name" "enable_desktop_notifications"
"is_checked" page_params.enable_desktop_notifications "is_checked" page_params.enable_desktop_notifications
"label" settings_label.enable_desktop_notifications}} "label" settings_label.enable_desktop_notifications}}
<div class="input-group disableable {{#unless page_params.enable_desktop_notifications}}control-label-disabled{{/unless}}"> <div class="input-group disableable {{#unless page_params.enable_desktop_notifications}}control-label-disabled{{/unless}}">
<label class="checkbox"> <label class="checkbox">
@@ -57,19 +57,19 @@
</div> </div>
{{partial "settings_checkbox" {{partial "settings_checkbox"
"setting_name" "enable_sounds" "setting_name" "enable_sounds"
"is_checked" page_params.enable_sounds "is_checked" page_params.enable_sounds
"label" settings_label.enable_sounds}} "label" settings_label.enable_sounds}}
{{partial "settings_checkbox" {{partial "settings_checkbox"
"setting_name" "enable_offline_email_notifications" "setting_name" "enable_offline_email_notifications"
"is_checked" page_params.enable_offline_email_notifications "is_checked" page_params.enable_offline_email_notifications
"label" settings_label.enable_offline_email_notifications}} "label" settings_label.enable_offline_email_notifications}}
{{partial "settings_checkbox" {{partial "settings_checkbox"
"setting_name" "enable_offline_push_notifications" "setting_name" "enable_offline_push_notifications"
"is_checked" page_params.enable_offline_push_notifications "is_checked" page_params.enable_offline_push_notifications
"label" settings_label.enable_offline_push_notifications}} "label" settings_label.enable_offline_push_notifications}}
<div class="input-group disableable {{#unless page_params.enable_offline_push_notifications}}control-label-disabled{{/unless}}"> <div class="input-group disableable {{#unless page_params.enable_offline_push_notifications}}control-label-disabled{{/unless}}">
<label class="checkbox"> <label class="checkbox">
@@ -92,9 +92,9 @@
<div class="alert-notification" id="other-notify-settings-status"></div> <div class="alert-notification" id="other-notify-settings-status"></div>
{{partial "settings_checkbox" {{partial "settings_checkbox"
"setting_name" "enable_digest_emails" "setting_name" "enable_digest_emails"
"is_checked" page_params.enable_digest_emails "is_checked" page_params.enable_digest_emails
"label" settings_label.enable_digest_emails}} "label" settings_label.enable_digest_emails}}
<div class="input-group {{#unless page_params.enable_offline_email_notifications}}control-label-disabled{{/unless}}"> <div class="input-group {{#unless page_params.enable_offline_email_notifications}}control-label-disabled{{/unless}}">
<label class="checkbox"> <label class="checkbox">
@@ -112,9 +112,9 @@
</div> </div>
{{partial "settings_checkbox" {{partial "settings_checkbox"
"setting_name" "realm_name_in_notifications" "setting_name" "realm_name_in_notifications"
"is_checked" page_params.realm_name_in_notifications "is_checked" page_params.realm_name_in_notifications
"label" settings_label.realm_name_in_notifications}} "label" settings_label.realm_name_in_notifications}}
</div> </div>
</form> </form>

View File

@@ -34,10 +34,10 @@
</div> </div>
{{partial "settings_checkbox" {{partial "settings_checkbox"
"setting_name" "realm_invite_required" "setting_name" "realm_invite_required"
"prefix" "id_" "prefix" "id_"
"is_checked" realm_invite_required "is_checked" realm_invite_required
"label" admin_settings_label.realm_invite_required}} "label" admin_settings_label.realm_invite_required}}
<div class="input-group disableable {{#unless realm_invite_required}}control-label-disabled{{/unless}}"> <div class="input-group disableable {{#unless realm_invite_required}}control-label-disabled{{/unless}}">
<label class="checkbox"> <label class="checkbox">
@@ -60,16 +60,16 @@
</div> </div>
<div class="inline-block organization-permissions-parent"> <div class="inline-block organization-permissions-parent">
{{partial "settings_checkbox" {{partial "settings_checkbox"
"setting_name" "realm_name_changes_disabled" "setting_name" "realm_name_changes_disabled"
"prefix" "id_" "prefix" "id_"
"is_checked" realm_name_changes_disabled "is_checked" realm_name_changes_disabled
"label" admin_settings_label.realm_name_changes_disabled}} "label" admin_settings_label.realm_name_changes_disabled}}
{{partial "settings_checkbox" {{partial "settings_checkbox"
"setting_name" "realm_email_changes_disabled" "setting_name" "realm_email_changes_disabled"
"prefix" "id_" "prefix" "id_"
"is_checked" realm_email_changes_disabled "is_checked" realm_email_changes_disabled
"label" admin_settings_label.realm_email_changes_disabled}} "label" admin_settings_label.realm_email_changes_disabled}}
</div> </div>
</div> </div>

View File

@@ -11,10 +11,10 @@
</div> </div>
<div class="inline-block organization-settings-parent"> <div class="inline-block organization-settings-parent">
{{partial "settings_checkbox" {{partial "settings_checkbox"
"setting_name" "realm_allow_message_editing" "setting_name" "realm_allow_message_editing"
"prefix" "id_" "prefix" "id_"
"is_checked" realm_allow_message_editing "is_checked" realm_allow_message_editing
"label" admin_settings_label.realm_allow_message_editing}} "label" admin_settings_label.realm_allow_message_editing}}
<div class="input-group disableable {{#unless realm_allow_message_editing}}control-label-disabled{{/unless}}"> <div class="input-group disableable {{#unless realm_allow_message_editing}}control-label-disabled{{/unless}}">
<label for="id_realm_message_content_edit_limit_minutes" <label for="id_realm_message_content_edit_limit_minutes"
@@ -42,10 +42,10 @@
</div> </div>
{{partial "settings_checkbox" {{partial "settings_checkbox"
"setting_name" "realm_allow_edit_history" "setting_name" "realm_allow_edit_history"
"prefix" "id_" "prefix" "id_"
"is_checked" realm_allow_edit_history "is_checked" realm_allow_edit_history
"label" admin_settings_label.realm_allow_edit_history}} "label" admin_settings_label.realm_allow_edit_history}}
</div> </div>
</div> </div>
@@ -68,25 +68,25 @@
</div> </div>
{{/if}} {{/if}}
{{partial "settings_checkbox" {{partial "settings_checkbox"
"setting_name" "realm_mandatory_topics" "setting_name" "realm_mandatory_topics"
"prefix" "id_" "prefix" "id_"
"is_checked" realm_mandatory_topics "is_checked" realm_mandatory_topics
"label" admin_settings_label.realm_mandatory_topics}} "label" admin_settings_label.realm_mandatory_topics}}
{{#if server_inline_image_preview}} {{#if server_inline_image_preview}}
{{partial "settings_checkbox" {{partial "settings_checkbox"
"setting_name" "realm_inline_image_preview" "setting_name" "realm_inline_image_preview"
"prefix" "id_" "prefix" "id_"
"is_checked" realm_inline_image_preview "is_checked" realm_inline_image_preview
"label" admin_settings_label.realm_inline_image_preview}} "label" admin_settings_label.realm_inline_image_preview}}
{{/if}} {{/if}}
{{#if server_inline_url_embed_preview}} {{#if server_inline_url_embed_preview}}
{{partial "settings_checkbox" {{partial "settings_checkbox"
"setting_name" "realm_inline_url_embed_preview" "setting_name" "realm_inline_url_embed_preview"
"prefix" "id_" "prefix" "id_"
"is_checked" realm_inline_url_embed_preview "is_checked" realm_inline_url_embed_preview
"label" admin_settings_label.realm_inline_url_embed_preview}} "label" admin_settings_label.realm_inline_url_embed_preview}}
{{/if}} {{/if}}
</div> </div>
</div> </div>
@@ -107,10 +107,10 @@
</select> </select>
</div> </div>
{{partial "settings_checkbox" {{partial "settings_checkbox"
"setting_name" "realm_default_twenty_four_hour_time" "setting_name" "realm_default_twenty_four_hour_time"
"prefix" "id_" "prefix" "id_"
"is_checked" realm_default_twenty_four_hour_time "is_checked" realm_default_twenty_four_hour_time
"label" admin_settings_label.realm_default_twenty_four_hour_time}} "label" admin_settings_label.realm_default_twenty_four_hour_time}}
</div> </div>
</div> </div>
@@ -121,10 +121,10 @@
</div> </div>
<div class="inline-block organization-settings-parent"> <div class="inline-block organization-settings-parent">
{{partial "settings_checkbox" {{partial "settings_checkbox"
"setting_name" "realm_send_welcome_emails" "setting_name" "realm_send_welcome_emails"
"prefix" "id_" "prefix" "id_"
"is_checked" realm_send_welcome_emails "is_checked" realm_send_welcome_emails
"label" admin_settings_label.realm_send_welcome_emails}} "label" admin_settings_label.realm_send_welcome_emails}}
</div> </div>
<div class="input-group"> <div class="input-group">

View File

@@ -39,7 +39,7 @@ def pretty_print_html(html, num_spaces=4):
# we proceed, we will push/pop info dictionaries on/off a stack. # we proceed, we will push/pop info dictionaries on/off a stack.
for token in tokens: for token in tokens:
if token.kind in ('html_start', 'handlebars_start', if token.kind in ('html_start', 'handlebars_start', 'handlebars_singleton',
'html_singleton', 'django_start') and stack[-1]['tag'] != 'pre': 'html_singleton', 'django_start') and stack[-1]['tag'] != 'pre':
# An HTML start tag should only cause a new indent if we # An HTML start tag should only cause a new indent if we
# are on a new line. # are on a new line.
@@ -95,7 +95,7 @@ def pretty_print_html(html, num_spaces=4):
) )
stack.append(info) stack.append(info)
elif (token.kind in ('html_end', 'handlebars_end', 'html_singleton_end', elif (token.kind in ('html_end', 'handlebars_end', 'html_singleton_end',
'django_end') and 'django_end', 'handlebars_singleton_end') and
(stack[-1]['tag'] != 'pre' or token.tag == 'pre')): (stack[-1]['tag'] != 'pre' or token.tag == 'pre')):
info = stack.pop() info = stack.pop()
if info['block']: if info['block']:
@@ -123,10 +123,12 @@ def pretty_print_html(html, num_spaces=4):
elif (start_line + info['line_span'] - 1 == end_line and elif (start_line + info['line_span'] - 1 == end_line and
(info['line_span'] > 2 or (info['line_span'] > 2 or
(info['line_span'] == 2 and (info['line_span'] == 2 and
token.kind == 'html_singleton_end'))): token.kind in
('html_singleton_end',
'handlebars_singleton_end')))):
offsets[end_line] = (1 + info['extra_indent'] + offsets[end_line] = (1 + info['extra_indent'] +
(info['depth'] + 1) * num_spaces) - adjustment (info['depth'] + 1) * num_spaces) - adjustment
if token.kind == 'html_singleton_end': if token.kind in ('html_singleton_end', 'handlebars_singleton_end'):
# We would like singleton tags to have 2 space # We would like singleton tags to have 2 space
# indentation in case they span over multiple lines. # indentation in case they span over multiple lines.
offsets[end_line] -= 2 offsets[end_line] -= 2
@@ -146,7 +148,7 @@ def pretty_print_html(html, num_spaces=4):
extra_indent = info['extra_indent'] extra_indent = info['extra_indent']
adjustment = len(line)-len(line.lstrip()) + 1 adjustment = len(line)-len(line.lstrip()) + 1
offset = (1 + extra_indent + new_depth * num_spaces) - adjustment offset = (1 + extra_indent + new_depth * num_spaces) - adjustment
if token.kind == 'html_singleton_end': if token.kind in ('html_singleton_end', 'handlebars_singleton_end'):
# We would like singleton tags to have 2 space # We would like singleton tags to have 2 space
# indentation in case they span over multiple lines. # indentation in case they span over multiple lines.
offset -= 2 offset -= 2

View File

@@ -60,6 +60,9 @@ def tokenize(text):
# type: () -> bool # type: () -> bool
return looking_at("{#") return looking_at("{#")
def looking_at_handlebarpartial() -> bool:
return looking_at("{{partial")
def looking_at_html_start(): def looking_at_html_start():
# type: () -> bool # type: () -> bool
return looking_at("<") and not looking_at("</") return looking_at("<") and not looking_at("</")
@@ -101,6 +104,10 @@ def tokenize(text):
s = get_django_comment(text, state.i) s = get_django_comment(text, state.i)
tag = s[2:-2] tag = s[2:-2]
kind = 'django_comment' kind = 'django_comment'
elif looking_at_handlebarpartial():
s = get_handlebar_partial(text, state.i)
tag = s[9:-2]
kind = 'handlebars_singleton'
elif looking_at_html_start(): elif looking_at_html_start():
s = get_html_tag(text, state.i) s = get_html_tag(text, state.i)
tag_parts = s[1:-1].split() tag_parts = s[1:-1].split()
@@ -155,12 +162,10 @@ def tokenize(text):
) )
tokens.append(token) tokens.append(token)
advance(len(s)) advance(len(s))
if kind == 'html_singleton':
# Here we insert a Pseudo html_singleton_end tag so as to have def add_pseudo_end_token(kind: str) -> None:
# ease of detection of end of singleton html tags which might be
# needed in some cases as with our html pretty printer.
token = Token( token = Token(
kind='html_singleton_end', kind=kind,
s='</' + tag + '>', s='</' + tag + '>',
tag=tag, tag=tag,
line=state.line, line=state.line,
@@ -169,6 +174,16 @@ def tokenize(text):
) )
tokens.append(token) tokens.append(token)
if kind == 'html_singleton':
# Here we insert a Pseudo html_singleton_end tag so as to have
# ease of detection of end of singleton html tags which might be
# needed in some cases as with our html pretty printer.
add_pseudo_end_token('html_singleton_end')
if kind == 'handlebars_singleton':
# We insert a pseudo handlbar end tag for singleton cases of
# handlebars like the partials. This helps in indenting multi line partials.
add_pseudo_end_token('handlebars_singleton_end')
return tokens return tokens
def validate(fn=None, text=None, check_indent=True): def validate(fn=None, text=None, check_indent=True):
@@ -382,3 +397,15 @@ def get_django_comment(text, i):
unclosed_end = end unclosed_end = end
end += 1 end += 1
raise TokenizationException('Unclosed comment', text[i:unclosed_end]) raise TokenizationException('Unclosed comment', text[i:unclosed_end])
def get_handlebar_partial(text, i):
# type: (str, int) -> str
end = i + 10
unclosed_end = 0
while end <= len(text):
if text[end-2:end] == '}}':
return text[i:end]
if not unclosed_end and text[end] == '<':
unclosed_end = end
end += 1
raise TokenizationException('Unclosed partial', text[i:unclosed_end])

View File

@@ -420,6 +420,24 @@ GOOD_HTML15 = """
</div> </div>
""" """
BAD_HTML16 = """
<div>
{{partial "settings_checkbox"
"setting_name" "realm_name_in_notifications"
"is_checked" page_params.realm_name_in_notifications
"label" settings_label.realm_name_in_notifications}}
</div>
"""
GOOD_HTML16 = """
<div>
{{partial "settings_checkbox"
"setting_name" "realm_name_in_notifications"
"is_checked" page_params.realm_name_in_notifications
"label" settings_label.realm_name_in_notifications}}
</div>
"""
class TestPrettyPrinter(unittest.TestCase): class TestPrettyPrinter(unittest.TestCase):
def compare(self, a: str, b: str) -> None: def compare(self, a: str, b: str) -> None:
self.assertEqual(a.split('\n'), b.split('\n')) self.assertEqual(a.split('\n'), b.split('\n'))
@@ -442,3 +460,4 @@ class TestPrettyPrinter(unittest.TestCase):
self.compare(pretty_print_html(BAD_HTML13), GOOD_HTML13) self.compare(pretty_print_html(BAD_HTML13), GOOD_HTML13)
self.compare(pretty_print_html(BAD_HTML14), GOOD_HTML14) self.compare(pretty_print_html(BAD_HTML14), GOOD_HTML14)
self.compare(pretty_print_html(BAD_HTML15), GOOD_HTML15) self.compare(pretty_print_html(BAD_HTML15), GOOD_HTML15)
self.compare(pretty_print_html(BAD_HTML16), GOOD_HTML16)