diff --git a/tests/rules/test_new_lines.py b/tests/rules/test_new_lines.py index 80334ead..0dce3c4b 100644 --- a/tests/rules/test_new_lines.py +++ b/tests/rules/test_new_lines.py @@ -31,7 +31,7 @@ def test_disabled(self): self.check('---\ntext\n', conf) self.check('---\r\ntext\r\n', conf) - def test_unix_type(self): + def test_unix_type_first_occurence(self): conf = ('new-line-at-end-of-file: disable\n' 'new-lines: {type: unix}\n') self.check('', conf) @@ -41,6 +41,17 @@ def test_unix_type(self): self.check('---\ntext\n', conf) self.check('---\r\ntext\r\n', conf, problem=(1, 4)) + def test_unix_type_all_occurences(self): + conf = ('new-line-at-end-of-file: disable\n' + 'new-lines: {type: unix,' + ' disable_after_first_occurence: False}\n') + self.check('', conf) + self.check('\r', conf) + self.check('\n', conf) + self.check('\r\n', conf, problem=(1, 1)) + self.check('---\ntext\n', conf) + self.check('---\r\ntext\r\n', conf, problem1=(1, 4), problem2=(2, 5)) + def test_unix_type_required_st_sp(self): # If we find a CRLF when looking for Unix newlines, yamllint # should always raise, regardless of logic with @@ -58,7 +69,7 @@ def test_dos_type(self): self.check('\r', conf) self.check('\n', conf, problem=(1, 1)) self.check('\r\n', conf) - self.check('---\ntext\n', conf, problem=(1, 4)) + self.check('---\ntext\n', conf, problem1=(1, 4)) self.check('---\r\ntext\r\n', conf) def test_platform_type(self): @@ -72,14 +83,10 @@ def test_platform_type(self): self.check('\n', conf) self.check('\r\n', conf, problem=(1, 1)) self.check('---\ntext\n', conf) - self.check('---\r\ntext\r\n', conf, problem=(1, 4)) + self.check('---\r\n#\r\n', conf, problem=(1, 4)) self.check('---\r\ntext\n', conf, problem=(1, 4)) - # FIXME: the following tests currently don't work - # because only the first line is checked for line-endings - # see: issue #475 - # --- - # self.check('---\ntext\r\nfoo\n', conf, problem=(2, 4)) - # self.check('---\ntext\r\n', conf, problem=(2, 4)) + self.check('---\ntext\r\nfoo\n', conf, problem=(2, 5)) + self.check('---\ntext\r\n', conf, problem=(2, 5)) # mock the Windows new-line-character with mock.patch('yamllint.rules.new_lines.linesep', '\r\n'): @@ -88,9 +95,5 @@ def test_platform_type(self): self.check('---\r\ntext\r\n', conf) self.check('---\ntext\n', conf, problem=(1, 4)) self.check('---\ntext\r\n', conf, problem=(1, 4)) - # FIXME: the following tests currently don't work - # because only the first line is checked for line-endings - # see: issue #475 - # --- - # self.check('---\r\ntext\nfoo\r\n', conf, problem=(2, 4)) - # self.check('---\r\ntext\n', conf, problem=(2, 4)) + self.check('---\r\ntext\nfoo\r\n', conf, problem=(2, 5)) + self.check('---\r\ntext\n', conf, problem=(2, 5)) diff --git a/yamllint/linter.py b/yamllint/linter.py index a2faa061..4ea4e454 100644 --- a/yamllint/linter.py +++ b/yamllint/linter.py @@ -104,6 +104,10 @@ def process_comment(self, comment): for id in rules: self.rules.discard(id) + def disable_by_force(self, rule): + if rule in self.all_rules: + self.rules.add(rule) + def is_disabled_by_directive(self, problem): return problem.rule in self.rules @@ -166,6 +170,9 @@ def process_comment(self, comment): for problem in cache: if not (disabled_for_line.is_disabled_by_directive(problem) or disabled.is_disabled_by_directive(problem)): + rule_conf = conf.rules[problem.rule] + if rule_conf.get('disable_after_first_occurence', False): + disabled.disable_by_force(problem.rule) yield problem disabled_for_line = disabled_for_next_line diff --git a/yamllint/rules/new_lines.py b/yamllint/rules/new_lines.py index 2ee5512a..7db3158f 100644 --- a/yamllint/rules/new_lines.py +++ b/yamllint/rules/new_lines.py @@ -39,8 +39,9 @@ ID = 'new-lines' TYPE = 'line' -CONF = {'type': ('unix', 'dos', 'platform')} -DEFAULT = {'type': 'unix'} +CONF = {'type': ('unix', 'dos', 'platform'), + 'disable_after_first_occurence': (True, False)} +DEFAULT = {'type': 'unix', 'disable_after_first_occurence': True} def check(conf, line): @@ -51,8 +52,8 @@ def check(conf, line): elif conf['type'] == 'dos': newline_char = '\r\n' - if line.start == 0 and len(line.buffer) > line.end: + if len(line.buffer) > line.end: if line.buffer[line.end:line.end + len(newline_char)] != newline_char: c = repr(newline_char).strip('\'') - yield LintProblem(1, line.end - line.start + 1, + yield LintProblem(line.line_no, line.end - line.start + 1, f'wrong new line character: expected {c}')