-
Notifications
You must be signed in to change notification settings - Fork 1
/
cns_complete.py
188 lines (144 loc) · 5.14 KB
/
cns_complete.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
184
185
186
187
188
import os
import re
import inspect
from cudatext import *
#from cudax_lib import get_translation
#_ = get_translation(__file__) # I18N
fn_config = os.path.join(app_path(APP_DIR_SETTINGS), 'plugins.ini')
SECTION = 'console_complete'
VK_SPACE = 0x20
prefix = 'id'
replace_right_part = True
add_func_params = True
def bool_to_str(v): return '1' if v else '0'
def str_to_bool(s): return s=='1'
class Command:
def __init__(self):
self.load_cfg()
hcons = app_proc(PROC_GET_CONSOLE_FORM, '')
h_in = dlg_proc(hcons, DLG_CTL_HANDLE, name='input')
self.ed_in = Editor(h_in)
dlg_proc(hcons, DLG_PROP_SET, prop={
'keypreview': True, # Should be True if form needs to handle on_key_down.
'on_key_down': self.on_cns_key,
})
def load_cfg(self):
global prefix
global replace_right_part
global add_func_params
prefix = ini_read(fn_config, SECTION, 'prefix', prefix)
replace_right_part = str_to_bool(
ini_read(fn_config, SECTION, 'replace_right_part', bool_to_str(replace_right_part)))
add_func_params = str_to_bool(
ini_read(fn_config, SECTION, 'add_func_params', bool_to_str(add_func_params)))
def config(self):
global prefix
global replace_right_part
global add_func_params
ini_write(fn_config, SECTION, 'prefix', value=prefix)
ini_write(fn_config, SECTION, 'replace_right_part', value=bool_to_str(replace_right_part))
ini_write(fn_config, SECTION, 'add_func_params', value=bool_to_str(add_func_params))
file_open(fn_config)
# just to load the plugin on first Console input
def on_console_nav(self, ed_self, text):
pass
def on_save(self, ed_self):
if ed_self.get_filename() == fn_config:
self.load_cfg()
def on_cns_key(self, id_dlg, key_code, data='', info=''):
state = data
if key_code == VK_SPACE and state == 'c':
self.complete()
def complete(self, *args, **vargs):
if self.ed_in.get_prop(PROP_FOCUSED):
edt = self.ed_in
elif ed.get_prop(PROP_FOCUSED) and ed.get_prop(PROP_LEXER_CARET) == 'Python':
edt = ed
else:
return
# get Console variables
if Parcel._globals == None:
app_proc(PROC_EXEC_PYTHON, 'from cudatext import *; from cuda_console_complete.cns_complete import Parcel; '+
'Parcel._globals = globals(); del Parcel;')
caretx, carety, _x2, _y2 = edt.get_carets()[0]
comp = None
replace_r = 0
text_start = edt.get_text_line(carety)
textr = text_start[:caretx][::-1] # text before caret reversed (for regex)
m = re.search('^([a-zA-Z0-9_.]+)([\'"])?', textr)
if m:
grs = m.groups()
if grs[1] != None: # have a "
text = ''
else:
text = grs[0][::-1]
right_text = text_start[caretx:]
m = re.search('^([a-zA-Z0-9_.]+)([\'"])?', right_text)
if m:
grs = m.groups()
if grs[1] != None: # have a "
text = ''
elif replace_right_part:
replace_r = len(grs[0])
else: # no match
text = ''
# method, field
if '.' in text:
spl = text.split('.')
replace_l = len(spl[-1])
# search for target object
var = None
for fname in spl[:-1]:
if var is None:
var = Parcel._globals.get(fname)
else:
var = getattr(var, fname, None)
if var is None:
break
if var != None:
comp = self._get_comp(obj=var, pre=spl[-1])
# var
elif text:
replace_l = len(text)
comp = self._get_comp(obj=None, pre=text)
if comp:
comp.sort()
edt.complete('\n'.join(comp), replace_l, replace_r)
def _get_comp(self, obj, pre):
dir_res = dir(obj) if obj != None else Parcel._globals
comp = []
for name in dir_res:
if not name.startswith(pre) or name.startswith('__'):
continue
if obj != None:
f = getattr(obj, name)
else:
f = Parcel._globals.get(name)
if not add_func_params or not callable(f):
comp.append(prefix +'|'+ name)
else:
try:
# ArgSpec( args=['id_menu', 'id_action', 'command', 'caption', 'index', 'hotkey', 'tag'],
# varargs=None, keywords=None,
# defaults=('', '', -1, '', ''))
spec = inspect.getfullargspec(f)
except TypeError:
spec = None
if spec:
sargs = []
arglen = len(spec.args) if spec.args else 0
deflen = len(spec.defaults) if spec.defaults else 0
noargs = arglen-deflen
for i in range(arglen):
if i == 0 and spec.args[i] == 'self':
continue
if i < noargs:
sargs.append(spec.args[i])
else:
sargs.append(spec.args[i] +'='+ spec.defaults[i-noargs].__repr__())
comp.append('{0}|{1}|({2})'.format(prefix, name, ", ".join(sargs)))
else:
comp.append(prefix +'|'+ name)
return comp
class Parcel:
_globals = None