diff --git a/tests/rules/test_line_length.py b/tests/rules/test_line_length.py index 7ea2c20..ea7fc2c 100644 --- a/tests/rules/test_line_length.py +++ b/tests/rules/test_line_length.py @@ -43,17 +43,17 @@ class LineLengthTestCase(RuleTestCase): self.check('---\n', conf) self.check(80 * 'a', conf) self.check('---\n' + 80 * 'a' + '\n', conf) - self.check(81 * 'a', conf, problem=(1, 81)) - self.check('---\n' + 81 * 'a' + '\n', conf, problem=(2, 81)) - self.check(1000 * 'b', conf, problem=(1, 81)) - self.check('---\n' + 1000 * 'b' + '\n', conf, problem=(2, 81)) + self.check(16 * 'aaaa ' + 'z', conf, problem=(1, 81)) + self.check('---\n' + 16 * 'aaaa ' + 'z' + '\n', conf, problem=(2, 81)) + self.check(1000 * 'word ' + 'end', conf, problem=(1, 81)) + self.check('---\n' + 1000 * 'word ' + 'end\n', conf, problem=(2, 81)) def test_max_length_10(self): conf = ('line-length: {max: 10}\n' 'new-line-at-end-of-file: disable\n') - self.check('---\nABCDEFGHIJ', conf) - self.check('---\nABCDEFGHIJK', conf, problem=(2, 11)) - self.check('---\nABCDEFGHIJK\n', conf, problem=(2, 11)) + self.check('---\nABCD EFGHI', conf) + self.check('---\nABCD EFGHIJ', conf, problem=(2, 11)) + self.check('---\nABCD EFGHIJ\n', conf, problem=(2, 11)) def test_spaces(self): conf = ('line-length: {max: 80}\n' @@ -61,3 +61,36 @@ class LineLengthTestCase(RuleTestCase): 'trailing-spaces: disable\n') self.check('---\n' + 81 * ' ', conf, problem=(2, 81)) self.check('---\n' + 81 * ' ' + '\n', conf, problem=(2, 81)) + + def test_non_breakable_word(self): + conf = 'line-length: {max: 20, allow-non-breakable-words: yes}' + self.check('---\n' + 30 * 'A' + '\n', conf) + self.check('---\n' + 'this:\n' + ' is:\n' + ' - a:\n' + ' http://localhost/very/long/url\n' + '...\n', conf) + self.check('---\n' + 'this:\n' + ' is:\n' + ' - a:\n' + ' # http://localhost/very/long/url\n' + ' comment\n' + '...\n', conf) + + conf = 'line-length: {max: 20, allow-non-breakable-words: no}' + self.check('---\n' + 30 * 'A' + '\n', conf, problem=(2, 21)) + self.check('---\n' + 'this:\n' + ' is:\n' + ' - a:\n' + ' http://localhost/very/long/url\n' + '...\n', conf, problem=(5, 21)) + self.check('---\n' + 'this:\n' + ' is:\n' + ' - a:\n' + ' # http://localhost/very/long/url\n' + ' comment\n' + '...\n', conf, problem=(5, 21)) diff --git a/yamllint/conf/default.yml b/yamllint/conf/default.yml index d1d701b..7d72570 100644 --- a/yamllint/conf/default.yml +++ b/yamllint/conf/default.yml @@ -35,6 +35,7 @@ rules: check-multi-line-strings: no line-length: max: 80 + allow-non-breakable-words: yes new-line-at-end-of-file: {level: error} new-lines: type: unix diff --git a/yamllint/rules/line_length.py b/yamllint/rules/line_length.py index a3c2cd7..32bed1f 100644 --- a/yamllint/rules/line_length.py +++ b/yamllint/rules/line_length.py @@ -20,6 +20,9 @@ Use this rule to set a limit to lines length. .. rubric:: Options * ``max`` defines the maximal (inclusive) length of lines. +* ``allow-non-breakable-words`` is used to allow non breakable words (without + spaces inside) to overflow the limit. This is useful for long URLs, for + instance. Use ``yes`` to allow, ``no`` to forbid. .. rubric:: Examples @@ -38,6 +41,35 @@ Use this rule to set a limit to lines length. long sentence: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. + +#. With ``line-length: {max: 60, allow-non-breakable-words: yes}`` + + the following code snippet would **PASS**: + :: + + this: + is: + - a: + http://localhost/very/very/very/very/very/very/very/very/long/url + + # this comment is too long, + # but hard to split: + # http://localhost/another/very/very/very/very/very/very/very/very/long/url + + the following code snippet would **FAIL**: + :: + + - this line is waaaaaaaaaaaaaay too long but could be easily splitted... + +#. With ``line-length: {max: 60, allow-non-breakable-words: no}`` + + the following code snippet would **FAIL**: + :: + + this: + is: + - a: + http://localhost/very/very/very/very/very/very/very/very/long/url """ @@ -46,11 +78,24 @@ from yamllint.linter import LintProblem ID = 'line-length' TYPE = 'line' -CONF = {'max': int} +CONF = {'max': int, + 'allow-non-breakable-words': bool} def check(conf, line): if line.end - line.start > conf['max']: + if conf['allow-non-breakable-words']: + start = line.start + while start < line.end and line.buffer[start] == ' ': + start += 1 + + if start != line.end: + if line.buffer[start] == '#': + start += 2 + + if line.buffer.find(' ', start, line.end) == -1: + return + yield LintProblem(line.line_no, conf['max'] + 1, 'line too long (%d > %d characters)' % (line.end - line.start, conf['max']))