Rules: indentation: Fix flow sequences with multi-line scalars

Typically sequences like this:

    ["multi
      line 1", "multi
                line 2"]
pull/4/head
Adrien Vergé 9 years ago
parent 14c99da2bb
commit dd163ed551

@ -611,6 +611,12 @@ class ScalarIndentationTestCase(RuleTestCase):
' {% else %}\n' ' {% else %}\n'
' {{ chef }}\n' ' {{ chef }}\n'
' {% endif %}"\n', conf) ' {% 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): def test_check_multi_line_quoted(self):
conf = ('indentation: {spaces: 2, check-multi-line-strings: yes}\n' conf = ('indentation: {spaces: 2, check-multi-line-strings: yes}\n'
@ -648,6 +654,24 @@ class ScalarIndentationTestCase(RuleTestCase):
' {{ chef }}\n' ' {{ chef }}\n'
' {% endif %}"\n', conf, ' {% endif %}"\n', conf,
problem1=(3, 8), problem2=(5, 8)) 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): def test_basics_folded_style(self):
conf = ('indentation: {spaces: 2, check-multi-line-strings: no}\n' conf = ('indentation: {spaces: 2, check-multi-line-strings: no}\n'

@ -14,6 +14,8 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import string
import yaml import yaml
from yamllint.linter import LintProblem from yamllint.linter import LintProblem
@ -77,6 +79,25 @@ def get_line_indent(token):
return content - start 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): def get_comments_between_tokens(token1, token2, skip_first_line=False):
if token2 is None: if token2 is None:
buf = token1.end_mark.buffer[token1.end_mark.pointer:] buf = token1.end_mark.buffer[token1.end_mark.pointer:]

@ -145,7 +145,7 @@ Use this rule to control the indentation.
import yaml import yaml
from yamllint.linter import LintProblem 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' ID = 'indentation'
@ -237,13 +237,14 @@ def check(conf, token, prev, next, context):
# Step 1: Lint # Step 1: Lint
needs_lint = ( is_visible = (
not isinstance(token, (yaml.StreamStartToken, yaml.StreamEndToken)) and not isinstance(token, (yaml.StreamStartToken, yaml.StreamEndToken)) and
not isinstance(token, yaml.BlockEndToken) and not isinstance(token, yaml.BlockEndToken) and
not (isinstance(token, yaml.ScalarToken) and token.value == '') and not (isinstance(token, yaml.ScalarToken) and token.value == ''))
first_in_line = (is_visible and
token.start_mark.line + 1 > context['cur_line']) token.start_mark.line + 1 > context['cur_line'])
if needs_lint: if first_in_line:
found_indentation = token.start_mark.column found_indentation = token.start_mark.column
expected = context['stack'][-1].indent expected = context['stack'][-1].indent
@ -267,9 +268,10 @@ def check(conf, token, prev, next, context):
# Step 2.a: # Step 2.a:
if needs_lint: if is_visible:
context['cur_line'] = get_real_end_line(token)
if first_in_line:
context['cur_line_indent'] = found_indentation context['cur_line_indent'] = found_indentation
context['cur_line'] = token.end_mark.line + 1
# Step 2.b: Update state # Step 2.b: Update state

Loading…
Cancel
Save