Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
60b72daad4 | ||
|
|
773bb8a648 | ||
|
|
d3cd8ba332 | ||
|
|
e56a7c788c | ||
|
|
d017631aff | ||
|
|
5b98cd2053 | ||
|
|
82dd7dbf16 | ||
|
|
4533b8ae49 | ||
|
|
a2c68fdf9b | ||
|
|
82ed191bc9 | ||
|
|
92ff315fb4 | ||
|
|
f4cebdc054 | ||
|
|
d174f9e3e3 | ||
|
|
c8ba8f7e99 |
@@ -31,7 +31,10 @@ Unless told otherwise, yamllint uses its ``default`` configuration:
|
|||||||
Details on rules can be found on :doc:`the rules page <rules>`.
|
Details on rules can be found on :doc:`the rules page <rules>`.
|
||||||
|
|
||||||
There is another pre-defined configuration named ``relaxed``. As its name
|
There is another pre-defined configuration named ``relaxed``. As its name
|
||||||
suggests, it is more tolerant.
|
suggests, it is more tolerant:
|
||||||
|
|
||||||
|
.. literalinclude:: ../yamllint/conf/relaxed.yaml
|
||||||
|
:language: yaml
|
||||||
|
|
||||||
It can be chosen using:
|
It can be chosen using:
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (C) 2016 Adrien Vergé
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import locale
|
||||||
|
|
||||||
|
|
||||||
|
locale.setlocale(locale.LC_ALL, 'C')
|
||||||
|
|||||||
@@ -35,6 +35,10 @@ class CommentsTestCase(RuleTestCase):
|
|||||||
' #comment 3 bis\n'
|
' #comment 3 bis\n'
|
||||||
' # comment 3 ter\n'
|
' # comment 3 ter\n'
|
||||||
'\n'
|
'\n'
|
||||||
|
'################################\n'
|
||||||
|
'## comment 4\n'
|
||||||
|
'##comment 5\n'
|
||||||
|
'\n'
|
||||||
'string: "Une longue phrase." # this is French\n', conf)
|
'string: "Une longue phrase." # this is French\n', conf)
|
||||||
|
|
||||||
def test_starting_space(self):
|
def test_starting_space(self):
|
||||||
@@ -52,7 +56,11 @@ class CommentsTestCase(RuleTestCase):
|
|||||||
'# comment 2\n'
|
'# comment 2\n'
|
||||||
'# comment 3\n'
|
'# comment 3\n'
|
||||||
' # comment 3 bis\n'
|
' # comment 3 bis\n'
|
||||||
' # comment 3 ter\n', conf)
|
' # comment 3 ter\n'
|
||||||
|
'\n'
|
||||||
|
'################################\n'
|
||||||
|
'## comment 4\n'
|
||||||
|
'## comment 5\n', conf)
|
||||||
self.check('---\n'
|
self.check('---\n'
|
||||||
'#comment\n'
|
'#comment\n'
|
||||||
'\n'
|
'\n'
|
||||||
@@ -63,9 +71,14 @@ class CommentsTestCase(RuleTestCase):
|
|||||||
'# comment 2\n'
|
'# comment 2\n'
|
||||||
'#comment 3\n'
|
'#comment 3\n'
|
||||||
' #comment 3 bis\n'
|
' #comment 3 bis\n'
|
||||||
' # comment 3 ter\n', conf,
|
' # comment 3 ter\n'
|
||||||
|
'\n'
|
||||||
|
'################################\n'
|
||||||
|
'## comment 4\n'
|
||||||
|
'##comment 5\n', conf,
|
||||||
problem1=(2, 2), problem2=(6, 13),
|
problem1=(2, 2), problem2=(6, 13),
|
||||||
problem4=(9, 2), problem5=(10, 4))
|
problem3=(9, 2), problem4=(10, 4),
|
||||||
|
problem5=(15, 3))
|
||||||
|
|
||||||
def test_spaces_from_content(self):
|
def test_spaces_from_content(self):
|
||||||
conf = ('comments:\n'
|
conf = ('comments:\n'
|
||||||
@@ -106,13 +119,18 @@ class CommentsTestCase(RuleTestCase):
|
|||||||
' #comment 3 bis\n'
|
' #comment 3 bis\n'
|
||||||
' # comment 3 ter\n'
|
' # comment 3 ter\n'
|
||||||
'\n'
|
'\n'
|
||||||
|
'################################\n'
|
||||||
|
'## comment 4\n'
|
||||||
|
'##comment 5\n'
|
||||||
|
'\n'
|
||||||
'string: "Une longue phrase." # this is French\n', conf,
|
'string: "Une longue phrase." # this is French\n', conf,
|
||||||
problem1=(2, 2),
|
problem1=(2, 2),
|
||||||
problem2=(4, 7),
|
problem2=(4, 7),
|
||||||
problem3=(6, 11), problem4=(6, 12),
|
problem3=(6, 11), problem4=(6, 12),
|
||||||
problem5=(9, 2),
|
problem5=(9, 2),
|
||||||
problem6=(10, 4),
|
problem6=(10, 4),
|
||||||
problem7=(13, 30))
|
problem7=(15, 3),
|
||||||
|
problem8=(17, 30))
|
||||||
|
|
||||||
def test_empty_comment(self):
|
def test_empty_comment(self):
|
||||||
conf = ('comments:\n'
|
conf = ('comments:\n'
|
||||||
@@ -132,6 +150,14 @@ class CommentsTestCase(RuleTestCase):
|
|||||||
' min-spaces-from-content: 2\n')
|
' min-spaces-from-content: 2\n')
|
||||||
self.check('# comment\n', conf)
|
self.check('# comment\n', conf)
|
||||||
|
|
||||||
|
def test_last_line(self):
|
||||||
|
conf = ('comments:\n'
|
||||||
|
' require-starting-space: yes\n'
|
||||||
|
' min-spaces-from-content: 2\n'
|
||||||
|
'new-line-at-end-of-file: disable\n')
|
||||||
|
self.check('# comment with no newline char:\n'
|
||||||
|
'#', conf)
|
||||||
|
|
||||||
def test_multi_line_scalar(self):
|
def test_multi_line_scalar(self):
|
||||||
conf = ('comments:\n'
|
conf = ('comments:\n'
|
||||||
' require-starting-space: yes\n'
|
' require-starting-space: yes\n'
|
||||||
|
|||||||
@@ -84,6 +84,9 @@ class LineLengthTestCase(RuleTestCase):
|
|||||||
'another:\n'
|
'another:\n'
|
||||||
' - https://localhost/very/very/long/url\n'
|
' - https://localhost/very/very/long/url\n'
|
||||||
'...\n', conf)
|
'...\n', conf)
|
||||||
|
self.check('---\n'
|
||||||
|
'long_line: http://localhost/very/very/long/url\n', conf,
|
||||||
|
problem=(2, 21))
|
||||||
|
|
||||||
conf = 'line-length: {max: 20, allow-non-breakable-words: no}'
|
conf = 'line-length: {max: 20, allow-non-breakable-words: no}'
|
||||||
self.check('---\n' + 30 * 'A' + '\n', conf, problem=(2, 21))
|
self.check('---\n' + 30 * 'A' + '\n', conf, problem=(2, 21))
|
||||||
@@ -106,3 +109,39 @@ class LineLengthTestCase(RuleTestCase):
|
|||||||
'another:\n'
|
'another:\n'
|
||||||
' - https://localhost/very/very/long/url\n'
|
' - https://localhost/very/very/long/url\n'
|
||||||
'...\n', conf, problem=(5, 21))
|
'...\n', conf, problem=(5, 21))
|
||||||
|
self.check('---\n'
|
||||||
|
'long_line: http://localhost/very/very/long/url\n'
|
||||||
|
'...\n', conf, problem=(2, 21))
|
||||||
|
|
||||||
|
conf = ('line-length: {max: 20, allow-non-breakable-words: yes}\n'
|
||||||
|
'trailing-spaces: disable')
|
||||||
|
self.check('---\n'
|
||||||
|
'loooooooooong+word+and+some+space+at+the+end \n',
|
||||||
|
conf, problem=(2, 21))
|
||||||
|
|
||||||
|
def test_non_breakable_inline_mappings(self):
|
||||||
|
conf = 'line-length: {max: 20, ' \
|
||||||
|
'allow-non-breakable-inline-mappings: yes}'
|
||||||
|
self.check('---\n'
|
||||||
|
'long_line: http://localhost/very/very/long/url\n'
|
||||||
|
'long line: http://localhost/very/very/long/url\n', conf)
|
||||||
|
self.check('---\n'
|
||||||
|
'- long line: http://localhost/very/very/long/url\n', conf)
|
||||||
|
|
||||||
|
self.check('---\n'
|
||||||
|
'long_line: http://localhost/short/url + word\n'
|
||||||
|
'long line: http://localhost/short/url + word\n',
|
||||||
|
conf, problem1=(2, 21), problem2=(3, 21))
|
||||||
|
|
||||||
|
conf = ('line-length: {max: 20,'
|
||||||
|
' allow-non-breakable-inline-mappings: yes}\n'
|
||||||
|
'trailing-spaces: disable')
|
||||||
|
self.check('---\n'
|
||||||
|
'long_line: and+some+space+at+the+end \n',
|
||||||
|
conf, problem=(2, 21))
|
||||||
|
self.check('---\n'
|
||||||
|
'long line: and+some+space+at+the+end \n',
|
||||||
|
conf, problem=(2, 21))
|
||||||
|
self.check('---\n'
|
||||||
|
'- long line: and+some+space+at+the+end \n',
|
||||||
|
conf, problem=(2, 21))
|
||||||
|
|||||||
@@ -18,7 +18,10 @@ try:
|
|||||||
from cStringIO import StringIO
|
from cStringIO import StringIO
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
|
import fcntl
|
||||||
|
import locale
|
||||||
import os
|
import os
|
||||||
|
import pty
|
||||||
import shutil
|
import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
import unittest
|
import unittest
|
||||||
@@ -64,6 +67,15 @@ class CommandLineTestCase(unittest.TestCase):
|
|||||||
f.write('---\n'
|
f.write('---\n'
|
||||||
'key: value\n')
|
'key: value\n')
|
||||||
|
|
||||||
|
# non-ASCII chars
|
||||||
|
os.mkdir(os.path.join(self.wd, 'non-ascii'))
|
||||||
|
with open(os.path.join(self.wd, 'non-ascii', 'utf-8'), 'wb') as f:
|
||||||
|
f.write((u'---\n'
|
||||||
|
u'- hétérogénéité\n'
|
||||||
|
u'# 19.99 €\n'
|
||||||
|
u'- お早う御座います。\n'
|
||||||
|
u'# الأَبْجَدِيَّة العَرَبِيَّة\n').encode('utf-8'))
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
shutil.rmtree(self.wd)
|
shutil.rmtree(self.wd)
|
||||||
|
|
||||||
@@ -261,6 +273,26 @@ class CommandLineTestCase(unittest.TestCase):
|
|||||||
self.assertEqual(out, '')
|
self.assertEqual(out, '')
|
||||||
self.assertEqual(err, '')
|
self.assertEqual(err, '')
|
||||||
|
|
||||||
|
def test_run_non_ascii_file(self):
|
||||||
|
file = os.path.join(self.wd, 'non-ascii', 'utf-8')
|
||||||
|
|
||||||
|
# Make sure the default localization conditions on this "system"
|
||||||
|
# support UTF-8 encoding.
|
||||||
|
loc = locale.getlocale()
|
||||||
|
locale.setlocale(locale.LC_ALL, 'C.UTF-8')
|
||||||
|
|
||||||
|
sys.stdout, sys.stderr = StringIO(), StringIO()
|
||||||
|
with self.assertRaises(SystemExit) as ctx:
|
||||||
|
cli.run(('-f', 'parsable', file))
|
||||||
|
|
||||||
|
locale.setlocale(locale.LC_ALL, loc)
|
||||||
|
|
||||||
|
self.assertEqual(ctx.exception.code, 0)
|
||||||
|
|
||||||
|
out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
|
||||||
|
self.assertEqual(out, '')
|
||||||
|
self.assertEqual(err, '')
|
||||||
|
|
||||||
def test_run_multiple_files(self):
|
def test_run_multiple_files(self):
|
||||||
items = [os.path.join(self.wd, 'empty.yml'),
|
items = [os.path.join(self.wd, 'empty.yml'),
|
||||||
os.path.join(self.wd, 's')]
|
os.path.join(self.wd, 's')]
|
||||||
@@ -278,7 +310,7 @@ class CommandLineTestCase(unittest.TestCase):
|
|||||||
'(key-duplicates)\n') % file)
|
'(key-duplicates)\n') % file)
|
||||||
self.assertEqual(err, '')
|
self.assertEqual(err, '')
|
||||||
|
|
||||||
def test_run_colored_output(self):
|
def test_run_piped_output_nocolor(self):
|
||||||
file = os.path.join(self.wd, 'a.yaml')
|
file = os.path.join(self.wd, 'a.yaml')
|
||||||
|
|
||||||
sys.stdout, sys.stderr = StringIO(), StringIO()
|
sys.stdout, sys.stderr = StringIO(), StringIO()
|
||||||
@@ -288,6 +320,38 @@ class CommandLineTestCase(unittest.TestCase):
|
|||||||
self.assertEqual(ctx.exception.code, 1)
|
self.assertEqual(ctx.exception.code, 1)
|
||||||
|
|
||||||
out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
|
out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
|
||||||
|
self.assertEqual(out, (
|
||||||
|
'%s\n'
|
||||||
|
' 2:4 error trailing spaces (trailing-spaces)\n'
|
||||||
|
' 3:4 error no new line character at the end of file '
|
||||||
|
'(new-line-at-end-of-file)\n'
|
||||||
|
'\n' % file))
|
||||||
|
self.assertEqual(err, '')
|
||||||
|
|
||||||
|
def test_run_colored_output(self):
|
||||||
|
file = os.path.join(self.wd, 'a.yaml')
|
||||||
|
|
||||||
|
# Create a pseudo-TTY and redirect stdout to it
|
||||||
|
master, slave = pty.openpty()
|
||||||
|
sys.stdout = sys.stderr = os.fdopen(slave, 'w')
|
||||||
|
|
||||||
|
with self.assertRaises(SystemExit) as ctx:
|
||||||
|
cli.run((file, ))
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
self.assertEqual(ctx.exception.code, 1)
|
||||||
|
|
||||||
|
# Read output from TTY
|
||||||
|
output = os.fdopen(master, 'r')
|
||||||
|
flag = fcntl.fcntl(master, fcntl.F_GETFD)
|
||||||
|
fcntl.fcntl(master, fcntl.F_SETFL, flag | os.O_NONBLOCK)
|
||||||
|
|
||||||
|
out = output.read().replace('\r\n', '\n')
|
||||||
|
|
||||||
|
sys.stdout.close()
|
||||||
|
sys.stderr.close()
|
||||||
|
output.close()
|
||||||
|
|
||||||
self.assertEqual(out, (
|
self.assertEqual(out, (
|
||||||
'\033[4m%s\033[0m\n'
|
'\033[4m%s\033[0m\n'
|
||||||
' \033[2m2:4\033[0m \033[31merror\033[0m '
|
' \033[2m2:4\033[0m \033[31merror\033[0m '
|
||||||
@@ -296,4 +360,3 @@ class CommandLineTestCase(unittest.TestCase):
|
|||||||
'no new line character at the end of file '
|
'no new line character at the end of file '
|
||||||
'\033[2m(new-line-at-end-of-file)\033[0m\n'
|
'\033[2m(new-line-at-end-of-file)\033[0m\n'
|
||||||
'\n' % file))
|
'\n' % file))
|
||||||
self.assertEqual(err, '')
|
|
||||||
|
|||||||
@@ -44,3 +44,15 @@ class LinterTestCase(unittest.TestCase):
|
|||||||
def test_run_on_list(self):
|
def test_run_on_list(self):
|
||||||
self.assertRaises(TypeError, linter.run,
|
self.assertRaises(TypeError, linter.run,
|
||||||
['h', 'e', 'l', 'l', 'o'], self.fake_config())
|
['h', 'e', 'l', 'l', 'o'], self.fake_config())
|
||||||
|
|
||||||
|
def test_run_on_non_ascii_chars(self):
|
||||||
|
s = (u'- hétérogénéité\n'
|
||||||
|
u'# 19.99 €\n')
|
||||||
|
linter.run(s, self.fake_config())
|
||||||
|
linter.run(s.encode('utf-8'), self.fake_config())
|
||||||
|
linter.run(s.encode('iso-8859-15'), self.fake_config())
|
||||||
|
|
||||||
|
s = (u'- お早う御座います。\n'
|
||||||
|
u'# الأَبْجَدِيَّة العَرَبِيَّة\n')
|
||||||
|
linter.run(s, self.fake_config())
|
||||||
|
linter.run(s.encode('utf-8'), self.fake_config())
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ indentation, etc."""
|
|||||||
|
|
||||||
|
|
||||||
APP_NAME = 'yamllint'
|
APP_NAME = 'yamllint'
|
||||||
APP_VERSION = '1.3.0'
|
APP_VERSION = '1.4.0'
|
||||||
APP_DESCRIPTION = __doc__
|
APP_DESCRIPTION = __doc__
|
||||||
|
|
||||||
__author__ = u'Adrien Vergé'
|
__author__ = u'Adrien Vergé'
|
||||||
|
|||||||
@@ -48,6 +48,17 @@ class Format(object):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def standard(problem, filename):
|
def standard(problem, filename):
|
||||||
|
line = ' %d:%d' % (problem.line, problem.column)
|
||||||
|
line += max(12 - len(line), 0) * ' '
|
||||||
|
line += problem.level
|
||||||
|
line += max(21 - len(line), 0) * ' '
|
||||||
|
line += problem.desc
|
||||||
|
if problem.rule:
|
||||||
|
line += ' (%s)' % problem.rule
|
||||||
|
return line
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def standard_color(problem, filename):
|
||||||
line = ' \033[2m%d:%d\033[0m' % (problem.line, problem.column)
|
line = ' \033[2m%d:%d\033[0m' % (problem.line, problem.column)
|
||||||
line += max(20 - len(line), 0) * ' '
|
line += max(20 - len(line), 0) * ' '
|
||||||
if problem.level == 'warning':
|
if problem.level == 'warning':
|
||||||
@@ -119,11 +130,17 @@ def run(argv=None):
|
|||||||
for problem in linter.run(f, conf):
|
for problem in linter.run(f, conf):
|
||||||
if args.format == 'parsable':
|
if args.format == 'parsable':
|
||||||
print(Format.parsable(problem, file))
|
print(Format.parsable(problem, file))
|
||||||
else:
|
elif sys.stdout.isatty():
|
||||||
if first:
|
if first:
|
||||||
print('\033[4m%s\033[0m' % file)
|
print('\033[4m%s\033[0m' % file)
|
||||||
first = False
|
first = False
|
||||||
|
|
||||||
|
print(Format.standard_color(problem, file))
|
||||||
|
else:
|
||||||
|
if first:
|
||||||
|
print(file)
|
||||||
|
first = False
|
||||||
|
|
||||||
print(Format.standard(problem, file))
|
print(Format.standard(problem, file))
|
||||||
|
|
||||||
if return_code == 0 and problem.level == 'error':
|
if return_code == 0 and problem.level == 'error':
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ rules:
|
|||||||
line-length:
|
line-length:
|
||||||
max: 80
|
max: 80
|
||||||
allow-non-breakable-words: yes
|
allow-non-breakable-words: yes
|
||||||
|
allow-non-breakable-inline-mappings: no
|
||||||
new-line-at-end-of-file: enable
|
new-line-at-end-of-file: enable
|
||||||
new-lines:
|
new-lines:
|
||||||
type: unix
|
type: unix
|
||||||
|
|||||||
@@ -25,3 +25,4 @@ rules:
|
|||||||
indent-sequences: consistent
|
indent-sequences: consistent
|
||||||
line-length:
|
line-length:
|
||||||
level: warning
|
level: warning
|
||||||
|
allow-non-breakable-inline-mappings: yes
|
||||||
|
|||||||
@@ -71,7 +71,10 @@ def get_costemic_problems(buffer, conf):
|
|||||||
self.all_rules = set([r.ID for r in rules])
|
self.all_rules = set([r.ID for r in rules])
|
||||||
|
|
||||||
def process_comment(self, comment):
|
def process_comment(self, comment):
|
||||||
comment = repr(comment)
|
try:
|
||||||
|
comment = str(comment)
|
||||||
|
except UnicodeError:
|
||||||
|
return # this certainly wasn't a yamllint directive comment
|
||||||
|
|
||||||
if re.match(r'^# yamllint disable( rule:\S+)*\s*$', comment):
|
if re.match(r'^# yamllint disable( rule:\S+)*\s*$', comment):
|
||||||
rules = [item[5:] for item in comment[18:].split(' ')][1:]
|
rules = [item[5:] for item in comment[18:].split(' ')][1:]
|
||||||
@@ -95,7 +98,10 @@ def get_costemic_problems(buffer, conf):
|
|||||||
|
|
||||||
class DisableLineDirective(DisableDirective):
|
class DisableLineDirective(DisableDirective):
|
||||||
def process_comment(self, comment):
|
def process_comment(self, comment):
|
||||||
comment = repr(comment)
|
try:
|
||||||
|
comment = str(comment)
|
||||||
|
except UnicodeError:
|
||||||
|
return # this certainly wasn't a yamllint directive comment
|
||||||
|
|
||||||
if re.match(r'^# yamllint disable-line( rule:\S+)*\s*$', comment):
|
if re.match(r'^# yamllint disable-line( rule:\S+)*\s*$', comment):
|
||||||
rules = [item[5:] for item in comment[23:].split(' ')][1:]
|
rules = [item[5:] for item in comment[23:].split(' ')][1:]
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ class Comment(object):
|
|||||||
self.token_after = token_after
|
self.token_after = token_after
|
||||||
self.comment_before = comment_before
|
self.comment_before = comment_before
|
||||||
|
|
||||||
def __repr__(self):
|
def __str__(self):
|
||||||
end = self.buffer.find('\n', self.pointer)
|
end = self.buffer.find('\n', self.pointer)
|
||||||
if end == -1:
|
if end == -1:
|
||||||
end = self.buffer.find('\0', self.pointer)
|
end = self.buffer.find('\0', self.pointer)
|
||||||
|
|||||||
@@ -35,6 +35,12 @@ Use this rule to control the position and formatting of comments.
|
|||||||
# This sentence
|
# This sentence
|
||||||
# is a block comment
|
# is a block comment
|
||||||
|
|
||||||
|
the following code snippet would **PASS**:
|
||||||
|
::
|
||||||
|
|
||||||
|
##############################
|
||||||
|
## This is some documentation
|
||||||
|
|
||||||
the following code snippet would **FAIL**:
|
the following code snippet would **FAIL**:
|
||||||
::
|
::
|
||||||
|
|
||||||
@@ -71,9 +77,13 @@ def check(conf, comment):
|
|||||||
yield LintProblem(comment.line_no, comment.column_no,
|
yield LintProblem(comment.line_no, comment.column_no,
|
||||||
'too few spaces before comment')
|
'too few spaces before comment')
|
||||||
|
|
||||||
if (conf['require-starting-space'] and
|
if conf['require-starting-space']:
|
||||||
comment.pointer + 1 < len(comment.buffer) and
|
text_start = comment.pointer + 1
|
||||||
comment.buffer[comment.pointer + 1] != ' ' and
|
while (comment.buffer[text_start] == '#' and
|
||||||
comment.buffer[comment.pointer + 1] != '\n'):
|
text_start < len(comment.buffer)):
|
||||||
yield LintProblem(comment.line_no, comment.column_no + 1,
|
text_start += 1
|
||||||
'missing starting space in comment')
|
if (text_start < len(comment.buffer) and
|
||||||
|
comment.buffer[text_start] not in (' ', '\n', '\0')):
|
||||||
|
yield LintProblem(comment.line_no,
|
||||||
|
comment.column_no + text_start - comment.pointer,
|
||||||
|
'missing starting space in comment')
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ Use this rule to set a limit to lines length.
|
|||||||
* ``allow-non-breakable-words`` is used to allow non breakable words (without
|
* ``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
|
spaces inside) to overflow the limit. This is useful for long URLs, for
|
||||||
instance. Use ``yes`` to allow, ``no`` to forbid.
|
instance. Use ``yes`` to allow, ``no`` to forbid.
|
||||||
|
* ``allow-non-breakable-inline-mappings`` implies ``allow-non-breakable-words``
|
||||||
|
and extends it to also allow non-breakable words in inline mappings.
|
||||||
|
|
||||||
.. rubric:: Examples
|
.. rubric:: Examples
|
||||||
|
|
||||||
@@ -61,6 +63,19 @@ Use this rule to set a limit to lines length.
|
|||||||
|
|
||||||
- this line is waaaaaaaaaaaaaay too long but could be easily split...
|
- this line is waaaaaaaaaaaaaay too long but could be easily split...
|
||||||
|
|
||||||
|
and the following code snippet would also **FAIL**:
|
||||||
|
::
|
||||||
|
|
||||||
|
- foobar: http://localhost/very/very/very/very/very/very/very/very/long/url
|
||||||
|
|
||||||
|
#. With ``line-length: {max: 60, allow-non-breakable-words: yes,
|
||||||
|
allow-non-breakable-inline-mappings: yes}``
|
||||||
|
|
||||||
|
the following code snippet would **PASS**:
|
||||||
|
::
|
||||||
|
|
||||||
|
- foobar: http://localhost/very/very/very/very/very/very/very/very/long/url
|
||||||
|
|
||||||
#. With ``line-length: {max: 60, allow-non-breakable-words: no}``
|
#. With ``line-length: {max: 60, allow-non-breakable-words: no}``
|
||||||
|
|
||||||
the following code snippet would **FAIL**:
|
the following code snippet would **FAIL**:
|
||||||
@@ -73,17 +88,34 @@ Use this rule to set a limit to lines length.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
|
||||||
from yamllint.linter import LintProblem
|
from yamllint.linter import LintProblem
|
||||||
|
|
||||||
|
|
||||||
ID = 'line-length'
|
ID = 'line-length'
|
||||||
TYPE = 'line'
|
TYPE = 'line'
|
||||||
CONF = {'max': int,
|
CONF = {'max': int,
|
||||||
'allow-non-breakable-words': bool}
|
'allow-non-breakable-words': bool,
|
||||||
|
'allow-non-breakable-inline-mappings': bool}
|
||||||
|
|
||||||
|
|
||||||
|
def check_inline_mapping(line):
|
||||||
|
loader = yaml.SafeLoader(line.content)
|
||||||
|
while loader.peek_token():
|
||||||
|
if isinstance(loader.get_token(), yaml.BlockMappingStartToken):
|
||||||
|
while loader.peek_token():
|
||||||
|
if isinstance(loader.get_token(), yaml.ValueToken):
|
||||||
|
t = loader.get_token()
|
||||||
|
if isinstance(t, yaml.ScalarToken):
|
||||||
|
return ' ' not in line.content[t.start_mark.column:]
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def check(conf, line):
|
def check(conf, line):
|
||||||
if line.end - line.start > conf['max']:
|
if line.end - line.start > conf['max']:
|
||||||
|
conf['allow-non-breakable-words'] |= \
|
||||||
|
conf['allow-non-breakable-inline-mappings']
|
||||||
if conf['allow-non-breakable-words']:
|
if conf['allow-non-breakable-words']:
|
||||||
start = line.start
|
start = line.start
|
||||||
while start < line.end and line.buffer[start] == ' ':
|
while start < line.end and line.buffer[start] == ' ':
|
||||||
@@ -96,6 +128,10 @@ def check(conf, line):
|
|||||||
if line.buffer.find(' ', start, line.end) == -1:
|
if line.buffer.find(' ', start, line.end) == -1:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if (conf['allow-non-breakable-inline-mappings'] and
|
||||||
|
check_inline_mapping(line)):
|
||||||
|
return
|
||||||
|
|
||||||
yield LintProblem(line.line_no, conf['max'] + 1,
|
yield LintProblem(line.line_no, conf['max'] + 1,
|
||||||
'line too long (%d > %d characters)' %
|
'line too long (%d > %d characters)' %
|
||||||
(line.end - line.start, conf['max']))
|
(line.end - line.start, conf['max']))
|
||||||
|
|||||||
Reference in New Issue
Block a user