diff --git a/tests/rules/test_indentation.py b/tests/rules/test_indentation.py index d6b764a..75f9ac7 100644 --- a/tests/rules/test_indentation.py +++ b/tests/rules/test_indentation.py @@ -611,6 +611,12 @@ class ScalarIndentationTestCase(RuleTestCase): ' {% else %}\n' ' {{ chef }}\n' ' {% endif %}"\n', conf) + self.check('["this is a very long line\n' + ' that needs to be split",\n' + ' "other line"]\n', conf) + self.check('["multi\n' + ' line 1", "multi\n' + ' line 2"]\n', conf) def test_check_multi_line_quoted(self): conf = ('indentation: {spaces: 2, check-multi-line-strings: yes}\n' @@ -648,6 +654,24 @@ class ScalarIndentationTestCase(RuleTestCase): ' {{ chef }}\n' ' {% endif %}"\n', conf, problem1=(3, 8), problem2=(5, 8)) + self.check('["this is a very long line\n' + ' that needs to be split",\n' + ' "other line"]\n', conf) + self.check('["this is a very long line\n' + ' that needs to be split",\n' + ' "other line"]\n', conf, problem=(2, 2)) + self.check('["this is a very long line\n' + ' that needs to be split",\n' + ' "other line"]\n', conf, problem=(2, 4)) + self.check('["multi\n' + ' line 1", "multi\n' + ' line 2"]\n', conf) + self.check('["multi\n' + ' line 1", "multi\n' + ' line 2"]\n', conf, problem=(3, 12)) + self.check('["multi\n' + ' line 1", "multi\n' + ' line 2"]\n', conf, problem=(3, 14)) def test_basics_folded_style(self): conf = ('indentation: {spaces: 2, check-multi-line-strings: no}\n' diff --git a/yamllint/rules/common.py b/yamllint/rules/common.py index 2f99e84..e343e62 100644 --- a/yamllint/rules/common.py +++ b/yamllint/rules/common.py @@ -14,6 +14,8 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +import string + import yaml from yamllint.linter import LintProblem @@ -77,6 +79,25 @@ def get_line_indent(token): return content - start +def get_real_end_line(token): + """Finds the line on which the token really ends. + + With pyyaml, scalar tokens often end on a next line. + """ + end_line = token.end_mark.line + 1 + + if not isinstance(token, yaml.ScalarToken): + return end_line + + pos = token.end_mark.pointer - 1 + while (pos >= token.start_mark.pointer - 1 and + token.end_mark.buffer[pos] in string.whitespace): + if token.end_mark.buffer[pos] == '\n': + end_line -= 1 + pos -= 1 + return end_line + + def get_comments_between_tokens(token1, token2, skip_first_line=False): if token2 is None: buf = token1.end_mark.buffer[token1.end_mark.pointer:] diff --git a/yamllint/rules/indentation.py b/yamllint/rules/indentation.py index 3828343..7d03ab4 100644 --- a/yamllint/rules/indentation.py +++ b/yamllint/rules/indentation.py @@ -145,7 +145,7 @@ Use this rule to control the indentation. import yaml from yamllint.linter import LintProblem -from yamllint.rules.common import is_explicit_key +from yamllint.rules.common import is_explicit_key, get_real_end_line ID = 'indentation' @@ -237,13 +237,14 @@ def check(conf, token, prev, next, context): # Step 1: Lint - needs_lint = ( + is_visible = ( not isinstance(token, (yaml.StreamStartToken, yaml.StreamEndToken)) and not isinstance(token, yaml.BlockEndToken) and - not (isinstance(token, yaml.ScalarToken) and token.value == '') and - token.start_mark.line + 1 > context['cur_line']) + not (isinstance(token, yaml.ScalarToken) and token.value == '')) + first_in_line = (is_visible and + token.start_mark.line + 1 > context['cur_line']) - if needs_lint: + if first_in_line: found_indentation = token.start_mark.column expected = context['stack'][-1].indent @@ -267,9 +268,10 @@ def check(conf, token, prev, next, context): # Step 2.a: - if needs_lint: - context['cur_line_indent'] = found_indentation - context['cur_line'] = token.end_mark.line + 1 + if is_visible: + context['cur_line'] = get_real_end_line(token) + if first_in_line: + context['cur_line_indent'] = found_indentation # Step 2.b: Update state