1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 from __future__ import with_statement
18
19 import sys
20 import os
21 import traceback
22 import __builtin__
23
24 from libxyz.core.utils import ustring
25 from libxyz.core.utils import is_func
26 from libxyz.core.plugins import Namespace
27 from libxyz.ui import Shortcut
28
29 import libxyz.exceptions as ex
32 """
33 Ensure the class has been instantiated
34 """
35
36 def wrap(cls, *args, **kwargs):
37 if cls._instance is None:
38 error(_(u"Class must be instantiated first!"))
39 else:
40 return func(cls, *args, **kwargs)
41
42 wrap.__doc__ = func.__doc__
43
44 return wrap
45
46
47
48 -def error(msg, trace=True):
49 if trace and hasattr(__builtin__, "xyzlog"):
50 xyzlog.debug(ustring(traceback.format_exc()))
51 raise ex.DSLError(_(u"DSL Error: %s") % msg)
52
53
54
55 -class XYZ(object):
56 """
57 XYZ DSL implementation object
58 """
59
60 api = ["let",
61 "val",
62 "unlet",
63 "load",
64 "bind",
65 "exec_file",
66 "kbd",
67 "action",
68 "macro",
69 "call",
70 "env",
71 "shell",
72 "alias",
73 "plugins_on",
74 "plugins_off",
75 "plugin_conf",
76 "icmd",
77 "prefix",
78 "help",
79 ]
80
81 macros = {}
82
83 _instance = None
84 _env = {}
85
106
107
108
109 @classmethod
110 @instantiated
111 - def let(cls, var, val, sect=u"local"):
112 """
113 Set variable.
114 Variable will be available in xyz.conf[section][varname]
115 If section is not provided - local will be used
116 """
117
118 _conf = cls.xyz.conf
119
120 if sect not in _conf:
121 _conf[sect] = {}
122
123 if var in _conf[sect] and isinstance(_conf[sect][var], dict) and \
124 isinstance(val, dict):
125
126 _conf[sect][var].update(val)
127 else:
128 cls.xyz.conf[sect][var] = val
129
130
131
132 @classmethod
133 @instantiated
134 - def val(cls, var, sect=u"local"):
135 """
136 Return variable value or None if undefined
137 """
138
139 try:
140 return cls.xyz.conf[sect][var]
141 except Exception:
142 return None
143
144
145
146 @classmethod
147 @instantiated
148 - def unlet(cls, var, sect=u"local"):
149 """
150 Unset variable
151 """
152
153 if var in cls.xyz.conf[sect]:
154 del(cls.xyz.conf[sect])
155
156
157
158 @classmethod
159 @instantiated
160 - def load(cls, plugin):
161 """
162 Load method[s] from plugin
163 """
164
165 try:
166 cls.xyz.km.load(plugin)
167 except Exception, e:
168 error(_(u"Unable to load plugin %s: %s") %
169 (plugin, ustring(str(e))))
170
171
172
173 @classmethod
174 @instantiated
175 - def bind(cls, method, shortcut, context="DEFAULT"):
176 """
177 Bind method to shortcut
178 """
179
180 try:
181 cls.xyz.km.bind(method, shortcut, context=context)
182 except Exception, e:
183 error(_(u"Unable to bind shortcut: %s") % (ustring(str(e))))
184
185
186
187 @classmethod
188 @instantiated
189 - def kbd(cls, *args):
190 """
191 Create keyboard shortcut
192 """
193
194 return Shortcut(sc=list(args))
195
196
197
198 @classmethod
199 @instantiated
201 """
202 Execute DSL in file
203 """
204
205 with open(filename) as fh:
206 cls.execute(fh.read())
207
208
209
210 @classmethod
211 @instantiated
213 """
214 Set up an action to be taken upon pressing action key on file
215 """
216
217 try:
218 cls.xyz.am.register(rule, fn)
219 except Exception, e:
220 error(_(u"Unable to register action: %s") % ustring(str(e)))
221
222
223
224 @classmethod
225 @instantiated
226 - def macro(cls, macroname):
227 """
228 Expand macro name.
229
230 Availbale macros:
231 * ACT_CWD -- Working directory in active panel
232 * INACT_CWD -- Working directory in inactive panel
233 * ACT_PATH -- Full selected object path in active panel
234 * INACT_PATH -- Full selected object path in inactive panel
235 * ACT_BASE -- Parent directory in active panel
236 * INACT_BASE -- Parent directory in inactive panel
237 * ACT_TAGGED -- List of tagged files in active panel
238 * INACT_TAGGED -- List of tagged files in inactive panel
239 * ACT_UNTAGGED -- List of not tagged files in active panel
240 * INACT_UNTAGGED -- List of not tagged files in inactive panel
241 """
242
243 if macroname in cls.macros:
244 try:
245 return cls.macros[macroname]()
246 except Exception, e:
247 xyzlog.warning(_(u"Unable to expand macro %s: %s") %
248 (ustring(macroname), ustring(str(e))))
249
250 return macroname
251
252
253
254 @classmethod
255 @instantiated
256 - def call(cls, method, *args):
257 """
258 Call plugin method
259 """
260
261 try:
262 p = Namespace(method)
263 m = cls.xyz.pm.from_load(p.pfull, p.method)
264 return m(*args)
265 except Exception, e:
266 error(_(u"Unable to execute method %s: %s" %
267 (method, ustring(str(e)))))
268
269
270
271 @classmethod
272 @instantiated
273 - def env(cls, var, default=None):
274 """
275 Return environment variable or default if is not set
276 """
277
278 return os.getenv(var, default)
279
280
281
282 @classmethod
283 @instantiated
284 - def shell(cls, cmd, *args, **kwargs):
285 """
286 Execute command via :core:shell plugin
287 Optional boolean argument 'current' can be provided to indicate
288 that cmd is to be run from current directory.
289 Optional boolean argument 'bg' can be provided to indicate that cmd
290 must be executed in background
291 Optional boolean argument 'reload' can be provided to indicate
292 that panel content should/should not be reloaded after execution
293
294 """
295
296 if kwargs.get("current", False):
297 cmd = "./%s" % cmd
298
299 bg = ["&"] if kwargs.get("bg", False) else []
300 reloadp = kwargs.get("reload", True)
301
302 try:
303 exef = cls.xyz.pm.from_load(":core:shell", "execute")
304 escapef = cls.xyz.pm.from_load(":sys:cmd", "escape")
305 reloadf = cls.xyz.pm.from_load(":sys:panel", "reload_all")
306 exef(" ".join([escapef(cmd, True)] +
307 [escapef(a, True) for a in args] + bg))
308 if reloadp:
309 reloadf()
310 except Exception, e:
311 error(_(u"Error in DSL shell execution: %s") % ustring(str(e)))
312
313
314
315 @classmethod
316 @instantiated
317 - def alias(cls, alias, replace):
318 """
319 Set an alias which will be expanded in command line before execution
320 @param replace: Either string or function
321 """
322
323 return cls.let(alias, replace, sect="aliases")
324
325
326
327 @classmethod
328 @instantiated
329 - def icmd(cls, command, obj):
330 """
331 Set an internal command.
332 """
333
334 if not is_func(obj):
335 error(_(u"Invalid object type: %s. Function expected") %
336 type(obj), trace=False)
337
338 return cls.let(command, obj, sect="commands")
339
340
341
342 @classmethod
343 @instantiated
345 """
346 Enable plugin[s]
347 """
348
349 for plugin in plugins:
350 cls.let("plugins", {plugin: "ENABLE"}, sect="xyz")
351
352
353
354 @classmethod
355 @instantiated
357 """
358 Disable plugin[s]
359 """
360
361 for plugin in plugins:
362 cls.let("plugins", {plugin: "DISABLE"}, sect="xyz")
363
364
365
366 @classmethod
367 @instantiated
369 """
370 Configure plugin.
371
372 @param plugin: Plugin name
373 @param opts: Either tuple (var, val) or
374 dict {var1: val1, var2: var2,..}
375 """
376
377 if isinstance(opts, tuple):
378 opts = dict([opts])
379
380 if not isinstance(opts, dict):
381 cls.error(_(u"Invalid opts type: %s. Dict instance expected")
382 % type(opts))
383
384 return cls.let(plugin, opts, sect="plugins")
385
386
387
388 @classmethod
389 @instantiated
396
397
398
399 @classmethod
400 @instantiated
401 - def help(cls, obj=None):
402 """
403 Help
404 """
405
406 fmt = lambda o: "%s\t%s" % (o, getattr(cls, o).__doc__)
407
408 if obj is not None and obj not in cls.api:
409 error(_(u"Invalid function %s") % obj)
410
411 objs = [obj] if obj else cls.api
412
413 return "\n".join([fmt(x) for x in objs]).replace("\t", " ")
414
415
416
417 @classmethod
418 @instantiated
420 """
421 Execute DSL statements
422 @param source: Either string or open file-object or code object
423 """
424
425 try:
426 exec source in cls._env.copy()
427 except Exception, e:
428 error(_(u"Error in DSL execution: %s") % ustring(str(e)))
429
430
431
432 @classmethod
433 @instantiated
435 """
436 Return copy of global dsl environment
437 """
438
439 return cls._env.copy()
440
441
442
443
444 module = sys.modules[__name__]
445
446 __all__ = ["XYZ"]
447
448 for f in XYZ.api:
449 setattr(module, f, getattr(XYZ, f))
450 __all__.append(f)
451