1
2
3
4
5
6 import os
7 import re
8
9 from libxyz.core import ODict
10 from libxyz.core.utils import ustring, bstring, intersect, split_cmd
11 from libxyz.core.plugins import BasePlugin
12
13 from libxyz.ui import lowui
14 from libxyz.ui import ListEntry
15 from libxyz.ui import Keys
16 from libxyz.ui import XYZListBox
17
19 "Auto-completion plugin"
20
21 NAME = u"complete"
22 AUTHOR = u"Max E. Kuznecov <syhpoon@syhpoon.name>"
23 VERSION = u"0.1"
24 BRIEF_DESCRIPTION = u"Auto-completion system"
25 FULL_DESCRIPTION = u"Plugin-based completion system"
26 NAMESPACE = u"core"
27 MIN_XYZ_VERSION = None
28 DOC = u"Configuration variables:\n"\
29 u"domains - List of domains to use.\n"\
30 u"Default: ['binpath', 'fs']"
31 HOMEPAGE = u"http://xyzcmd.syhpoon.name/"
32 EVENTS = None
33
43
44
45
47
48 try:
49
50 for domain in self.conf["domains"]:
51 self._domains[domain] = self._init_domain(domain)
52
53 behaviour = []
54
55 for (pattern, domain) in self.conf["behaviour"]:
56 behaviour.append((re.compile(pattern), domain))
57
58 self.conf["behaviour"] = behaviour
59 except Exception, e:
60 xyzlog.warning(_(u"Error ininitalizing plugin: %s") %
61 (ustring(str(e))))
62
63
64
66 for domain in self._domains:
67 try:
68 domain.finalize()
69 except Exception:
70 pass
71
72
73
75 """
76 Take current buffer and return list of list-generator each entry for
77 each domain.
78
79 @param buf: Current buffer
80 @param domains: List of domains to search in,
81 if None search in all available domains.
82 @return: List of list-generator each entry for each domain
83 """
84
85 buf = bstring(buf)
86
87 result = []
88
89 if domains is None:
90 domains = self._domains.keys()
91
92 for d in domains:
93 result.append(self._domains[d].complete(buf))
94
95 return result
96
97
98
100 """
101 Try to guess what completion domain can be used based on
102 provided buffer and defined behaviour.
103
104 @param cmd: Current buffer
105 @return: List of list-generator each entry for each domain
106 """
107
108 if not cmd:
109 return
110
111 data = None
112 pat_used = False
113 buf = bstring(split_cmd(cmd)[-1])
114
115
116 for (pattern, domain) in self.conf["behaviour"]:
117 if pattern.search(cmd) is not None:
118 pat_used = True
119 data = self.dialog(cmd, [domain])
120 break
121
122
123 if pat_used == False:
124
125 if buf.startswith(os.path.sep) or buf.startswith("./") or \
126 buf.startswith("../"):
127 data = self.dialog(buf, ["fs"])
128 else:
129
130 data = self.dialog(buf, ["binpath"])
131
132 if data is not None:
133 data = intersect(buf, data)
134 self.xyz.pm.from_load(":sys:cmd", "append")(data)
135
136
137
138 - def dialog(self, buf, domains=None):
139 """
140 Show a window containing matched entries
141 and return user selected one
142 """
143
144 match = self.complete(buf, domains)
145
146 _chdir = self.xyz.pm.from_load(u":sys:panel", u"chdir")
147
148 _sel_attr = self.xyz.skin.attr(CompleteWindow.resolution, u"selected")
149 _wdata = []
150
151 for gen in match:
152 for entry in sorted(gen):
153 _wdata.append(ListEntry(entry, _sel_attr))
154
155 if len(_wdata) == 1:
156 return _wdata[0].text
157
158 _walker = lowui.PollingListWalker(_wdata)
159 _dim = tuple([x - 2 for x in self.xyz.screen.get_cols_rows()])
160
161 return CompleteWindow(self.xyz, self.xyz.top, _walker, _(u"Complete"),
162 _dim, extra=_wdata, buf=buf).show()
163
164
165
166 - def _init_domain(self, dom):
167 """
168 Try to load and initialize domain class
169
170 @param dom: Domain name string. Class name is constructed by
171 prepending domain_ prefix
172 """
173
174 domain_class = __import__("domain_%s" % dom, globals(), locals(), [])
175 domain_obj = domain_class.Domain()
176
177 domain_obj.prepare()
178
179 return domain_obj
180
181
182
185 if "extra" in kwargs:
186 self._extra = kwargs["extra"]
187 del(kwargs["extra"])
188 else:
189 self._extra = None
190
191 if "buf" in kwargs:
192 self._buf = kwargs["buf"]
193 del(kwargs["buf"])
194 else:
195 self._buf = u""
196
197 super(CompleteWindow, self).__init__(*args, **kwargs)
198
199
200
201 - def show(self, dim=None, exit_keys=None):
202 """
203 Show window. Update contents as user types
204 """
205
206 exit_keys = exit_keys or []
207
208 if dim is None:
209 dim = self.xyz.screen.get_cols_rows()
210
211 _buf = u""
212 _title = self.title
213
214 while True:
215 self.xyz.screen.draw_screen(dim, self.render(dim, True))
216
217 _i = self.xyz.input.get()
218
219 if self.xyz.input.WIN_RESIZE in _i:
220 dim = self.xyz.screen.get_cols_rows()
221 continue
222
223 update = False
224
225 if _i:
226 for _k in _i:
227 if _k == self._keys.ESC:
228 return
229 elif _k == self._keys.BACKSPACE:
230 _buf = _buf[:-1]
231 update = True
232 elif _k == self._keys.ENTER:
233 entry, _ = self.listbox.get_focus()
234 return entry.text
235 elif len(ustring(_k)) == 1:
236 _buf += _k
237 update = True
238 else:
239 self._listbox.keypress(dim, _k)
240
241 if update:
242 _b = bstring(_buf)
243 self.set_title(u"%s: %s" % (_title, _buf))
244
245 self.listbox.body.contents = [x for x in self._extra
246 if _b in x._text]
247