-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnumber_formatter.py
More file actions
136 lines (98 loc) · 4.18 KB
/
Copy pathnumber_formatter.py
File metadata and controls
136 lines (98 loc) · 4.18 KB
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
import re
import sublime
import sublime_plugin
class FormatNumberCommand(sublime_plugin.TextCommand):
def expand_region_to_whitespace(self, region):
# Consider only the lines containing the region
line_region = self.view.line(region)
if not line_region:
return None
line_string = self.view.substr(line_region)
# Looks for a whitespace boundary at the beginning of the region or between
# the beginning of the region and the beginning of the line it starts on
region_begin = region.begin() - line_region.begin()
space_boundary_begin = self.get_space_boundary_begin(line_string,
region_begin)
# Looks for whitespace between end of the region
# and the end of the line it ends on
region_end = region.end() - line_region.begin()
space_boundary_end = self.get_space_boundary_end(line_string, region_end)
# Returns region expanded to whitespace boundaries
expanded_region_begin = line_region.begin() + space_boundary_begin
expanded_region_end = line_region.begin() + space_boundary_end
return sublime.Region(expanded_region_begin, expanded_region_end)
def get_space_boundary_begin(self, str, pos):
"""
Returns position of the closest whitespace boundary between `pos`
and the beginning of the string
"""
match = re.search(r"\S+$", str[:pos], re.UNICODE)
if match:
return pos - (match.end() - match.start())
# Sets `pos` as the boundary when `str` is not preceded by a whitespace
return pos
def get_space_boundary_end(self, str, pos):
"""
Returns position of the closest whitespace boundary between `pos`
and the end of the string
"""
match = re.search(r"\s", str[pos:], re.UNICODE)
if match:
return pos + match.start()
return len(str)
def is_number(self, str):
"""
Strips off all locale characters from string and tests whether it's a number
"""
result = False
str = (str
.replace(self.decimal_separator, ".")
.replace(self.thousands_separator, ""))
try:
val = float(str)
result = True
except:
pass
return result
def run(self, edit):
settings = sublime.load_settings("NumberFormatter.sublime-settings")
self.decimal_separator = settings.get("decimal_separator", ".")
self.format_thousands = settings.get("format_thousands", True)
self.thousands_separator = settings.get("thousands_separator", ",")
expanded_regions = []
selected_regions = self.view.sel()
# Expands selected regions to the nearest whitespace
for region in selected_regions:
expanded_region = self.expand_region_to_whitespace(region)
if expanded_region is None:
continue
if self.is_number(self.view.substr(expanded_region)):
expanded_regions.append(expanded_region)
# Formats the numbers in the selected regions
for region in reversed(expanded_regions):
substr = self.view.substr(region)
if self.thousands_separator in substr:
# Removes formatting from the number
new_string = substr.replace(self.thousands_separator, "")
else:
decimal_number = None
# Adds formatting to the number
if bool(re.search(re.escape(self.decimal_separator), substr)):
# Splits the number into whole and decimal number strings
whole_number, decimal_number = substr.split(self.decimal_separator)
else:
whole_number = substr
# Skips formatting four-digit numbers when set
if (not self.format_thousands) and (1000 <= int(whole_number) <= 9999):
continue
new_string = ""
# Decorates whole number strings by adding a comma to every third
# character starting from the end:
for idx, character in enumerate(reversed(whole_number)):
if idx % 3 == 0 and idx > 0:
character = character + self.thousands_separator
new_string = character + new_string
# Recombines the whole and decimal number strings into a single number
if decimal_number is not None:
new_string += self.decimal_separator + decimal_number
self.view.replace(edit, region, new_string)