-
Notifications
You must be signed in to change notification settings - Fork 472
/
code_snippet.py
118 lines (93 loc) · 3.22 KB
/
code_snippet.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import codecs
import itertools
from .color import AnsiColor
from .color import colorize
class CodeSnippetHighlighter:
def get_code_snippet(self, filename, line_number, lines_of_context=5):
"""
:type filename: str
:type line_number: int
:param line_number: line which you want to focus on
:type lines_of_context: int
:param lines_of_context: how many lines to display around the line you want
to focus on.
:rtype: CodeSnippet
"""
secret_line_index = line_number - 1
end_line = secret_line_index + lines_of_context + 1
if secret_line_index <= lines_of_context:
start_line = 0
index_of_secret_in_output = secret_line_index
else:
start_line = secret_line_index - lines_of_context
index_of_secret_in_output = lines_of_context
return CodeSnippet(
list(
itertools.islice(
self._get_lines_in_file(filename),
start_line,
end_line,
),
),
start_line,
index_of_secret_in_output,
)
def _get_lines_in_file(self, filename):
"""
:rtype: list
"""
with codecs.open(filename, encoding='utf-8') as file:
return file.read().splitlines()
class CodeSnippet:
def __init__(self, snippet, start_line, target_index):
"""
:type snippet: list
:param snippet: lines of code extracted from file
:type start_line: int
:param start_line: first line number in segment
:type target_index: int
:param target_index: index in snippet of target line
"""
self.lines = snippet
self.start_line = start_line
self.target_index = target_index
@property
def target_line(self):
return self.lines[self.target_index]
@target_line.setter
def target_line(self, value):
self.lines[self.target_index] = value
def add_line_numbers(self):
for index, line in enumerate(self.lines):
self.lines[index] = u'{}:{}'.format(
self.get_line_number(self.start_line + index + 1),
line,
)
return self
def highlight_line(self, payload):
"""
:type payload: str
:param payload: string to highlight, on chosen line
"""
index_of_payload = self.target_line.lower().index(payload.lower())
end_of_payload = index_of_payload + len(payload)
self.target_line = u'{}{}{}'.format(
self.target_line[:index_of_payload],
self.apply_highlight(self.target_line[index_of_payload:end_of_payload]),
self.target_line[end_of_payload:],
)
return self
def get_line_number(self, line_number):
"""Broken out, for custom colorization."""
return colorize(
str(line_number),
AnsiColor.LIGHT_GREEN,
)
def apply_highlight(self, payload):
"""Broken out, for custom colorization."""
return colorize(
payload,
AnsiColor.RED_BACKGROUND,
)
def __str__(self):
return '\n'.join(self.lines)