-
Notifications
You must be signed in to change notification settings - Fork 26
/
table_cleaner.py
183 lines (142 loc) · 6.4 KB
/
table_cleaner.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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# Author: Andrei Misarca
import copy
import os.path
import sys
this_dir = os.path.dirname(os.path.realpath(__file__))
if this_dir not in sys.path:
sys.path += [this_dir]
import table_commons
class TableCleanerCommand(table_commons.TextCommand):
# Default separator, all the recognised separators being replaced with this
# one, before aligning the tables, acting as an intermediate.
SEPARATOR = "&"
def run(self, edit):
self.edit = edit
self.get_settings()
orig_lines = self.filter_lines(self.selected_lines())
lines, separator = self.replace_separator(orig_lines), self.SEPARATOR
# If no separator has been found, then do not perform any changes
if lines:
lines, front_whites = self.front_whitespaces(lines)
self.align(lines, orig_lines, front_whites)
# Select only the lines that contain at least one separator.
def filter_lines(self, lines):
new_lines = []
for line in lines:
sep_found = False
# If at least one separator can be found on the current line, add
# it to the list of lines that will be arranged.
for sep in self.separators:
if sep in line[1]:
sep_found = True
if sep_found:
new_lines.append(line)
return new_lines
# Replace all separators with the default one.
def replace_separator(self, lines):
new_lines = []
for line in lines:
new_line = copy.deepcopy(line)
# Replace the separators with the default one.
for sep in self.separators:
new_line[1] = new_line[1].replace(sep, self.SEPARATOR)
new_lines.append(new_line)
return new_lines
# Retrieve all the settings from the settings file and store them in
# instance variables
def get_settings(self):
self.separators = (self.view.settings()
.get('table_cleaner_delimiters', ['|', '&']))
self.align_to_middle = (self.view.settings()
.get('table_cleaner_align_to_middle',
False))
self.delimiter_spaces = (self.view.settings()
.get('table_cleaner_delimiter_spaces', 1))
# Split the lines by a separator
def split_lines(self, lines, separator):
for line in lines:
# if there is no escaped separator, just use normal version
if "\\" + separator not in line[1]:
line[1] = line[1].split(separator)
# if there is escaped separator in table (eg: \&)
else:
temp_line = []
last_i = 0
for i in xrange(len(line[1])):
if line[1][i] == separator and line[1][i-1] != "\\":
temp_line.append(line[1][last_i:i])
last_i = i+1
temp_line.append(line[1][last_i:])
line[1] = temp_line
return lines
# Replace the old lines with the new ones, containing the cleaned table
def render_lines(self, lines, front_whites):
for line in lines:
new_line = front_whites + line[1] + "\n"
self.replace_line(self.edit, line[0], new_line)
# Create a generator that yields the separators from a line
def orig_separators(self, line):
for i in xrange(len(line)):
for sep in self.separators:
if line[i:].startswith(sep):
yield sep
# Restore the separators of a line, given the original line. The separators
# are going to be restored in the order they appeared in the original
# string.
def restore_line(self, line, orig_line):
it = self.orig_separators(orig_line)
new_line = list(line)
for i in xrange(len(new_line)):
if new_line[i] == self.SEPARATOR:
new_line = new_line[:i] + [it.next()] + new_line[i+1:]
return "".join(new_line)
def restore_lines(self, lines, orig_lines):
# print(orig_lines)
for i in xrange(len(lines)):
lines[i][1] = self.restore_line(self.SEPARATOR.join(lines[i][1]),
orig_lines[i][1])
return lines
# Perform the alignment
def align(self, lines, orig_lines, front_whites):
lines = self.split_lines(lines, self.SEPARATOR)
# Find the sizes of the table
rows_size = len(lines)
cols_size = min([len(line[1]) for line in lines])
for col in xrange(0, cols_size):
max_len = 0
# Find the largest cell on the current column
for row in xrange(0, rows_size):
max_len = max(max_len, len(lines[row][1][col].strip()))
for row in xrange(0, rows_size):
cell = lines[row][1][col].strip()
diff = max_len - len(cell)
if self.align_to_middle:
# Determine the number of characters that need to be
# inserted to left and to right
l_diff = diff / 2
r_diff = diff - l_diff
# If the current column is the first column, do not insert
# the delimiters white spaces to the left
if col == 0:
cell = ((l_diff * " ") + cell + (" " * r_diff) +
(self.delimiter_spaces * " "))
# If the column only contains a whitespace,
# then remove it
if cell == " ":
cell = ""
else:
cell = ((self.delimiter_spaces * " ") +
(l_diff * " ") + cell + (" " * r_diff) +
(self.delimiter_spaces * " "))
else:
if col == 0:
cell = (cell + (" " * diff) +
self.delimiter_spaces * " ")
if cell == " ":
cell = ""
else:
cell = (" " + cell + (" " * diff) +
self.delimiter_spaces * " ")
lines[row][1][col] = cell
lines = self.restore_lines(lines, orig_lines)
self.render_lines(lines, front_whites)