Package libxyz :: Package ui :: Module cmd
[hide private]
[frames] | no frames]

Source Code for Module libxyz.ui.cmd

  1  #-*- coding: utf8 -* 
  2  # 
  3  # Max E. Kuznecov ~syhpoon <syhpoon@syhpoon.name> 2008 
  4  # 
  5  # This file is part of XYZCommander. 
  6  # XYZCommander is free software: you can redistribute it and/or modify 
  7  # it under the terms of the GNU Lesser Public License as published by 
  8  # the Free Software Foundation, either version 3 of the License, or 
  9  # (at your option) any later version. 
 10  # XYZCommander is distributed in the hope that it will be useful, 
 11  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
 13  # GNU Lesser Public License for more details. 
 14  # You should have received a copy of the GNU Lesser Public License 
 15  # along with XYZCommander. If not, see <http://www.gnu.org/licenses/>. 
 16   
 17  import copy 
 18  import traceback 
 19  import re 
 20   
 21  import libxyz.core 
 22   
 23  from libxyz.ui import lowui 
 24  from libxyz.ui import Prompt 
 25  from libxyz.ui import XYZListBox 
 26  from libxyz.ui import NumEntry 
 27  from libxyz.ui import Keys 
 28  from libxyz.ui.utils import refresh 
 29  from libxyz.core.utils import ustring, bstring, is_func 
30 31 -class Cmd(lowui.FlowWidget):
32 """ 33 Command line widget 34 """ 35 36 resolution = (u"cmd",) 37 38 LEFT = u"left" 39 RIGHT = u"right" 40 END = u"end" 41 UNDER = u"under" 42
43 - def __init__(self, xyz):
44 """ 45 @param xyz: XYZData instance 46 47 Resources used: text, prompt 48 """ 49 50 super(Cmd, self).__init__() 51 52 self.xyz = xyz 53 self._attr = lambda x: xyz.skin.attr(self.resolution, x) 54 55 self._keys = Keys() 56 57 self._text_attr = self._attr(u"text") 58 self._data = [] 59 # Internal cursor index. Value is in range(0,len(self._data)) 60 self._index = 0 61 # Virtual cursor index. Value is in range(0,maxcol) 62 self._vindex = 0 63 self._hindex = 0 64 65 self.context = None 66 self._panel = self.xyz.pm.load(":sys:panel") 67 68 self._plugin = self._init_plugin() 69 70 _conf = self._plugin.conf 71 self.prompt = Prompt(_conf[u"prompt"], self._attr(u"prompt")) 72 self._undo = libxyz.core.Queue(_conf[u"undo_depth"]) 73 self._history = libxyz.core.Queue(_conf[u"history_depth"])
74 75 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 76
77 - def _init_plugin(self):
78 """ 79 Init virtual plugin 80 """ 81 82 _cmd_plugin = libxyz.core.plugins.VirtualPlugin(self.xyz, u"cmd") 83 _cmd_plugin.AUTHOR = u"Max E. Kuznecov <syhpoon@syhpoon.name>" 84 _cmd_plugin.VERSION = u"0.1" 85 _cmd_plugin.BRIEF_DESCRIPTION = u"Command line plugin" 86 _cmd_plugin.FULL_DESCRIPTION = u"Command line plugin. "\ 87 u"It allows to enter, edit and "\ 88 u"execute commands." 89 _cmd_plugin.DOC = u"Configuration variables:\n"\ 90 u"undo_depth - Specifies how many undo levels to "\ 91 u"keep. Default - 10\n"\ 92 u"history_depth - Specifies how man entered "\ 93 u"commands to keep. Default - 50\n"\ 94 u"prompt - Command line prompt. Default - '$ '" 95 96 _cmd_plugin.export(self.del_char) 97 _cmd_plugin.export(self.del_char_left) 98 _cmd_plugin.export(self.del_word_left) 99 _cmd_plugin.export(self.del_word_right) 100 _cmd_plugin.export(self.clear) 101 _cmd_plugin.export(self.clear_left) 102 _cmd_plugin.export(self.clear_right) 103 _cmd_plugin.export(self.cursor_begin) 104 _cmd_plugin.export(self.cursor_end) 105 _cmd_plugin.export(self.cursor_left) 106 _cmd_plugin.export(self.cursor_right) 107 _cmd_plugin.export(self.cursor_word_left) 108 _cmd_plugin.export(self.cursor_word_right) 109 _cmd_plugin.export(self.is_empty) 110 _cmd_plugin.export(self.undo) 111 _cmd_plugin.export(self.undo_clear) 112 _cmd_plugin.export(self.execute) 113 _cmd_plugin.export(self.history_prev) 114 _cmd_plugin.export(self.history_next) 115 _cmd_plugin.export(self.history_clear) 116 _cmd_plugin.export(self.show_history) 117 _cmd_plugin.export(self.put_active_object) 118 _cmd_plugin.export(self.put_active_object_path) 119 _cmd_plugin.export(self.put_inactive_object) 120 _cmd_plugin.export(self.put_inactive_object_path) 121 _cmd_plugin.export(self.put_active_cwd) 122 _cmd_plugin.export(self.put_inactive_cwd) 123 _cmd_plugin.export(self.escape) 124 _cmd_plugin.export(self.replace_aliases) 125 126 self.xyz.pm.register(_cmd_plugin) 127 128 self.context = _cmd_plugin.ns.pfull 129 130 return _cmd_plugin
131 132 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 133
134 - def selectable(self):
135 return True
136 137 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 138
139 - def rows(self, (maxcol,), focus=False):
140 """ 141 Return the number of lines that will be rendered 142 """ 143 144 return 1
145 146 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 147
148 - def render(self, (maxcol,), focus=False):
149 """ 150 Render the command line 151 """ 152 153 if self.prompt is not None: 154 _canv_prompt = self.prompt.render((maxcol,)) 155 else: 156 _canv_prompt = lowui.Text(u"").render((maxcol,)) 157 158 _data = [bstring(x) for x in self._get_visible(maxcol)] 159 _text_len = abs(maxcol - self.prompt.length()) 160 161 _canv_text = lowui.AttrWrap(lowui.Text("".join(_data)), 162 self._text_attr).render((maxcol,)) 163 164 _canvases = [] 165 166 if self.prompt.length() > 0: 167 _canvases.append((_canv_prompt, None, False, self.prompt.length())) 168 169 _canvases.append((_canv_text, 0, True, _text_len)) 170 171 canv = lowui.CanvasJoin(_canvases) 172 canv.cursor = self.get_cursor_coords((maxcol,)) 173 174 return canv
175 176 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 177
178 - def _get_visible(self, maxcol):
179 """ 180 Calculate and return currently visible piece of cmd data 181 """ 182 183 maxcol -= 1 184 185 _plen = self.prompt.length() 186 _dlen = len(self._data) 187 _xindex = _plen + self._index 188 189 if self._vindex >= maxcol: 190 self._vindex = maxcol - 1 191 192 if _plen + _dlen >= maxcol: 193 _off = _xindex - maxcol 194 _to = _xindex 195 196 if _off < 0: 197 _off = 0 198 _to = maxcol - _plen + 1 199 200 _data = self._data[_off:_to] 201 else: 202 _data = self._data 203 204 return _data
205 206 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 207
208 - def get_cursor_coords(self, (maxcol,)):
209 """ 210 Return the (x,y) coordinates of cursor within widget. 211 """ 212 213 return self.prompt.length() + self._vindex, 0
214 215 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 216
217 - def _put_object(self, char):
218 self._data.insert(self._index, char) 219 self._index += 1 220 self._vindex += 1
221 222 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 223
224 - def keypress(self, size, key):
225 """ 226 Process pressed key 227 """ 228 229 _meth = self.xyz.km.process(key) 230 231 if _meth is not None: 232 return _meth() 233 else: 234 _good = [x for x in key if len(x) == 1] 235 236 if _good: 237 try: 238 map(lambda x: self._put_object(x), _good) 239 except Exception, e: 240 xyzlog.error(_(ustring(str(e)))) 241 xyzlog.debug(ustring(traceback.format_exc())) 242 else: 243 self._invalidate()
244 245 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 246
247 - def _save_undo(self):
248 """ 249 Save undo data 250 """ 251 252 self._undo.push((self._index, copy.copy(self._data)))
253 254 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 255
256 - def _restore_undo(self):
257 """ 258 Restore one undo level 259 """ 260 261 if self._undo: 262 self._index, self._data = self._undo.pop() 263 self._vindex = self._index
264 265 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 266
267 - def _save_history(self):
268 """ 269 Save typed command history 270 """ 271 272 # Prevent duplicating entries 273 if not self._history.tail() == self._data: 274 self._history.push(copy.copy(self._data)) 275 276 self._hindex = len(self._history)
277 278 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 279
280 - def _clear_cmd(self):
281 """ 282 Internal clear 283 """ 284 285 self._data = [] 286 self._index = 0 287 self._vindex = 0
288 289 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 290
291 - def _move_cursor(self, direction, chars=None, topred=None):
292 """ 293 Generic cursor moving procedure 294 @param direction: LEFT or RIGHT 295 @param chars: Number of character to move or END to move to the end 296 in corresponding direction 297 @param topred: Predicate function which must return True if char 298 under the cursor is endpoint in move 299 """ 300 301 _newindex = None 302 303 # Using predicate 304 if callable(topred): 305 if direction == self.LEFT: 306 _range = range(self._index - 1, 0, -1) 307 else: 308 _range = range(self._index + 1, len(self._data)) 309 310 for i in _range: 311 if topred(self._data[i]): 312 _newindex = i 313 break 314 315 if _newindex is None: 316 # To start or end, depending on direction 317 return self._move_cursor(direction, chars=self.END) 318 319 elif direction == self.LEFT: 320 if chars == self.END: 321 _newindex = 0 322 elif chars is not None and self._index >= chars: 323 _newindex = self._index - chars 324 325 elif direction == self.RIGHT: 326 if chars == self.END: 327 _newindex = len(self._data) 328 329 elif (self._index + chars) <= len(self._data): 330 _newindex = self._index + chars 331 332 if _newindex is not None: 333 self._index = _newindex 334 self._vindex = _newindex 335 self._invalidate()
336 337 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 338 339 @refresh
340 - def _delete(self, direction, chars=None, topred=None):
341 """ 342 Generic delete procedure 343 @param direction: LEFT, RIGHT or UNDER 344 @param chars: Number of characters to delete 345 @param topred: Predicate function which must return True if char 346 under the cursor is endpoint in delete 347 """ 348 349 _newindex = None 350 _delindex = None 351 _newdata = None 352 353 if callable(topred): 354 if direction == self.LEFT: 355 _range = range(self._index - 1, 0, -1) 356 else: 357 _range = range(self._index + 1, len(self._data)) 358 359 _found = False 360 361 for i in _range: 362 if topred(self._data[i]): 363 _found = True 364 if direction == self.LEFT: 365 _newindex = i 366 _newdata = self._data[:_newindex] + \ 367 self._data[self._index:] 368 else: 369 _newdata = self._data[:self._index] + self._data[i:] 370 371 self._save_undo() 372 break 373 374 if not _found: 375 return self._delete(direction, chars=self.END) 376 377 elif direction == self.UNDER: 378 if self._index >= 0 and self._index < len(self._data): 379 _delindex = self._index 380 381 elif direction == self.LEFT: 382 if chars == self.END: 383 self._save_undo() 384 _newdata = self._data[self._index:] 385 _newindex = 0 386 elif chars is not None and self._index >= chars: 387 _newindex = self._index - chars 388 _delindex = _newindex 389 390 elif direction == self.RIGHT: 391 if chars == self.END: 392 self._save_undo() 393 _newdata = self._data[:self._index] 394 395 if _newindex is not None: 396 self._index = _newindex 397 self._vindex = _newindex 398 if _newdata is not None: 399 self._data = _newdata 400 if _delindex is not None: 401 del(self._data[_delindex])
402 403 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 404 405 # Public methods 406
407 - def del_char_left(self):
408 """ 409 Delete single character left to the cursor 410 """ 411 412 self._delete(self.LEFT, chars=1)
413 414 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 415
416 - def del_char(self):
417 """ 418 Delete single character under the cursor 419 """ 420 421 return self._delete(self.UNDER)
422 423 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 424
425 - def del_word_left(self):
426 """ 427 Delete a word left to the cursor 428 """ 429 430 return self._delete(self.LEFT, topred=lambda x: x.isspace())
431 432 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 433
434 - def del_word_right(self):
435 """ 436 Delete a word right to the cursor 437 """ 438 439 return self._delete(self.RIGHT, topred=lambda x: x.isspace())
440 441 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 442
443 - def clear(self):
444 """ 445 Clear the whole cmd line 446 """ 447 448 self._save_undo() 449 self._clear_cmd() 450 self._invalidate()
451 452 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 453
454 - def clear_left(self):
455 """ 456 Clear the cmd line from the cursor to the left 457 """ 458 459 self._delete(self.LEFT, chars=self.END)
460 461 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 462
463 - def clear_right(self):
464 """ 465 Clear the cmd line from the cursor to the right 466 """ 467 468 return self._delete(self.RIGHT, chars=self.END)
469 470 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 471
472 - def cursor_begin(self):
473 """ 474 Move cursor to the beginning of the command line 475 """ 476 477 self._move_cursor(self.LEFT, chars=self.END)
478 479 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 480
481 - def cursor_end(self):
482 """ 483 Move cursor to the end of the command line 484 """ 485 486 self._move_cursor(self.RIGHT, chars=self.END)
487 488 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 489
490 - def cursor_left(self):
491 """ 492 Move cursor left 493 """ 494 495 self._move_cursor(self.LEFT, chars=1)
496 497 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 498
499 - def cursor_right(self):
500 """ 501 Move cursor right 502 """ 503 504 self._move_cursor(self.RIGHT, chars=1)
505 506 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 507
508 - def cursor_word_left(self):
509 """ 510 Move cursor one word left 511 """ 512 513 self._move_cursor(self.LEFT, topred=lambda x: x.isspace())
514 515 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 516
517 - def cursor_word_right(self):
518 """ 519 Move cursor one word right 520 """ 521 522 self._move_cursor(self.RIGHT, topred=lambda x: x.isspace())
523 524 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 525
526 - def execute(self):
527 """ 528 Execute cmd contents 529 """ 530 531 if not self._data: 532 return 533 534 self._save_history() 535 536 _data = self.replace_aliases("".join(self._data)) 537 538 _cmd, _rest = split_cmd(_data) 539 540 # Do not run shell, execute internal command 541 if _cmd in self.xyz.conf["commands"]: 542 try: 543 self.xyz.conf["commands"][_cmd]( 544 _rest if _rest is None else bstring(_rest)) 545 except Exception, e: 546 xyzlog.error(_("Error executing internal command %s: %s") % 547 (_cmd, ustring(str(e)))) 548 else: 549 if not hasattr(self, "_execf"): 550 self._execf = self.xyz.pm.from_load(":core:shell", "execute") 551 552 if not hasattr(self, "_reloadf"): 553 self._reloadf =self.xyz.pm.from_load(":sys:panel", 554 "reload_all") 555 556 self._execf(_data) 557 self._reloadf() 558 559 self._clear_cmd() 560 self._invalidate()
561 562 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 563
564 - def replace_aliases(self, data):
565 """ 566 Check if first word of the command line (which is supposed to be a 567 command to execute) is in our aliases table, if it is, replace it. 568 569 @param data: String 570 """ 571 572 cmd, _ = split_cmd(data) 573 574 try: 575 raw_alias = self.xyz.conf["aliases"][cmd] 576 577 if isinstance(raw_alias, basestring): 578 alias = raw_alias 579 elif is_func(raw_alias): 580 alias = raw_alias() 581 else: 582 xyzlog.error(_(u"Invalid alias type: %s") % 583 ustring(str(type(raw_alias)))) 584 return data 585 586 587 return re.sub(r"^%s" % cmd, alias, data) 588 except KeyError: 589 return data 590 except Exception, e: 591 xyzlog.error(_(u"Unable to replace an alias %s: %s") % 592 (ustring(cmd), ustring(str(e)))) 593 return data
594 595 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 596 597
598 - def is_empty(self):
599 """ 600 Return True if cmd is empty, i.e. has no contents 601 """ 602 603 return self._data == []
604 605 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 606
607 - def undo(self):
608 """ 609 Restore one level from undo buffer 610 """ 611 612 self._restore_undo() 613 self._invalidate()
614 615 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 616
617 - def undo_clear(self):
618 """ 619 Clear undo buffer 620 """ 621 622 self._undo.clear() 623 self._invalidate()
624 625 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 626
627 - def history_prev(self):
628 """ 629 Scroll through list of saved commands backward 630 """ 631 632 if self._hindex > 0: 633 self._hindex -= 1 634 self._data = copy.copy(self._history[self._hindex]) 635 self.cursor_end()
636 637 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 638
639 - def history_next(self):
640 """ 641 Scroll through list of saved commands forward 642 """ 643 644 if self._hindex < len(self._history) - 1: 645 self._hindex += 1 646 self._data = copy.copy(self._history[self._hindex]) 647 self.cursor_end()
648 649 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 650
651 - def history_clear(self):
652 """ 653 Clear commands history 654 """ 655 656 self._history.clear()
657 658 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 659
660 - def show_history(self):
661 """ 662 Show commands history list 663 """ 664 665 def _enter_cb(num): 666 if num >= len(self._history): 667 return 668 669 self._data = copy.copy(self._history[num]) 670 self.cursor_end()
671 672 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 673 674 _sel_attr = self.xyz.skin.attr(XYZListBox.resolution, u"selected") 675 676 _wdata = [] 677 678 for i in range(len(self._history)): 679 _wdata.append(NumEntry(u"".join([ustring(x) for x in 680 self._history[i]]), 681 _sel_attr, i, 682 enter_cb=_enter_cb)) 683 684 _walker = lowui.SimpleListWalker(_wdata) 685 _walker.focus = len(_walker) - 1 686 687 _dim = tuple([x - 2 for x in self.xyz.screen.get_cols_rows()]) 688 689 _ek = [self._keys.ENTER] 690 691 XYZListBox(self.xyz, self.xyz.top, _walker, _(u"History"), 692 _dim).show(exit_keys=_ek)
693 694 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 695
696 - def put_active_object(self):
697 """ 698 Put currently selected VFS object name in panel to cmd line 699 """ 700 701 return self._put_engine(self._panel.get_selected().name)
702 703 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 704
705 - def put_active_object_path(self):
706 """ 707 Put currently selected VFS object full path in panel to cmd line 708 """ 709 710 return self._put_engine(self._panel.get_selected().path)
711 712 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 713
714 - def put_inactive_object(self):
715 """ 716 Put selected VFS object name in inactive panel to cmd line 717 """ 718 719 return self._put_engine(self._panel.get_selected_inactive().name)
720 721 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 722
723 - def put_inactive_object_path(self):
724 """ 725 Put selected VFS object full path in inactive panel to cmd line 726 """ 727 728 return self._put_engine(self._panel.get_selected_inactive().path)
729 730 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 731
732 - def put_active_cwd(self):
733 """ 734 Put current working directory of active panel to cmd line 735 """ 736 737 return self._put_engine(self._panel.cwd())
738 739 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 740
741 - def put_inactive_cwd(self):
742 """ 743 Put current working directory of inactive panel to cmd line 744 """ 745 746 return self._put_engine(self._panel.cwd_inactive())
747 748 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 749
750 - def _put_engine(self, obj):
751 """ 752 Put list content to cmd 753 """ 754 755 map(lambda x: self._put_object(x), 756 self.escape([bstring(x) for x in ustring(obj)]) + [" "]) 757 self._invalidate()
758 759 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 760
761 - def escape(self, obj, join=False):
762 """ 763 Escape filename 764 @param obj: String to escape 765 @param join: If False return list otherwise return joined string 766 """ 767 768 result = [] 769 toescape = [" ", "'", '"', "*", "?", "\\", "&", 770 "(", ")", 771 "[", "]", 772 "{", "}", 773 ] 774 775 for x in obj: 776 if x in toescape: 777 result.extend(["\\", x]) 778 else: 779 result.append(x) 780 781 return "".join(result) if join else result
782
783 #++++++++++++++++++++++++++++++++++++++++++++++++ 784 785 -def split_cmd(cmdline):
786 """ 787 Return command name and the rest of the command line 788 """ 789 790 _r = cmdline.split(" ", 1) 791 792 if len(_r) == 1: 793 return _r[0], None 794 else: 795 return _r[0], _r[1]
796