From f09aef4f89a83fa031b99158bba955e2456fb79b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20Verg=C3=A9?= Date: Mon, 18 Jan 2016 18:34:40 +0100 Subject: [PATCH] Rules: comments-indentation: Allow two levels Previously only comments that were indented like the following content line were allowed, e.g.: prev: line: # commented line current: line With this change, such new cases are also allowed: prev: line # commented line 1 # commented line 2 current: line --- tests/rules/test_comments_indentation.py | 28 ++++++++++++++++-- tests/rules/test_common.py | 24 ++++++++++++++- yamllint/rules/comments_indentation.py | 37 +++++++++++++++++++----- yamllint/rules/common.py | 10 +++++++ 4 files changed, 88 insertions(+), 11 deletions(-) diff --git a/tests/rules/test_comments_indentation.py b/tests/rules/test_comments_indentation.py index 47b1ff9..dcd6921 100644 --- a/tests/rules/test_comments_indentation.py +++ b/tests/rules/test_comments_indentation.py @@ -88,15 +88,39 @@ class CommentsIndentationTestCase(RuleTestCase): self.check('---\n' 'obj1:\n' ' a: 1\n' - ' # comments\n' + ' # the following line is disabled\n' + ' # b: 2\n', conf) + self.check('---\n' + 'obj1:\n' + ' a: 1\n' + ' # b: 2\n' '\n' 'obj2:\n' - ' b: 2\n', conf, problem=(4, 3)) + ' b: 2\n', conf) + self.check('---\n' + 'obj1:\n' + ' a: 1\n' + ' # b: 2\n' + '# this object is useless\n' + 'obj2: no\n', conf) + self.check('---\n' + 'obj1:\n' + ' a: 1\n' + '# this object is useless\n' + ' # b: 2\n' + 'obj2: no\n', conf, problem=(5, 3)) self.check('---\n' 'obj1:\n' ' a: 1\n' ' # comments\n' ' b: 2\n', conf) + self.check('---\n' + 'mylist:\n' + ' - todo 1\n' + ' - todo 2\n' + ' # commented for now\n' + ' # - todo 3\n' + '...\n', conf) def test_first_line(self): conf = 'comments-indentation: {}' diff --git a/tests/rules/test_common.py b/tests/rules/test_common.py index ca3320f..1588914 100644 --- a/tests/rules/test_common.py +++ b/tests/rules/test_common.py @@ -18,10 +18,32 @@ import unittest import yaml -from yamllint.rules.common import Comment, get_comments_between_tokens +from yamllint.rules.common import (Comment, get_line_indent, + get_comments_between_tokens) class CommonTestCase(unittest.TestCase): + def test_get_line_indent(self): + tokens = list(yaml.scan('a: 1\n' + 'b:\n' + ' - c: [2, 3, {d: 4}]\n')) + + self.assertEqual(tokens[3].value, 'a') + self.assertEqual(tokens[5].value, '1') + self.assertEqual(tokens[7].value, 'b') + self.assertEqual(tokens[13].value, 'c') + self.assertEqual(tokens[16].value, '2') + self.assertEqual(tokens[18].value, '3') + self.assertEqual(tokens[22].value, 'd') + self.assertEqual(tokens[24].value, '4') + + for i in (3, 5): + self.assertEqual(get_line_indent(tokens[i]), 0) + for i in (7,): + self.assertEqual(get_line_indent(tokens[i]), 0) + for i in (13, 16, 18, 22, 24): + self.assertEqual(get_line_indent(tokens[i]), 2) + def check_comments(self, buffer, *expected): yaml_loader = yaml.BaseLoader(buffer) diff --git a/yamllint/rules/comments_indentation.py b/yamllint/rules/comments_indentation.py index 41f1efd..f256043 100644 --- a/yamllint/rules/comments_indentation.py +++ b/yamllint/rules/comments_indentation.py @@ -17,27 +17,48 @@ import yaml from yamllint.errors import LintProblem -from yamllint.rules.common import get_comments_between_tokens +from yamllint.rules.common import get_line_indent, get_comments_between_tokens ID = 'comments-indentation' TYPE = 'token' +# Case A: +# +# prev: line: +# # commented line +# current: line +# +# Case B: +# +# prev: line +# # commented line 1 +# # commented line 2 +# current: line + def check(conf, token, prev, next): if prev is None: return - token_indent = token.start_mark.column + curr_line_indent = token.start_mark.column if isinstance(token, yaml.StreamEndToken): - token_indent = 0 + curr_line_indent = 0 - skip_first = True + skip_first_line = True if isinstance(prev, yaml.StreamStartToken): - skip_first = False + skip_first_line = False + prev_line_indent = 0 + else: + prev_line_indent = get_line_indent(prev) + + if prev_line_indent <= curr_line_indent: + prev_line_indent = -1 # disable it - for comment in get_comments_between_tokens(prev, token, - skip_first_line=skip_first): - if comment.column != token_indent + 1: + for comment in get_comments_between_tokens( + prev, token, skip_first_line=skip_first_line): + if comment.column - 1 == curr_line_indent: + prev_line_indent = -1 # disable it + elif comment.column - 1 != prev_line_indent: yield LintProblem(comment.line, comment.column, 'comment not indented like content') diff --git a/yamllint/rules/common.py b/yamllint/rules/common.py index 4047c28..d38fd92 100644 --- a/yamllint/rules/common.py +++ b/yamllint/rules/common.py @@ -64,6 +64,16 @@ class Comment(object): str(self) == str(other)) +def get_line_indent(token): + """Finds the indent of the line the token starts in.""" + start = token.start_mark.buffer.rfind('\n', 0, + token.start_mark.pointer) + 1 + content = start + while token.start_mark.buffer[content] == ' ': + content += 1 + return content - start + + def get_comments_between_tokens(token1, token2, skip_first_line=False): if token2 is None: buf = token1.end_mark.buffer[token1.end_mark.pointer:]