mirror of
https://github.com/codespell-project/codespell.git
synced 2025-08-06 09:40:56 +08:00
* Add context options: -A/-B/-C; Fixes #287 * Fix indentation of line continuation. * Fix 'only before context' case. * Add some tests for the new context options. * Refactor context code (pass context tuple, instead of before/after variables) * Get rid of 'remove temp file code' in context test. * Fix reintroduced error (regarding 'only before context').
This commit is contained in:

committed by
Eric Larson

parent
c3e589d066
commit
e74f433bb8
@ -283,6 +283,12 @@ def parse_options(args):
|
||||
action='store_true', default=False,
|
||||
help='Check hidden files (those starting with ".") as '
|
||||
'well.')
|
||||
parser.add_option('-A', '--after-context', metavar='LINES',
|
||||
help='print LINES of trailing context', type='int')
|
||||
parser.add_option('-B', '--before-context', metavar='LINES',
|
||||
help='print LINES of leading context', type='int')
|
||||
parser.add_option('-C', '--context', metavar='LINES',
|
||||
help='print LINES of surrounding context', type='int')
|
||||
|
||||
(o, args) = parser.parse_args(list(args))
|
||||
|
||||
@ -411,8 +417,15 @@ def ask_for_word_fix(line, wrongword, misspelling, interactivity):
|
||||
return misspelling.fix, fix_case(wrongword, misspelling.data)
|
||||
|
||||
|
||||
def print_context(lines, index, context):
|
||||
# context = (context_before, context_after)
|
||||
for i in range(index - context[0], index + context[1] + 1):
|
||||
if 0 <= i < len(lines):
|
||||
print('%s %s' % ('>' if i == index else ':', lines[i].rstrip()))
|
||||
|
||||
|
||||
def parse_file(filename, colors, summary, misspellings, exclude_lines,
|
||||
file_opener, word_regex, options):
|
||||
file_opener, word_regex, context, options):
|
||||
bad_count = 0
|
||||
lines = None
|
||||
changed = False
|
||||
@ -479,10 +492,14 @@ def parse_file(filename, colors, summary, misspellings, exclude_lines,
|
||||
for word in word_regex.findall(line):
|
||||
lword = word.lower()
|
||||
if lword in misspellings:
|
||||
context_shown = False
|
||||
fix = misspellings[lword].fix
|
||||
fixword = fix_case(word, misspellings[lword].data)
|
||||
|
||||
if options.interactive and lword not in asked_for:
|
||||
if context is not None:
|
||||
context_shown = True
|
||||
print_context(lines, i, context)
|
||||
fix, fixword = ask_for_word_fix(
|
||||
lines[i], word, misspellings[lword],
|
||||
options.interactive)
|
||||
@ -527,6 +544,8 @@ def parse_file(filename, colors, summary, misspellings, exclude_lines,
|
||||
# our bad_count and thus return value
|
||||
bad_count += 1
|
||||
|
||||
if (not context_shown) and (context is not None):
|
||||
print_context(lines, i, context)
|
||||
if filename != '-':
|
||||
print("%(FILENAME)s:%(LINE)s: %(WRONGWORD)s "
|
||||
" ==> %(RIGHTWORD)s%(REASON)s"
|
||||
@ -613,6 +632,26 @@ def main(*args):
|
||||
else:
|
||||
summary = None
|
||||
|
||||
context = None
|
||||
if options.context is not None:
|
||||
if (options.before_context is not None) or \
|
||||
(options.after_context is not None):
|
||||
print('ERROR: --context/-C cannot be used together with '
|
||||
'--context-before/-B or --context-after/-A')
|
||||
parser.print_help()
|
||||
return 1
|
||||
context_both = max(0, options.context)
|
||||
context = (context_both, context_both)
|
||||
elif (options.before_context is not None) or \
|
||||
(options.after_context is not None):
|
||||
context_before = 0
|
||||
context_after = 0
|
||||
if options.before_context is not None:
|
||||
context_before = max(0, options.before_context)
|
||||
if options.after_context is not None:
|
||||
context_after = max(0, options.after_context)
|
||||
context = (context_before, context_after)
|
||||
|
||||
exclude_lines = set()
|
||||
if options.exclude_file:
|
||||
build_exclude_hashes(options.exclude_file, exclude_lines)
|
||||
@ -642,7 +681,7 @@ def main(*args):
|
||||
continue
|
||||
bad_count += parse_file(
|
||||
fname, colors, summary, misspellings, exclude_lines,
|
||||
file_opener, word_regex, options)
|
||||
file_opener, word_regex, context, options)
|
||||
|
||||
# skip (relative) directories
|
||||
dirs[:] = [dir_ for dir_ in dirs if not glob_match.match(dir_)]
|
||||
@ -650,7 +689,7 @@ def main(*args):
|
||||
else:
|
||||
bad_count += parse_file(
|
||||
filename, colors, summary, misspellings, exclude_lines,
|
||||
file_opener, word_regex, options)
|
||||
file_opener, word_regex, context, options)
|
||||
|
||||
if summary:
|
||||
print("\n-------8<-------\nSUMMARY:")
|
||||
|
@ -302,6 +302,65 @@ def test_case_handling(tmpdir, capsys):
|
||||
os.remove(f.name)
|
||||
|
||||
|
||||
def test_context(tmpdir, capsys):
|
||||
"""Test context options."""
|
||||
d = str(tmpdir)
|
||||
with open(op.join(d, 'context.txt'), 'w') as f:
|
||||
f.write('line 1\nline 2\nline 3 abandonned\nline 4\nline 5')
|
||||
|
||||
# symmetric context, fully within file
|
||||
cs.main('-C', '1', d)
|
||||
lines = capsys.readouterr()[0].split('\n')
|
||||
assert len(lines) == 5
|
||||
assert lines[0] == ': line 2'
|
||||
assert lines[1] == '> line 3 abandonned'
|
||||
assert lines[2] == ': line 4'
|
||||
|
||||
# requested context is bigger than the file
|
||||
cs.main('-C', '10', d)
|
||||
lines = capsys.readouterr()[0].split('\n')
|
||||
assert len(lines) == 7
|
||||
assert lines[0] == ': line 1'
|
||||
assert lines[1] == ': line 2'
|
||||
assert lines[2] == '> line 3 abandonned'
|
||||
assert lines[3] == ': line 4'
|
||||
assert lines[4] == ': line 5'
|
||||
|
||||
# only before context
|
||||
cs.main('-B', '2', d)
|
||||
lines = capsys.readouterr()[0].split('\n')
|
||||
assert len(lines) == 5
|
||||
assert lines[0] == ': line 1'
|
||||
assert lines[1] == ': line 2'
|
||||
assert lines[2] == '> line 3 abandonned'
|
||||
|
||||
# only after context
|
||||
cs.main('-A', '1', d)
|
||||
lines = capsys.readouterr()[0].split('\n')
|
||||
assert len(lines) == 4
|
||||
assert lines[0] == '> line 3 abandonned'
|
||||
assert lines[1] == ': line 4'
|
||||
|
||||
# asymmetric context
|
||||
cs.main('-B', '2', '-A', '1', d)
|
||||
lines = capsys.readouterr()[0].split('\n')
|
||||
assert len(lines) == 6
|
||||
assert lines[0] == ': line 1'
|
||||
assert lines[1] == ': line 2'
|
||||
assert lines[2] == '> line 3 abandonned'
|
||||
assert lines[3] == ': line 4'
|
||||
|
||||
# both '-C' and '-A' on the command line
|
||||
cs.main('-C', '2', '-A', '1', d)
|
||||
lines = capsys.readouterr()[0].split('\n')
|
||||
assert 'ERROR' in lines[0]
|
||||
|
||||
# both '-C' and '-B' on the command line
|
||||
cs.main('-C', '2', '-B', '1', d)
|
||||
lines = capsys.readouterr()[0].split('\n')
|
||||
assert 'ERROR' in lines[0]
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def FakeStdin(text):
|
||||
if sys.version[0] == '2':
|
||||
|
Reference in New Issue
Block a user