-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpostfix.py
158 lines (130 loc) · 4.1 KB
/
postfix.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
import os
import re
import yaml
import sublime
import sublime_plugin
from .dbg import Dbg
DEFAULT_POSTFIXES_PATH = "Packages/Postfixer/postfixes.yml"
FIX_RE = re.compile(r"^(\s*)(.+)\.(.+)$")
VAR_CURSOR = "$cursor"
VAR_INDENT = "$-->"
VAR_WHOLE = "$0"
def plugin_loaded():
# Get settings
settings = sublime.load_settings("Postfixer.sublime-settings")
# Setup debug utils
global d
d = Dbg(settings)
# Load postfixes
win = sublime.active_window()
win.run_command("reload_postfixes")
class PostfixCommand(sublime_plugin.TextCommand):
def run(self, edit):
# get postfixes for current scope
scope = self.view.scope_name(0).split(' ')[0]
if scope in postfixes:
scopefixes = postfixes[scope]
else:
d.lg("Cannot find postfixes for scope: " + scope)
return
# Get indent type (from syntax / global settings)
syn = self.view.settings().get("syntax")
syn = os.path.basename(syn)
syn = os.path.splitext(syn)[0]
syn_settings = sublime.load_settings(syn + ".sublime-settings")
sp_indent = syn_settings.get("translate_tabs_to_spaces")
if sp_indent is None:
sp_indent = self.view.settings().get("translate_tabs_to_spaces")
# Get intent size
if sp_indent:
tab_size = syn_settings.get("tab_size")
if tab_size is None:
tab_size = self.view.settings().get("tab_size")
# Set indent
if sp_indent:
self.indent_str = " " * tab_size
else:
self.indent_str = "\t"
# Fix all possible occurrences
cursors = []
for r in self.view.sel():
if not r.empty():
continue
line_r = sublime.Region(self.view.line(r).begin(), r.b)
try:
out, cursor = self.fix(scopefixes, self.view.substr(line_r))
except ValueError:
continue
self.view.replace(edit, line_r, out)
cursor = line_r.begin() + cursor
cursors.append(sublime.Region(cursor, cursor))
# Update cursor(s) position
if len(cursors) > 0:
self.view.sel().clear()
self.view.sel().add_all(cursors)
def fix(self, fixes, line):
# Parse line
parsed_line = FIX_RE.match(line)
if parsed_line is None:
raise ValueError("no_fit")
indent, target, cmd = parsed_line.groups()
# Find fix
fix = None
for f in fixes:
if cmd == f['cmd']:
fix = f
break
if fix is None:
raise ValueError("no_fix")
# Render fix
target_match = re.match(fix['target'], target)
if target_match is None:
raise ValueError("no_fix")
parsed = fix['fix'].replace(VAR_WHOLE, target_match.group(0))
parsed = parsed.replace(VAR_INDENT, self.indent_str)
if len(target_match.groups()) > 0:
for i, tm in enumerate(target_match.groups()):
parsed = parsed.replace("$" + str(i + 1), tm)
# Indent
output = []
nl = "\n"
if self.view.line_endings() == "Windows":
nl = "\r\n"
for rl in parsed.splitlines():
output.append(indent + rl)
output = nl.join(output)
# Get cursor index
cursor_index = output.find(VAR_CURSOR)
if cursor_index == -1:
cursor_index = len(output)
output = output.replace(VAR_CURSOR, "")
return (output, cursor_index)
class ReloadPostfixesCommand(sublime_plugin.WindowCommand):
def run(self):
# Get default postfixes file
postfixes_str = ""
try:
postfixes_str = sublime.load_resource(DEFAULT_POSTFIXES_PATH)
except:
d.lg("Cannot load default postfixes file: " + DEFAULT_POSTFIXES_PATH)
# Get user's postfixes file or create new from default
fixes_path = os.path.join(sublime.packages_path(), "User/postfixes.yml")
if os.path.isfile(fixes_path):
with open(fixes_path) as f:
postfixes_str = f.read()
else:
with open(fixes_path, "w") as f:
f.write(postfixes_str)
# Parse snippets
try:
fixes = yaml.load(postfixes_str)
except:
d.lg("Cannot parse postfixes yaml")
fixes = {}
# Prepare snippets to use
global postfixes
postfixes = {}
for scopes, rules in fixes.items():
for scope in scopes.split(' '):
postfixes[scope] = rules
d.lg("Snippets (re)loaded")