forked from thatsIch/sublime-rainmeter
-
Notifications
You must be signed in to change notification settings - Fork 0
/
indentrainmeter.py
130 lines (92 loc) · 4.03 KB
/
indentrainmeter.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
"""
This module handles the indention of the rainmeter files.
Default indention is required to allow collapsing of code blocks.
"""
import re
import sublime
import sublime_plugin
FOLD_MARKER_EXP = re.compile("^([ \\t]*)(;;.*)$")
SECTION_EXP = re.compile("^([ \\t]*)(\\[.*)$")
EMPTY_LINE_EXP = re.compile("^\\s*$")
COMMENT_EXP = re.compile("^\\s*(;.*)")
class IndentType(object): # pylint: disable=R0903; enum
"""Enum to store the several types of area blocks you can have in a rainmeter skin."""
# lvl 0, lvl 1, lvl 1 or 2
Initial, FoldMarker, Section = range(1, 4)
def calc_section_indention_depth(context, context_depth):
"""."""
if context == IndentType.Section:
return context_depth - 1, IndentType.Section, context_depth
else:
return context_depth, IndentType.Section, context_depth + 1
def calc_line_indention_depth(line, context, context_depth):
"""."""
empty_line_match = EMPTY_LINE_EXP.match(line)
if empty_line_match:
return 0, context, context_depth
folder_marker_match = FOLD_MARKER_EXP.match(line)
if folder_marker_match:
return 0, IndentType.FoldMarker, 1
comment_match = COMMENT_EXP.match(line)
if comment_match:
return context_depth, context, context_depth
section_match = SECTION_EXP.match(line)
if section_match:
return calc_section_indention_depth(context, context_depth)
# key value case
return context_depth, context, context_depth
def get_line_replacement(line, context_depth):
"""Replace the current line with the given indention level."""
stripped = line.lstrip()
replacement = "\t" * context_depth + stripped
return replacement
def indent_text_by_tab_size(text):
"""Main entry point for indenting text."""
lines = text.split("\n")
context = IndentType.Initial
context_depth = 0
result = []
for line in lines:
depth, context, context_depth = calc_line_indention_depth(line, context, context_depth)
replacement = get_line_replacement(line, depth)
result.append(replacement)
return "\n".join(result)
class RainmeterIndentCommand(sublime_plugin.TextCommand):
"""
Indent a Rainmeter file so code folding is possible in a sensible way.
Double semicolons at the start of a line indent everything until the next
double semicolon so you can create custom fold markers. If nothing is
selected, the whole file will be indented. If one or more regions are
selected, only these lines will be indented without paying attention to
the surroundings
"""
def __get_selected_region(self):
# If nothing is selected, apply to whole buffer
if self.view.sel()[0].a == self.view.sel()[-1].b:
regions = [sublime.Region(0, self.view.size())]
# If something is selected, apply only to selected regions
else:
regions = self.view.sel()
return regions
def run(self, edit): # pylint: disable=R0201; sublime text API, no need for class reference
"""Called when the command is run."""
regions = self.__get_selected_region()
for region in regions:
text = self.view.substr(region)
indented_text = indent_text_by_tab_size(text)
self.view.replace(edit, region, indented_text)
def is_enabled(self): # pylint: disable=R0201; sublime text API, no need for class reference
"""
Return True if the command is able to be run at this time.
The default implementation simply always returns True.
"""
# Check if current syntax is rainmeter
israinmeter = self.view.score_selector(self.view.sel()[0].a, "source.rainmeter")
return israinmeter > 0
def description(self): # pylint: disable=R0201; sublime text API, no need for class reference
"""
Return a description of the command with the given arguments.
Used in the menus, and for Undo/Redo descriptions.
Return None to get the default description.
"""
return "Indent Ini for Code Folding"