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, split_cmd 
 30  from libxyz.core.dsl import XYZ 
 31  from libxyz.exceptions import XYZRuntimeError 
32 33 -class Cmd(lowui.FlowWidget):
34 """ 35 Command line widget 36 """ 37 38 resolution = (u"cmd",) 39 40 LEFT = u"left" 41 RIGHT = u"right" 42 END = u"end" 43 UNDER = u"under" 44
45 - def __init__(self, xyz):
46 """ 47 @param xyz: XYZData instance 48 49 Resources used: text, prompt 50 """ 51 52 super(Cmd, self).__init__() 53 54 self.xyz = xyz 55 self._attr = lambda x: xyz.skin.attr(self.resolution, x) 56 57 self._keys = Keys() 58 59 self._text_attr = self._attr(u"text") 60 self._data = [] 61 # Internal cursor index. Value is in range(0,len(self._data)) 62 self._index = 0 63 # Virtual cursor index. Value is in range(0,maxcol) 64 self._vindex = 0 65 self._hindex = 0 66 67 self.context = None 68 self._panel = self.xyz.pm.load(":sys:panel") 69 70 self._plugin = self._init_plugin() 71 self._ud = libxyz.core.UserData() 72 self._history_file = "history" 73 74 _conf = self._plugin.conf 75 self.prompt = Prompt(_conf[u"prompt"], self._attr(u"prompt")) 76 self._undo = libxyz.core.Queue(_conf[u"undo_depth"]) 77 self._history = libxyz.core.Queue(_conf[u"history_depth"]) 78 79 self.xyz.hm.register("event:conf_update", self._update_conf_hook) 80 self.xyz.hm.register("event:startup", self._load_history_hook) 81 self.xyz.hm.register("event:shutdown", self._save_history_hook)
82 83 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 84
85 - def _update_conf_hook(self, var, val, sect):
86 """ 87 Hook for update conf event 88 """ 89 90 # Not ours 91 if sect != "plugins" or var != self._plugin.ns.pfull: 92 return 93 94 mapping = { 95 "prompt": lambda x: self._set_prompt(x), 96 "undo_depth": lambda x: self._undo.set_size(x), 97 "history_depth": lambda x: self._history.set_size(x), 98 } 99 100 for k, v in val.iteritems(): 101 if k in mapping: 102 mapping[k](v)
103 104 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 105
106 - def _save_history_hook(self):
107 """ 108 Save history at shutdown 109 """ 110 111 f = None 112 try: 113 f = self._ud.openfile(self._history_file, "w", "data") 114 f.write("\n".join([bstring(u"".join(x)) for x in self._history])) 115 except XYZRuntimeError, e: 116 if f: 117 f.close() 118 119 xyzlog.info(_(u"Unable to open history data file: %s") 120 % unicode(e)) 121 else: 122 if f: 123 f.close()
124 125 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 126
127 - def _load_history_hook(self):
128 """ 129 Load history at startup 130 """ 131 132 f = None 133 134 try: 135 f = self._ud.openfile(self._history_file, "r", "data") 136 data = f.readlines() 137 138 if len(data) > self._history.maxsize: 139 data = data[-self._history.maxsize] 140 141 self._history.clear() 142 143 for line in data: 144 self._history.push([x for x in ustring(line.rstrip())]) 145 except Exception: 146 pass 147 148 if f: 149 f.close()
150 151 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 152
153 - def _init_plugin(self):
154 """ 155 Init virtual plugin 156 """ 157 158 _cmd_plugin = libxyz.core.plugins.VirtualPlugin(self.xyz, u"cmd") 159 _cmd_plugin.AUTHOR = u"Max E. Kuznecov <syhpoon@syhpoon.name>" 160 _cmd_plugin.VERSION = u"0.1" 161 _cmd_plugin.BRIEF_DESCRIPTION = _(u"Command line plugin") 162 _cmd_plugin.FULL_DESCRIPTION = _(u"Command line plugin. "\ 163 u"It allows to enter, edit and "\ 164 u"execute commands.") 165 _cmd_plugin.DOC = _(u"Configuration variables:\n"\ 166 u"undo_depth - Specifies how many undo levels to "\ 167 u"keep. Default - 10\n"\ 168 u"history_depth - Specifies how many entered "\ 169 u"commands to keep. Default - 50\n"\ 170 u"prompt - Command line prompt. Default - '$ '") 171 172 _cmd_plugin.export(self.del_char) 173 _cmd_plugin.export(self.del_char_left) 174 _cmd_plugin.export(self.del_word_left) 175 _cmd_plugin.export(self.del_word_right) 176 _cmd_plugin.export(self.clear) 177 _cmd_plugin.export(self.clear_left) 178 _cmd_plugin.export(self.clear_right) 179 _cmd_plugin.export(self.cursor_begin) 180 _cmd_plugin.export(self.cursor_end) 181 _cmd_plugin.export(self.cursor_left) 182 _cmd_plugin.export(self.cursor_right) 183 _cmd_plugin.export(self.cursor_word_left) 184 _cmd_plugin.export(self.cursor_word_right) 185 _cmd_plugin.export(self.is_empty) 186 _cmd_plugin.export(self.undo) 187 _cmd_plugin.export(self.undo_clear) 188 _cmd_plugin.export(self.execute) 189 _cmd_plugin.export(self.history_prev) 190 _cmd_plugin.export(self.history_next) 191 _cmd_plugin.export(self.history_clear) 192 _cmd_plugin.export(self.show_history) 193 _cmd_plugin.export(self.put_active_object) 194 _cmd_plugin.export(self.put_active_object_path) 195 _cmd_plugin.export(self.put_inactive_object) 196 _cmd_plugin.export(self.put_inactive_object_path) 197 _cmd_plugin.export(self.put_active_cwd) 198 _cmd_plugin.export(self.put_inactive_cwd) 199 _cmd_plugin.export(self.put) 200 _cmd_plugin.export(self.get) 201 _cmd_plugin.export(self.append) 202 _cmd_plugin.export(self.escape) 203 _cmd_plugin.export(self.replace_aliases) 204 205 self.xyz.pm.register(_cmd_plugin) 206 207 self.context = _cmd_plugin.ns.pfull 208 209 return _cmd_plugin
210 211 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 212
213 - def selectable(self):
214 return True
215 216 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 217
218 - def rows(self, (maxcol,), focus=False):
219 """ 220 Return the number of lines that will be rendered 221 """ 222 223 return 1
224 225 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 226
227 - def render(self, (maxcol,), focus=False):
228 """ 229 Render the command line 230 """ 231 232 if self.prompt is not None: 233 _canv_prompt = self.prompt.render((maxcol,)) 234 _prompt_len = len(self.prompt) 235 else: 236 _canv_prompt = lowui.Text(u"").render((maxcol,)) 237 _prompt_len = 0 238 239 _data = [bstring(x) for x in self._get_visible(maxcol)] 240 _text_len = abs(maxcol - _prompt_len) 241 242 _canv_text = lowui.AttrWrap(lowui.Text("".join(_data)), 243 self._text_attr).render((maxcol,)) 244 245 _canvases = [] 246 247 if _prompt_len > 0: 248 _canvases.append((_canv_prompt, None, False, _prompt_len)) 249 250 _canvases.append((_canv_text, 0, True, _text_len)) 251 252 canv = lowui.CanvasJoin(_canvases) 253 canv.cursor = self.get_cursor_coords((maxcol,)) 254 255 return canv
256 257 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 258
259 - def _get_visible(self, maxcol):
260 """ 261 Calculate and return currently visible piece of cmd data 262 """ 263 264 maxcol -= 1 265 266 _plen = len(self.prompt) 267 _dlen = len(self._data) 268 _xindex = _plen + self._index 269 270 if self._vindex >= maxcol: 271 self._vindex = maxcol - 1 272 273 if _plen + _dlen >= maxcol: 274 _off = _xindex - maxcol 275 _to = _xindex 276 277 if _off < 0: 278 _off = 0 279 _to = maxcol - _plen + 1 280 281 _data = self._data[_off:_to] 282 else: 283 _data = self._data 284 285 return _data
286 287 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 288
289 - def get_cursor_coords(self, (maxcol,)):
290 """ 291 Return the (x,y) coordinates of cursor within widget. 292 """ 293 294 return len(self.prompt) + self._vindex, 0
295 296 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 297
298 - def _put_object(self, char):
299 self._data.insert(self._index, ustring(char)) 300 self._index += 1 301 self._vindex += 1
302 303 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 304
305 - def keypress(self, size, key):
306 """ 307 Process pressed key 308 """ 309 310 _meth = self.xyz.km.process(key) 311 312 if _meth is not None: 313 return _meth() 314 else: 315 _good = [x for x in key if len(x) == 1] 316 317 if _good: 318 try: 319 map(lambda x: self._put_object(x), _good) 320 except Exception, e: 321 xyzlog.error(unicode(e)) 322 xyzlog.debug(ustring(traceback.format_exc())) 323 else: 324 self._invalidate()
325 326 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 327
328 - def _save_undo(self):
329 """ 330 Save undo data 331 """ 332 333 self._undo.push((self._index, copy.copy(self._data)))
334 335 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 336
337 - def _restore_undo(self):
338 """ 339 Restore one undo level 340 """ 341 342 if self._undo: 343 self._index, self._data = self._undo.pop() 344 self._vindex = self._index
345 346 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 347
348 - def _save_history(self):
349 """ 350 Save typed command history 351 """ 352 353 # Prevent duplicating entries 354 if not self._history.tail() == self._data: 355 self._history.push(copy.copy(self._data)) 356 357 self._hindex = len(self._history)
358 359 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 360
361 - def _clear_cmd(self):
362 """ 363 Internal clear 364 """ 365 366 self._data = [] 367 self._index = 0 368 self._vindex = 0
369 370 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 371
372 - def _move_cursor(self, direction, chars=None, topred=None):
373 """ 374 Generic cursor moving procedure 375 @param direction: LEFT or RIGHT 376 @param chars: Number of character to move or END to move to the end 377 in corresponding direction 378 @param topred: Predicate function which must return True if char 379 under the cursor is endpoint in move 380 """ 381 382 _newindex = None 383 384 # Using predicate 385 if callable(topred): 386 if direction == self.LEFT: 387 _range = range(self._index - 1, 0, -1) 388 else: 389 _range = range(self._index + 1, len(self._data)) 390 391 for i in _range: 392 if topred(self._data[i]): 393 _newindex = i 394 break 395 396 if _newindex is None: 397 # To start or end, depending on direction 398 return self._move_cursor(direction, chars=self.END) 399 400 elif direction == self.LEFT: 401 if chars == self.END: 402 _newindex = 0 403 elif chars is not None and self._index >= chars: 404 _newindex = self._index - chars 405 406 elif direction == self.RIGHT: 407 if chars == self.END: 408 _newindex = len(self._data) 409 410 elif (self._index + chars) <= len(self._data): 411 _newindex = self._index + chars 412 413 if _newindex is not None: 414 self._index = _newindex 415 self._vindex = _newindex 416 self._invalidate()
417 418 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 419 420 @refresh
421 - def _delete(self, direction, chars=None, topred=None):
422 """ 423 Generic delete procedure 424 @param direction: LEFT, RIGHT or UNDER 425 @param chars: Number of characters to delete 426 @param topred: Predicate function which must return True if char 427 under the cursor is endpoint in delete 428 """ 429 430 _newindex = None 431 _delindex = None 432 _newdata = None 433 434 if callable(topred): 435 if direction == self.LEFT: 436 _range = range(self._index - 1, 0, -1) 437 else: 438 _range = range(self._index + 1, len(self._data)) 439 440 _found = False 441 442 for i in _range: 443 if topred(self._data[i]): 444 _found = True 445 if direction == self.LEFT: 446 _newindex = i 447 _newdata = self._data[:_newindex] + \ 448 self._data[self._index:] 449 else: 450 _newdata = self._data[:self._index] + self._data[i:] 451 452 self._save_undo() 453 break 454 455 if not _found: 456 return self._delete(direction, chars=self.END) 457 458 elif direction == self.UNDER: 459 if self._index >= 0 and self._index < len(self._data): 460 _delindex = self._index 461 462 elif direction == self.LEFT: 463 if chars == self.END: 464 self._save_undo() 465 _newdata = self._data[self._index:] 466 _newindex = 0 467 elif chars is not None and self._index >= chars: 468 _newindex = self._index - chars 469 _delindex = _newindex 470 471 elif direction == self.RIGHT: 472 if chars == self.END: 473 self._save_undo() 474 _newdata = self._data[:self._index] 475 476 if _newindex is not None: 477 self._index = _newindex 478 self._vindex = _newindex 479 if _newdata is not None: 480 self._data = _newdata 481 if _delindex is not None: 482 del(self._data[_delindex])
483 484 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 485 486 # Public methods 487
488 - def del_char_left(self):
489 """ 490 Delete single character left to the cursor 491 """ 492 493 self._delete(self.LEFT, chars=1)
494 495 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 496
497 - def del_char(self):
498 """ 499 Delete single character under the cursor 500 """ 501 502 return self._delete(self.UNDER)
503 504 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 505
506 - def del_word_left(self):
507 """ 508 Delete a word left to the cursor 509 """ 510 511 return self._delete(self.LEFT, topred=lambda x: x.isspace())
512 513 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 514
515 - def del_word_right(self):
516 """ 517 Delete a word right to the cursor 518 """ 519 520 return self._delete(self.RIGHT, topred=lambda x: x.isspace())
521 522 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 523
524 - def clear(self):
525 """ 526 Clear the whole cmd line 527 """ 528 529 self._save_undo() 530 self._clear_cmd() 531 self._invalidate()
532 533 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 534
535 - def clear_left(self):
536 """ 537 Clear the cmd line from the cursor to the left 538 """ 539 540 self._delete(self.LEFT, chars=self.END)
541 542 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 543
544 - def clear_right(self):
545 """ 546 Clear the cmd line from the cursor to the right 547 """ 548 549 return self._delete(self.RIGHT, chars=self.END)
550 551 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 552
553 - def cursor_begin(self):
554 """ 555 Move cursor to the beginning of the command line 556 """ 557 558 self._move_cursor(self.LEFT, chars=self.END)
559 560 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 561
562 - def cursor_end(self):
563 """ 564 Move cursor to the end of the command line 565 """ 566 567 self._move_cursor(self.RIGHT, chars=self.END)
568 569 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 570
571 - def cursor_left(self):
572 """ 573 Move cursor left 574 """ 575 576 self._move_cursor(self.LEFT, chars=1)
577 578 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 579
580 - def cursor_right(self):
581 """ 582 Move cursor right 583 """ 584 585 self._move_cursor(self.RIGHT, chars=1)
586 587 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 588
589 - def cursor_word_left(self):
590 """ 591 Move cursor one word left 592 """ 593 594 self._move_cursor(self.LEFT, topred=lambda x: x.isspace())
595 596 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 597
598 - def cursor_word_right(self):
599 """ 600 Move cursor one word right 601 """ 602 603 self._move_cursor(self.RIGHT, topred=lambda x: x.isspace())
604 605 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 606
607 - def execute(self):
608 """ 609 Execute cmd contents 610 """ 611 612 # We're inside non-local VFS, execution is not allowed 613 if XYZ.call(":sys:panel:vfs_driver"): 614 xyzlog.error( 615 _(u"Unable to execute commands on non-local filesystems")) 616 return 617 618 if not self._data: 619 return 620 621 _data = self.replace_aliases(bstring(u"".join(self._data))) 622 _cmd, _rest = _split_cmd(_data) 623 624 if _cmd: 625 self._save_history() 626 627 # Do not run shell, execute internal command 628 if _cmd in self.xyz.conf["commands"]: 629 try: 630 if _rest is None: 631 arg = _rest 632 else: 633 arg = _rest 634 635 self.xyz.conf["commands"][_cmd](arg) 636 except Exception, e: 637 xyzlog.error(_("Error executing internal command %s: %s") % 638 (_cmd, unicode(e))) 639 elif _cmd: 640 if not hasattr(self, "_execf"): 641 self._execf = self.xyz.pm.from_load(":core:shell", "execute") 642 643 if not hasattr(self, "_reloadf"): 644 self._reloadf = self.xyz.pm.from_load(":sys:panel", 645 "reload_all") 646 647 self._execf(_data) 648 self._reloadf() 649 650 self._clear_cmd() 651 self._invalidate()
652 653 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 654
655 - def replace_aliases(self, data):
656 """ 657 Check if first word of the command line (which is supposed to be a 658 command to execute) is in our aliases table, if it is, replace it. 659 660 @param data: String 661 """ 662 663 cmd, _ = _split_cmd(data) 664 665 try: 666 raw_alias = self.xyz.conf["aliases"][cmd] 667 668 if isinstance(raw_alias, basestring): 669 alias = raw_alias 670 elif is_func(raw_alias): 671 alias = raw_alias() 672 else: 673 xyzlog.error(_(u"Invalid alias type: %s") % 674 ustring(str(type(raw_alias)))) 675 return data 676 677 return re.sub(r"^%s" % cmd, alias, data) 678 except KeyError: 679 return data 680 except Exception, e: 681 xyzlog.error(_(u"Unable to replace an alias %s: %s") % 682 (ustring(cmd), unicode(e))) 683 return data
684 685 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 686
687 - def is_empty(self):
688 """ 689 Return True if cmd is empty, i.e. has no contents 690 """ 691 692 return self._data == []
693 694 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 695
696 - def undo(self):
697 """ 698 Restore one level from undo buffer 699 """ 700 701 self._restore_undo() 702 self._invalidate()
703 704 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 705
706 - def undo_clear(self):
707 """ 708 Clear undo buffer 709 """ 710 711 self._undo.clear() 712 self._invalidate()
713 714 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 715
716 - def history_prev(self):
717 """ 718 Scroll through list of saved commands backward 719 """ 720 721 if self._hindex > 0: 722 self._hindex -= 1 723 self._data = copy.copy(self._history[self._hindex]) 724 self.cursor_end()
725 726 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 727
728 - def history_next(self):
729 """ 730 Scroll through list of saved commands forward 731 """ 732 733 if self._hindex < len(self._history) - 1: 734 self._hindex += 1 735 self._data = copy.copy(self._history[self._hindex]) 736 self.cursor_end()
737 738 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 739
740 - def history_clear(self):
741 """ 742 Clear commands history 743 """ 744 745 self._history.clear()
746 747 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 748
749 - def show_history(self):
750 """ 751 Show commands history list 752 """ 753 754 def _enter_cb(num): 755 if num >= len(self._history): 756 return 757 758 self._data = copy.copy(self._history[num]) 759 self.cursor_end()
760 761 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 762 763 _sel_attr = self.xyz.skin.attr(XYZListBox.resolution, u"selected") 764 765 _wdata = [] 766 767 for i in range(len(self._history)): 768 _wdata.append(NumEntry(u"".join([ustring(x) for x in 769 self._history[i]]), 770 _sel_attr, i, 771 enter_cb=_enter_cb)) 772 773 _walker = lowui.SimpleListWalker(_wdata) 774 _walker.focus = len(_walker) - 1 775 776 _dim = tuple([x - 2 for x in self.xyz.screen.get_cols_rows()]) 777 778 _ek = [self._keys.ENTER] 779 780 XYZListBox(self.xyz, self.xyz.top, _walker, _(u"History"), 781 _dim).show(exit_keys=_ek)
782 783 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 784
785 - def put_active_object(self):
786 """ 787 Put currently selected VFS object name in panel to cmd line 788 """ 789 790 return self._put_engine(self._panel.get_selected().name)
791 792 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 793
794 - def put_active_object_path(self):
795 """ 796 Put currently selected VFS object full path in panel to cmd line 797 """ 798 799 return self._put_engine(self._panel.get_selected().full_path)
800 801 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 802
803 - def put_inactive_object(self):
804 """ 805 Put selected VFS object name in inactive panel to cmd line 806 """ 807 808 return self._put_engine(self._panel.get_selected(False).name)
809 810 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 811
812 - def put_inactive_object_path(self):
813 """ 814 Put selected VFS object full path in inactive panel to cmd line 815 """ 816 817 return self._put_engine(self._panel.get_selected(False).full_path)
818 819 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 820
821 - def put_active_cwd(self):
822 """ 823 Put current working directory of active panel to cmd line 824 """ 825 826 return self._put_engine(self._panel.cwd())
827 828 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 829
830 - def put_inactive_cwd(self):
831 """ 832 Put current working directory of inactive panel to cmd line 833 """ 834 835 return self._put_engine(self._panel.cwd(False))
836 837 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 838
839 - def put(self, obj, space=True):
840 """ 841 Put arbitrary string to cmd line starting from the cursor position 842 @param space: Flag indicating whether to append space char after the obj 843 """ 844 845 return self._put_engine(obj, space=space)
846 847 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 848
849 - def get(self):
850 """ 851 Get cmd contents 852 """ 853 854 return bstring(u"".join(self._data))
855 856 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 857
858 - def append(self, obj):
859 """ 860 Append arbitrary string at the end of cmd 861 """ 862 863 self.cursor_end() 864 self.put(obj, space=False)
865 866 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 867
868 - def _put_engine(self, obj, space=True):
869 """ 870 Put list content to cmd 871 """ 872 873 if space: 874 extra = [u" "] 875 else: 876 extra = [] 877 878 map(lambda x: self._put_object(x), 879 self.escape([x for x in ustring(obj)]) + extra) 880 self._invalidate()
881 882 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 883
884 - def escape(self, obj, join=False):
885 """ 886 Escape filename 887 @param obj: String to escape 888 @param join: If False return list otherwise return joined string 889 """ 890 891 result = [] 892 toescape = [u" ", u"'", u'"', u"*", u"?", u"\\", u"&", 893 u"(", ")", 894 u"[", "]", 895 u"{", "}", 896 ] 897 898 if isinstance(obj, basestring): 899 obj = ustring(obj) 900 901 for x in obj: 902 if x in toescape: 903 result.extend([u"\\", x]) 904 else: 905 result.append(x) 906 907 if join: 908 return u"".join(result) 909 else: 910 return result
911 912 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 913
914 - def _set_prompt(self, new):
915 """ 916 Set command line prompt 917 """ 918 919 self.prompt = Prompt(new, self._attr(u"prompt")) 920 self._invalidate()
921
922 #++++++++++++++++++++++++++++++++++++++++++++++++ 923 924 -def _split_cmd(cmdline):
925 """ 926 Return command name and the rest of the command line 927 """ 928 929 _r = split_cmd(cmdline) 930 _len = len(_r) 931 932 if _len == 0: 933 return "", None 934 elif _len == 1: 935 return _r[0], None 936 else: 937 return _r[0], _r[1]
938