home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2010 November / maximum-cd-2010-11.iso / DiscContents / calibre-0.7.13.msi / file_1727 (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2010-08-06  |  47.0 KB  |  1,629 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. import curses
  5. import fcntl
  6. import signal
  7. import struct
  8. import tty
  9. import textwrap
  10. import inspect
  11. from IPython import ipapi
  12. import astyle
  13. import ipipe
  14.  
  15. try:
  16.     set
  17. except NameError:
  18.     import sets
  19.     set = sets.Set
  20.  
  21.  
  22. try:
  23.     sorted
  24. except NameError:
  25.     from ipipe import sorted
  26.  
  27.  
  28. class UnassignedKeyError(Exception):
  29.     pass
  30.  
  31.  
  32. class UnknownCommandError(Exception):
  33.     pass
  34.  
  35.  
  36. class CommandError(Exception):
  37.     pass
  38.  
  39.  
  40. class Keymap(dict):
  41.     
  42.     def __init__(self):
  43.         self._keymap = { }
  44.  
  45.     
  46.     def __setitem__(self, key, command):
  47.         if isinstance(key, str):
  48.             for c in key:
  49.                 dict.__setitem__(self, ord(c), command)
  50.             
  51.         else:
  52.             dict.__setitem__(self, key, command)
  53.  
  54.     
  55.     def __getitem__(self, key):
  56.         if isinstance(key, str):
  57.             key = ord(key)
  58.         
  59.         return dict.__getitem__(self, key)
  60.  
  61.     
  62.     def __detitem__(self, key):
  63.         if isinstance(key, str):
  64.             key = ord(key)
  65.         
  66.         dict.__detitem__(self, key)
  67.  
  68.     
  69.     def register(self, command, *keys):
  70.         for key in keys:
  71.             self[key] = command
  72.         
  73.  
  74.     
  75.     def get(self, key, default = None):
  76.         if isinstance(key, str):
  77.             key = ord(key)
  78.         
  79.         return dict.get(self, key, default)
  80.  
  81.     
  82.     def findkey(self, command, default = ipipe.noitem):
  83.         for key, commandcandidate in self.iteritems():
  84.             if commandcandidate == command:
  85.                 return key
  86.         
  87.         if default is ipipe.noitem:
  88.             raise KeyError(command)
  89.         default is ipipe.noitem
  90.         return default
  91.  
  92.  
  93.  
  94. class _BrowserCachedItem(object):
  95.     __slots__ = ('item', 'marked')
  96.     
  97.     def __init__(self, item):
  98.         self.item = item
  99.         self.marked = False
  100.  
  101.  
  102.  
  103. class _BrowserHelp(object):
  104.     style_header = astyle.Style.fromstr('yellow:black:bold')
  105.     
  106.     def __init__(self, browser):
  107.         self.browser = browser
  108.  
  109.     
  110.     def __xrepr__(self, mode):
  111.         yield (-1, True)
  112.         if mode == 'header' or mode == 'footer':
  113.             yield (astyle.style_default, 'ibrowse help screen')
  114.         else:
  115.             yield (astyle.style_default, repr(self))
  116.  
  117.     
  118.     def __iter__(self):
  119.         allkeys = { }
  120.         for key, cmd in self.browser.keymap.iteritems():
  121.             allkeys.setdefault(cmd, []).append(key)
  122.         
  123.         fields = ('key', 'description')
  124.         commands = []
  125.         for name in dir(self.browser):
  126.             if name.startswith('cmd_'):
  127.                 command = getattr(self.browser, name)
  128.                 commands.append((inspect.getsourcelines(command)[-1], name[4:], command))
  129.                 continue
  130.         
  131.         commands.sort()
  132.         commands = [ (c[1], c[2]) for c in commands ]
  133.         for name, command in enumerate(commands):
  134.             description = command.__doc__
  135.             keys = allkeys.get(name, [])
  136.             yield ipipe.Fields(fields, key = '', description = astyle.Text((self.style_header, name)))
  137.             [] if description is None else []
  138.             for i in xrange(max(len(keys), len(lines))):
  139.                 
  140.                 try:
  141.                     key = self.browser.keylabel(keys[i])
  142.                 except IndexError:
  143.                     key = ''
  144.  
  145.                 
  146.                 try:
  147.                     line = lines[i]
  148.                 except IndexError:
  149.                     line = ''
  150.  
  151.                 yield ipipe.Fields(fields, key = key, description = line)
  152.             
  153.         
  154.  
  155.  
  156.  
  157. class _BrowserLevel(object):
  158.     
  159.     def __init__(self, browser, input, mainsizey, *attrs):
  160.         self.browser = browser
  161.         self.input = input
  162.         self.header = _[1]
  163.         self.iterator = ipipe.xiter(input)
  164.         self.exhausted = False
  165.         self.attrs = attrs
  166.         self.items = ipipe.deque()
  167.         self.marked = 0
  168.         self.cury = 0
  169.         self.curx = 0
  170.         self.datastartx = 0
  171.         self.datastarty = 0
  172.         self.mainsizey = mainsizey
  173.         self.mainsizex = 0
  174.         self.numbersizex = 0
  175.         self.displayattrs = []
  176.         self.displayattr = (None, ipipe.noitem)
  177.         self.colwidths = { }
  178.         self.hiddenattrs = set()
  179.         self.moveto(0, 0, refresh = True)
  180.  
  181.     
  182.     def fetch(self, count):
  183.         have = len(self.items)
  184.         while not (self.exhausted) and have < count:
  185.             
  186.             try:
  187.                 item = self.iterator.next()
  188.             except StopIteration:
  189.                 self.exhausted = True
  190.                 break
  191.                 continue
  192.                 except (KeyboardInterrupt, SystemExit):
  193.                     raise 
  194.                     continue
  195.                     except Exception:
  196.                         exc = None
  197.                         have += 1
  198.                         self.items.append(_BrowserCachedItem(exc))
  199.                         self.exhausted = True
  200.                         break
  201.                         continue
  202.                     else:
  203.                         have += 1
  204.                         self.items.append(_BrowserCachedItem(item))
  205.                     None<EXCEPTION MATCH>Exception
  206.                 return None
  207.  
  208.  
  209.     
  210.     def calcdisplayattrs(self):
  211.         attrs = set()
  212.         self.displayattrs = []
  213.         if self.attrs:
  214.             for attr in self.attrs:
  215.                 attr = ipipe.upgradexattr(attr)
  216.                 if attr not in attrs and attr not in self.hiddenattrs:
  217.                     self.displayattrs.append(attr)
  218.                     attrs.add(attr)
  219.                     continue
  220.             
  221.         else:
  222.             endy = min(self.datastarty + self.mainsizey, len(self.items))
  223.             for i in xrange(self.datastarty, endy):
  224.                 for attr in ipipe.xattrs(self.items[i].item, 'default'):
  225.                     if attr not in attrs and attr not in self.hiddenattrs:
  226.                         self.displayattrs.append(attr)
  227.                         attrs.add(attr)
  228.                         continue
  229.                 
  230.             
  231.  
  232.     
  233.     def getrow(self, i):
  234.         row = { }
  235.         item = self.items[i].item
  236.         for attr in self.displayattrs:
  237.             
  238.             try:
  239.                 value = attr.value(item)
  240.             except (KeyboardInterrupt, SystemExit):
  241.                 raise 
  242.             except Exception:
  243.                 exc = None
  244.                 value = exc
  245.  
  246.             if value is not ipipe.noitem:
  247.                 row[attr] = ipipe.xformat(value, 'cell', self.browser.maxattrlength)
  248.                 continue
  249.         
  250.         return row
  251.  
  252.     
  253.     def calcwidths(self):
  254.         self.colwidths = { }
  255.         for row in self.displayrows:
  256.             for attr in self.displayattrs:
  257.                 
  258.                 try:
  259.                     length = row[attr][1]
  260.                 except KeyError:
  261.                     length = 0
  262.  
  263.                 if attr not in self.colwidths:
  264.                     self.colwidths[attr] = len(attr.name())
  265.                 
  266.                 newwidth = max(self.colwidths[attr], length)
  267.                 self.colwidths[attr] = newwidth
  268.             
  269.         
  270.         self.numbersizex = len(str(self.datastarty + self.mainsizey - 1))
  271.         self.mainsizex = self.browser.scrsizex - self.numbersizex - 3
  272.         self.datasizex = sum(self.colwidths.itervalues()) + len(self.colwidths)
  273.  
  274.     
  275.     def calcdisplayattr(self):
  276.         pos = 0
  277.         for i, attr in enumerate(self.displayattrs):
  278.             if pos + self.colwidths[attr] >= self.curx:
  279.                 self.displayattr = (i, attr)
  280.                 break
  281.             
  282.             pos += self.colwidths[attr] + 1
  283.         else:
  284.             self.displayattr = (None, ipipe.noitem)
  285.  
  286.     
  287.     def moveto(self, x, y, refresh = False):
  288.         olddatastarty = self.datastarty
  289.         oldx = self.curx
  290.         oldy = self.cury
  291.         x = int(x + 0.5)
  292.         y = int(y + 0.5)
  293.         newx = x
  294.         newy = y
  295.         scrollbordery = min(self.browser.scrollbordery, self.mainsizey // 2)
  296.         scrollborderx = min(self.browser.scrollborderx, self.mainsizex // 2)
  297.         if y < 0:
  298.             y = 0
  299.         
  300.         self.fetch(max(y + scrollbordery + 1, self.mainsizey))
  301.         if y >= len(self.items):
  302.             y = max(0, len(self.items) - 1)
  303.         
  304.         if y < self.datastarty + scrollbordery:
  305.             self.datastarty = max(0, y - scrollbordery)
  306.         elif y >= self.datastarty + self.mainsizey - scrollbordery:
  307.             self.datastarty = max(0, min((y - self.mainsizey) + scrollbordery + 1, len(self.items) - self.mainsizey))
  308.         
  309.         if refresh:
  310.             self.calcdisplayattrs()
  311.             endy = min(self.datastarty + self.mainsizey, len(self.items))
  312.             self.displayrows = map(self.getrow, xrange(self.datastarty, endy))
  313.             self.calcwidths()
  314.         elif self.datastarty != olddatastarty:
  315.             olddisplayattrs = self.displayattrs
  316.             self.calcdisplayattrs()
  317.             if self.displayattrs != olddisplayattrs:
  318.                 endy = min(self.datastarty + self.mainsizey, len(self.items))
  319.                 self.displayrows = map(self.getrow, xrange(self.datastarty, endy))
  320.             elif self.datastarty < olddatastarty:
  321.                 del self.displayrows[self.datastarty - olddatastarty:]
  322.                 for i in xrange(min(olddatastarty, self.datastarty + self.mainsizey) - 1, self.datastarty - 1, -1):
  323.                     
  324.                     try:
  325.                         row = self.getrow(i)
  326.                     except IndexError:
  327.                         break
  328.  
  329.                     self.displayrows.insert(0, row)
  330.                 
  331.             else:
  332.                 del self.displayrows[:self.datastarty - olddatastarty]
  333.                 for i in xrange(max(olddatastarty + self.mainsizey, self.datastarty), self.datastarty + self.mainsizey):
  334.                     
  335.                     try:
  336.                         row = self.getrow(i)
  337.                     except IndexError:
  338.                         break
  339.  
  340.                     self.displayrows.append(row)
  341.                 
  342.             self.calcwidths()
  343.         
  344.         if x < 0:
  345.             x = 0
  346.         elif x >= self.datasizex:
  347.             x = max(0, self.datasizex - 1)
  348.         
  349.         if x < self.datastartx + scrollborderx:
  350.             self.datastartx = max(0, x - scrollborderx)
  351.         elif x >= self.datastartx + self.mainsizex - scrollborderx:
  352.             self.datastartx = max(0, min((x - self.mainsizex) + scrollborderx + 1, self.datasizex - self.mainsizex))
  353.         
  354.         if x == oldx and y == oldy:
  355.             if x != newx or y != newy:
  356.                 self.browser.beep()
  357.             else:
  358.                 self.curx = x
  359.                 self.cury = y
  360.                 self.calcdisplayattr()
  361.  
  362.     
  363.     def sort(self, key, reverse = False):
  364.         curitem = self.items[self.cury]
  365.         
  366.         def realkey(item):
  367.             return key(item.item)
  368.  
  369.         self.items = ipipe.deque(sorted(self.items, key = realkey, reverse = reverse))
  370.         cury = self.cury
  371.         for i, item in enumerate(self.items):
  372.             if item is curitem:
  373.                 cury = i
  374.                 break
  375.                 continue
  376.             (None,)
  377.         
  378.         self.moveto(self.curx, cury, refresh = True)
  379.  
  380.     
  381.     def refresh(self):
  382.         self.iterator = ipipe.xiter(self.input)
  383.         self.items.clear()
  384.         self.exhausted = False
  385.         self.datastartx = self.datastarty = 0
  386.         self.moveto(0, 0, refresh = True)
  387.  
  388.     
  389.     def refreshfind(self):
  390.         
  391.         try:
  392.             oldobject = self.items[self.cury].item
  393.         except IndexError:
  394.             oldobject = ipipe.noitem
  395.  
  396.         self.iterator = ipipe.xiter(self.input)
  397.         self.items.clear()
  398.         self.exhausted = False
  399.         while True:
  400.             self.fetch(len(self.items) + 1)
  401.             if self.exhausted:
  402.                 curses.beep()
  403.                 self.datastartx = self.datastarty = 0
  404.                 self.moveto(self.curx, 0, refresh = True)
  405.                 break
  406.             
  407.             if self.items[-1].item == oldobject:
  408.                 self.datastartx = self.datastarty = 0
  409.                 self.moveto(self.curx, len(self.items) - 1, refresh = True)
  410.                 break
  411.                 continue
  412.  
  413.  
  414.  
  415. class _CommandInput(object):
  416.     keymap = Keymap()
  417.     keymap.register('left', curses.KEY_LEFT)
  418.     keymap.register('right', curses.KEY_RIGHT)
  419.     keymap.register('home', curses.KEY_HOME, '\x01')
  420.     keymap.register('end', curses.KEY_END, '\x05')
  421.     keymap.register('backspace', curses.KEY_BACKSPACE, '\x08\x7f')
  422.     keymap.register('delete', curses.KEY_DC)
  423.     keymap.register('delend', 11)
  424.     keymap.register('execute', '\r\n')
  425.     keymap.register('up', curses.KEY_UP)
  426.     keymap.register('down', curses.KEY_DOWN)
  427.     keymap.register('incsearchup', curses.KEY_PPAGE)
  428.     keymap.register('incsearchdown', curses.KEY_NPAGE)
  429.     (keymap.register('exit', '\x18'),)
  430.     
  431.     def __init__(self, prompt):
  432.         self.prompt = prompt
  433.         self.history = []
  434.         self.maxhistory = 100
  435.         self.input = ''
  436.         self.curx = 0
  437.         self.cury = -1
  438.  
  439.     
  440.     def start(self):
  441.         self.input = ''
  442.         self.curx = 0
  443.         self.cury = -1
  444.  
  445.     
  446.     def handlekey(self, browser, key):
  447.         cmdname = self.keymap.get(key, None)
  448.         if cmdname is not None:
  449.             cmdfunc = getattr(self, 'cmd_%s' % cmdname, None)
  450.             if cmdfunc is not None:
  451.                 return cmdfunc(browser)
  452.             curses.beep()
  453.         elif key != -1:
  454.             
  455.             try:
  456.                 char = chr(key)
  457.             except ValueError:
  458.                 curses.beep()
  459.  
  460.             return self.handlechar(browser, char)
  461.         
  462.  
  463.     
  464.     def handlechar(self, browser, char):
  465.         self.input = self.input[:self.curx] + char + self.input[self.curx:]
  466.         self.curx += 1
  467.         return True
  468.  
  469.     
  470.     def dohistory(self):
  471.         self.history.insert(0, self.input)
  472.         del self.history[:-(self.maxhistory)]
  473.  
  474.     
  475.     def cmd_backspace(self, browser):
  476.         if self.curx:
  477.             self.input = self.input[:self.curx - 1] + self.input[self.curx:]
  478.             self.curx -= 1
  479.             return True
  480.         curses.beep()
  481.  
  482.     
  483.     def cmd_delete(self, browser):
  484.         if self.curx < len(self.input):
  485.             self.input = self.input[:self.curx] + self.input[self.curx + 1:]
  486.             return True
  487.         curses.beep()
  488.  
  489.     
  490.     def cmd_delend(self, browser):
  491.         if self.curx < len(self.input):
  492.             self.input = self.input[:self.curx]
  493.             return True
  494.  
  495.     
  496.     def cmd_left(self, browser):
  497.         if self.curx:
  498.             self.curx -= 1
  499.             return True
  500.         curses.beep()
  501.  
  502.     
  503.     def cmd_right(self, browser):
  504.         if self.curx < len(self.input):
  505.             self.curx += 1
  506.             return True
  507.         curses.beep()
  508.  
  509.     
  510.     def cmd_home(self, browser):
  511.         if self.curx:
  512.             self.curx = 0
  513.             return True
  514.         curses.beep()
  515.  
  516.     
  517.     def cmd_end(self, browser):
  518.         if self.curx < len(self.input):
  519.             self.curx = len(self.input)
  520.             return True
  521.         curses.beep()
  522.  
  523.     
  524.     def cmd_up(self, browser):
  525.         if self.cury < len(self.history) - 1:
  526.             self.cury += 1
  527.             self.input = self.history[self.cury]
  528.             self.curx = len(self.input)
  529.             return True
  530.         curses.beep()
  531.  
  532.     
  533.     def cmd_down(self, browser):
  534.         if self.cury >= 0:
  535.             self.cury -= 1
  536.             if self.cury >= 0:
  537.                 self.input = self.history[self.cury]
  538.             else:
  539.                 self.input = ''
  540.             self.curx = len(self.input)
  541.             return True
  542.         curses.beep()
  543.  
  544.     
  545.     def cmd_incsearchup(self, browser):
  546.         prefix = self.input[:self.curx]
  547.         cury = self.cury
  548.         while True:
  549.             cury += 1
  550.             if cury >= len(self.history):
  551.                 break
  552.             
  553.             if self.history[cury].startswith(prefix):
  554.                 self.input = self.history[cury]
  555.                 self.cury = cury
  556.                 return True
  557.             continue
  558.             self.history[cury].startswith(prefix)
  559.         curses.beep()
  560.  
  561.     
  562.     def cmd_incsearchdown(self, browser):
  563.         prefix = self.input[:self.curx]
  564.         cury = self.cury
  565.         while True:
  566.             cury -= 1
  567.             if cury <= 0:
  568.                 break
  569.             
  570.             if self.history[cury].startswith(prefix):
  571.                 self.input = self.history[self.cury]
  572.                 self.cury = cury
  573.                 return True
  574.             continue
  575.             self.history[cury].startswith(prefix)
  576.         curses.beep()
  577.  
  578.     
  579.     def cmd_exit(self, browser):
  580.         browser.mode = 'default'
  581.         return True
  582.  
  583.     
  584.     def cmd_execute(self, browser):
  585.         raise NotImplementedError
  586.  
  587.  
  588.  
  589. class _CommandGoto(_CommandInput):
  590.     
  591.     def __init__(self):
  592.         _CommandInput.__init__(self, 'goto object #')
  593.  
  594.     
  595.     def handlechar(self, browser, char):
  596.         if char <= char:
  597.             pass
  598.         elif not char <= '9':
  599.             curses.beep()
  600.         else:
  601.             return _CommandInput.handlechar(self, browser, char)
  602.         return char <= '9'
  603.  
  604.     
  605.     def cmd_execute(self, browser):
  606.         level = browser.levels[-1]
  607.         if self.input:
  608.             self.dohistory()
  609.             level.moveto(level.curx, int(self.input))
  610.         
  611.         browser.mode = 'default'
  612.         return True
  613.  
  614.  
  615.  
  616. class _CommandFind(_CommandInput):
  617.     
  618.     def __init__(self):
  619.         _CommandInput.__init__(self, 'find expression')
  620.  
  621.     
  622.     def cmd_execute(self, browser):
  623.         level = browser.levels[-1]
  624.         if self.input:
  625.             self.dohistory()
  626.             while True:
  627.                 cury = level.cury
  628.                 level.moveto(level.curx, cury + 1)
  629.                 if cury == level.cury:
  630.                     curses.beep()
  631.                     break
  632.                 
  633.                 item = level.items[level.cury].item
  634.                 
  635.                 try:
  636.                     globals = ipipe.getglobals(None)
  637.                     if eval(self.input, globals, ipipe.AttrNamespace(item)):
  638.                         break
  639.                 continue
  640.                 except (KeyboardInterrupt, SystemExit):
  641.                     raise 
  642.                     continue
  643.                     except Exception:
  644.                         exc = None
  645.                         browser.report(exc)
  646.                         curses.beep()
  647.                         break
  648.                         continue
  649.                     
  650.                     None<EXCEPTION MATCH>Exception
  651.                 except:
  652.                     None<EXCEPTION MATCH>(KeyboardInterrupt, SystemExit)
  653.                     browser.mode = 'default'
  654.                     return True
  655.  
  656.  
  657.  
  658.  
  659. class _CommandFindBackwards(_CommandInput):
  660.     
  661.     def __init__(self):
  662.         _CommandInput.__init__(self, 'find backwards expression')
  663.  
  664.     
  665.     def cmd_execute(self, browser):
  666.         level = browser.levels[-1]
  667.         if self.input:
  668.             self.dohistory()
  669.             while level.cury:
  670.                 level.moveto(level.curx, level.cury - 1)
  671.                 item = level.items[level.cury].item
  672.                 
  673.                 try:
  674.                     globals = ipipe.getglobals(None)
  675.                     if eval(self.input, globals, ipipe.AttrNamespace(item)):
  676.                         break
  677.                 continue
  678.                 except (KeyboardInterrupt, SystemExit):
  679.                     raise 
  680.                     continue
  681.                     except Exception:
  682.                         exc = None
  683.                         browser.report(exc)
  684.                         curses.beep()
  685.                         break
  686.                         continue
  687.                     
  688.                     None<EXCEPTION MATCH>Exception
  689.                 except:
  690.                     None<EXCEPTION MATCH>(KeyboardInterrupt, SystemExit)
  691.                     browser.mode = 'default'
  692.                     return True
  693.  
  694.  
  695.  
  696.  
  697. class ibrowse(ipipe.Display):
  698.     pageoverlapx = 1
  699.     pageoverlapy = 1
  700.     scrollborderx = 10
  701.     scrollbordery = 5
  702.     acceleratex = 1.05
  703.     acceleratey = 1.05
  704.     maxspeedx = 0.5
  705.     maxspeedy = 0.5
  706.     maxheaders = 5
  707.     maxattrlength = 200
  708.     style_objheadertext = astyle.Style.fromstr('white:black:bold|reverse')
  709.     style_objheadernumber = astyle.Style.fromstr('white:blue:bold|reverse')
  710.     style_objheaderobject = astyle.Style.fromstr('white:black:reverse')
  711.     style_colheader = astyle.Style.fromstr('blue:white:reverse')
  712.     style_colheaderhere = astyle.Style.fromstr('green:black:bold|reverse')
  713.     style_colheadersep = astyle.Style.fromstr('blue:black:reverse')
  714.     style_number = astyle.Style.fromstr('blue:white:reverse')
  715.     style_numberhere = astyle.Style.fromstr('green:black:bold|reverse')
  716.     style_sep = astyle.Style.fromstr('blue:black')
  717.     style_data = astyle.Style.fromstr('white:black')
  718.     style_datapad = astyle.Style.fromstr('blue:black:bold')
  719.     style_footer = astyle.Style.fromstr('black:white')
  720.     style_report = astyle.Style.fromstr('white:black')
  721.     headersepchar = '|'
  722.     datapadchar = '.'
  723.     datasepchar = '|'
  724.     nodatachar = '-'
  725.     prompts = {
  726.         'goto': _CommandGoto(),
  727.         'find': _CommandFind(),
  728.         'findbackwards': _CommandFindBackwards() }
  729.     keymap = Keymap()
  730.     keymap.register('quit', 'q')
  731.     keymap.register('up', curses.KEY_UP)
  732.     keymap.register('down', curses.KEY_DOWN)
  733.     keymap.register('pageup', curses.KEY_PPAGE)
  734.     keymap.register('pagedown', curses.KEY_NPAGE)
  735.     keymap.register('left', curses.KEY_LEFT)
  736.     keymap.register('right', curses.KEY_RIGHT)
  737.     keymap.register('home', curses.KEY_HOME, '\x01')
  738.     keymap.register('end', curses.KEY_END, '\x05')
  739.     keymap.register('prevattr', '<\x1b')
  740.     keymap.register('nextattr', '>\t')
  741.     keymap.register('pick', 'p')
  742.     keymap.register('pickattr', 'P')
  743.     keymap.register('pickallattrs', 'C')
  744.     keymap.register('pickmarked', 'm')
  745.     keymap.register('pickmarkedattr', 'M')
  746.     keymap.register('pickinput', 'i')
  747.     keymap.register('pickinputattr', 'I')
  748.     keymap.register('hideattr', 'h')
  749.     keymap.register('unhideattrs', 'H')
  750.     keymap.register('help', '?')
  751.     keymap.register('enter', '\r\n')
  752.     keymap.register('enterattr', 'E')
  753.     keymap.register('leave', curses.KEY_BACKSPACE, 'x\x08\x7f')
  754.     keymap.register('detail', 'd')
  755.     keymap.register('detailattr', 'D')
  756.     keymap.register('tooglemark', ' ')
  757.     keymap.register('markrange', '%')
  758.     keymap.register('sortattrasc', 'v')
  759.     keymap.register('sortattrdesc', 'V')
  760.     keymap.register('goto', 'g')
  761.     keymap.register('find', 'f')
  762.     keymap.register('findbackwards', 'b')
  763.     keymap.register('refresh', 'r')
  764.     keymap.register('refreshfind', 'R')
  765.     
  766.     def __init__(self, input = None, *attrs):
  767.         ipipe.Display.__init__(self, input)
  768.         self.attrs = attrs
  769.         self.levels = []
  770.         self.stepx = 1
  771.         self.stepy = 1
  772.         self._dobeep = True
  773.         self._styles = { }
  774.         self._colors = { }
  775.         self._maxcolor = 1
  776.         self._headerlines = 1
  777.         self._firstheaderline = 0
  778.         self.scr = None
  779.         self._report = None
  780.         self.returnvalue = None
  781.         self.mode = 'default'
  782.         self.resized = False
  783.  
  784.     
  785.     def nextstepx(self, step):
  786.         return max(1, min(step * self.acceleratex, self.maxspeedx * self.levels[-1].mainsizex))
  787.  
  788.     
  789.     def nextstepy(self, step):
  790.         return max(1, min(step * self.acceleratey, self.maxspeedy * self.levels[-1].mainsizey))
  791.  
  792.     
  793.     def getstyle(self, style):
  794.         
  795.         try:
  796.             return self._styles[(style.fg, style.bg, style.attrs)]
  797.         except KeyError:
  798.             attrs = 0
  799.             for b in astyle.A2CURSES:
  800.                 if style.attrs & b:
  801.                     attrs |= astyle.A2CURSES[b]
  802.                     continue
  803.             
  804.             
  805.             try:
  806.                 color = self._colors[(style.fg, style.bg)]
  807.             except KeyError:
  808.                 curses.init_pair(self._maxcolor, astyle.COLOR2CURSES[style.fg], astyle.COLOR2CURSES[style.bg])
  809.                 color = curses.color_pair(self._maxcolor)
  810.                 self._colors[(style.fg, style.bg)] = color
  811.                 self._maxcolor += 1
  812.             except:
  813.                 self
  814.  
  815.             c = color | attrs
  816.             self._styles[(style.fg, style.bg, style.attrs)] = c
  817.             return c
  818.             self
  819.  
  820.  
  821.     
  822.     def addstr(self, y, x, begx, endx, text, style):
  823.         text2 = text[max(0, begx - x):max(0, endx - x)]
  824.         if text2:
  825.             self.scr.addstr(y, max(x, begx), text2, self.getstyle(style))
  826.         
  827.         return len(text)
  828.  
  829.     
  830.     def addchr(self, y, x, begx, endx, c, l, style):
  831.         x0 = max(x, begx)
  832.         x1 = min(x + l, endx)
  833.         if x1 > x0:
  834.             self.scr.addstr(y, x0, c * (x1 - x0), self.getstyle(style))
  835.         
  836.         return l
  837.  
  838.     
  839.     def _calcheaderlines(self, levels):
  840.         if levels is None:
  841.             levels = len(self.levels)
  842.         
  843.         self._headerlines = min(self.maxheaders, levels)
  844.         self._firstheaderline = levels - self._headerlines
  845.  
  846.     
  847.     def getstylehere(self, style):
  848.         return astyle.Style(style.fg, astyle.COLOR_BLUE, style.attrs | astyle.A_BOLD)
  849.  
  850.     
  851.     def report(self, msg):
  852.         self._report = msg
  853.  
  854.     
  855.     def enter(self, item, *attrs):
  856.         if self.levels and item is self.levels[-1].input:
  857.             curses.beep()
  858.             self.report(CommandError('Recursion on input object'))
  859.         else:
  860.             oldlevels = len(self.levels)
  861.             self._calcheaderlines(oldlevels + 1)
  862.             
  863.             try:
  864.                 level = _BrowserLevel(self, item, self.scrsizey - 1 - self._headerlines - 2, *attrs)
  865.             except (KeyboardInterrupt, SystemExit):
  866.                 raise 
  867.             except Exception:
  868.                 exc = None
  869.                 if not self.levels:
  870.                     raise 
  871.                 self.levels
  872.                 self._calcheaderlines(oldlevels)
  873.                 curses.beep()
  874.                 self.report(exc)
  875.  
  876.             self.levels.append(level)
  877.  
  878.     
  879.     def startkeyboardinput(self, mode):
  880.         self.mode = mode
  881.         self.prompts[mode].start()
  882.  
  883.     
  884.     def keylabel(self, keycode):
  885.         if keycode <= 255:
  886.             specialsnames = {
  887.                 ord('\n'): 'RETURN',
  888.                 ord(' '): 'SPACE',
  889.                 ord('\t'): 'TAB',
  890.                 ord('\x7f'): 'DELETE',
  891.                 ord('\x08'): 'BACKSPACE' }
  892.             if keycode in specialsnames:
  893.                 return specialsnames[keycode]
  894.             if keycode < keycode:
  895.                 pass
  896.             elif keycode < 32:
  897.                 return 'CTRL-%s' % chr(keycode + 64)
  898.             keycode in specialsnames
  899.             return repr(chr(keycode))
  900.         for name in dir(curses):
  901.             if name.startswith('KEY_') and getattr(curses, name) == keycode:
  902.                 return name
  903.         
  904.         return str(keycode)
  905.  
  906.     
  907.     def beep(self, force = False):
  908.         if force or self._dobeep:
  909.             curses.beep()
  910.             self._dobeep = False
  911.         
  912.  
  913.     
  914.     def cmd_up(self):
  915.         level = self.levels[-1]
  916.         self.report('up')
  917.         level.moveto(level.curx, level.cury - self.stepy)
  918.  
  919.     
  920.     def cmd_down(self):
  921.         level = self.levels[-1]
  922.         self.report('down')
  923.         level.moveto(level.curx, level.cury + self.stepy)
  924.  
  925.     
  926.     def cmd_pageup(self):
  927.         level = self.levels[-1]
  928.         self.report('page up')
  929.         level.moveto(level.curx, (level.cury - level.mainsizey) + self.pageoverlapy)
  930.  
  931.     
  932.     def cmd_pagedown(self):
  933.         level = self.levels[-1]
  934.         self.report('page down')
  935.         level.moveto(level.curx, level.cury + level.mainsizey - self.pageoverlapy)
  936.  
  937.     
  938.     def cmd_left(self):
  939.         level = self.levels[-1]
  940.         self.report('left')
  941.         level.moveto(level.curx - self.stepx, level.cury)
  942.  
  943.     
  944.     def cmd_right(self):
  945.         level = self.levels[-1]
  946.         self.report('right')
  947.         level.moveto(level.curx + self.stepx, level.cury)
  948.  
  949.     
  950.     def cmd_home(self):
  951.         level = self.levels[-1]
  952.         self.report('home')
  953.         level.moveto(0, level.cury)
  954.  
  955.     
  956.     def cmd_end(self):
  957.         level = self.levels[-1]
  958.         self.report('end')
  959.         level.moveto(level.datasizex + level.mainsizey - self.pageoverlapx, level.cury)
  960.  
  961.     
  962.     def cmd_prevattr(self):
  963.         level = self.levels[-1]
  964.         if level.displayattr[0] is None or level.displayattr[0] == 0:
  965.             self.beep()
  966.         else:
  967.             self.report('prevattr')
  968.             pos = 0
  969.             for i, attrname in enumerate(level.displayattrs):
  970.                 if i == level.displayattr[0] - 1:
  971.                     break
  972.                 
  973.                 pos += level.colwidths[attrname] + 1
  974.             
  975.             level.moveto(pos, level.cury)
  976.  
  977.     
  978.     def cmd_nextattr(self):
  979.         level = self.levels[-1]
  980.         if level.displayattr[0] is None or level.displayattr[0] == len(level.displayattrs) - 1:
  981.             self.beep()
  982.         else:
  983.             self.report('nextattr')
  984.             pos = 0
  985.             for i, attrname in enumerate(level.displayattrs):
  986.                 if i == level.displayattr[0] + 1:
  987.                     break
  988.                 
  989.                 pos += level.colwidths[attrname] + 1
  990.             
  991.             level.moveto(pos, level.cury)
  992.  
  993.     
  994.     def cmd_pick(self):
  995.         level = self.levels[-1]
  996.         self.returnvalue = level.items[level.cury].item
  997.         return True
  998.  
  999.     
  1000.     def cmd_pickattr(self):
  1001.         level = self.levels[-1]
  1002.         attr = level.displayattr[1]
  1003.         if attr is ipipe.noitem:
  1004.             curses.beep()
  1005.             self.report(CommandError('no column under cursor'))
  1006.             return None
  1007.         value = attr.value(level.items[level.cury].item)
  1008.         if value is ipipe.noitem:
  1009.             curses.beep()
  1010.             self.report(AttributeError(attr.name()))
  1011.         else:
  1012.             self.returnvalue = value
  1013.             return True
  1014.         return attr is ipipe.noitem
  1015.  
  1016.     
  1017.     def cmd_pickallattrs(self):
  1018.         level = self.levels[-1]
  1019.         attr = level.displayattr[1]
  1020.         if attr is ipipe.noitem:
  1021.             curses.beep()
  1022.             self.report(CommandError('no column under cursor'))
  1023.             return None
  1024.         result = []
  1025.         for cache in level.items:
  1026.             value = attr.value(cache.item)
  1027.             if value is not ipipe.noitem:
  1028.                 result.append(value)
  1029.                 continue
  1030.             attr is ipipe.noitem
  1031.         
  1032.         self.returnvalue = result
  1033.         return True
  1034.  
  1035.     
  1036.     def cmd_pickmarked(self):
  1037.         level = self.levels[-1]
  1038.         self.returnvalue = _[1]
  1039.         return True
  1040.  
  1041.     
  1042.     def cmd_pickmarkedattr(self):
  1043.         level = self.levels[-1]
  1044.         attr = level.displayattr[1]
  1045.         if attr is ipipe.noitem:
  1046.             curses.beep()
  1047.             self.report(CommandError('no column under cursor'))
  1048.             return None
  1049.         result = []
  1050.         for cache in level.items:
  1051.             if cache.marked:
  1052.                 value = attr.value(cache.item)
  1053.                 if value is not ipipe.noitem:
  1054.                     result.append(value)
  1055.                 
  1056.             value is not ipipe.noitem
  1057.         
  1058.         self.returnvalue = result
  1059.         return True
  1060.  
  1061.     
  1062.     def cmd_pickinput(self):
  1063.         level = self.levels[-1]
  1064.         value = level.items[level.cury].item
  1065.         self.returnvalue = None
  1066.         api = ipapi.get()
  1067.         api.set_next_input(str(value))
  1068.         return True
  1069.  
  1070.     
  1071.     def cmd_pickinputattr(self):
  1072.         level = self.levels[-1]
  1073.         attr = level.displayattr[1]
  1074.         if attr is ipipe.noitem:
  1075.             curses.beep()
  1076.             self.report(CommandError('no column under cursor'))
  1077.             return None
  1078.         value = attr.value(level.items[level.cury].item)
  1079.         if value is ipipe.noitem:
  1080.             curses.beep()
  1081.             self.report(AttributeError(attr.name()))
  1082.         
  1083.         self.returnvalue = None
  1084.         api = ipapi.get()
  1085.         api.set_next_input(str(value))
  1086.         return True
  1087.  
  1088.     
  1089.     def cmd_markrange(self):
  1090.         level = self.levels[-1]
  1091.         self.report('markrange')
  1092.         start = None
  1093.         if level.items:
  1094.             for i in xrange(level.cury, -1, -1):
  1095.                 if level.items[i].marked:
  1096.                     start = i
  1097.                     break
  1098.                     continue
  1099.             
  1100.         
  1101.         if start is None:
  1102.             self.report(CommandError('no mark before cursor'))
  1103.             curses.beep()
  1104.         else:
  1105.             for i in xrange(start, level.cury + 1):
  1106.                 cache = level.items[i]
  1107.                 if not cache.marked:
  1108.                     cache.marked = True
  1109.                     level.marked += 1
  1110.                     continue
  1111.                 level
  1112.             
  1113.  
  1114.     
  1115.     def cmd_enter(self):
  1116.         level = self.levels[-1]
  1117.         
  1118.         try:
  1119.             item = level.items[level.cury].item
  1120.         except IndexError:
  1121.             self.report(CommandError('No object'))
  1122.             curses.beep()
  1123.  
  1124.         self.report('entering object...')
  1125.         self.enter(item)
  1126.  
  1127.     
  1128.     def cmd_leave(self):
  1129.         self.report('leave')
  1130.         if len(self.levels) > 1:
  1131.             self._calcheaderlines(len(self.levels) - 1)
  1132.             self.levels.pop(-1)
  1133.         else:
  1134.             self.report(CommandError('This is the last level'))
  1135.             curses.beep()
  1136.  
  1137.     
  1138.     def cmd_enterattr(self):
  1139.         level = self.levels[-1]
  1140.         attr = level.displayattr[1]
  1141.         if attr is ipipe.noitem:
  1142.             curses.beep()
  1143.             self.report(CommandError('no column under cursor'))
  1144.             return None
  1145.         
  1146.         try:
  1147.             item = level.items[level.cury].item
  1148.         except IndexError:
  1149.             attr is ipipe.noitem
  1150.             attr is ipipe.noitem
  1151.             self.report(CommandError('No object'))
  1152.             curses.beep()
  1153.         except:
  1154.             attr is ipipe.noitem
  1155.  
  1156.         value = attr.value(item)
  1157.         name = attr.name()
  1158.         if value is ipipe.noitem:
  1159.             self.report(AttributeError(name))
  1160.         else:
  1161.             self.report('entering object attribute %s...' % name)
  1162.             self.enter(value)
  1163.  
  1164.     
  1165.     def cmd_detail(self):
  1166.         level = self.levels[-1]
  1167.         
  1168.         try:
  1169.             item = level.items[level.cury].item
  1170.         except IndexError:
  1171.             self.report(CommandError('No object'))
  1172.             curses.beep()
  1173.  
  1174.         self.report('entering detail view for object...')
  1175.         attrs = [ ipipe.AttributeDetail(item, attr) for attr in ipipe.xattrs(item, 'detail') ]
  1176.         self.enter(attrs)
  1177.  
  1178.     
  1179.     def cmd_detailattr(self):
  1180.         level = self.levels[-1]
  1181.         attr = level.displayattr[1]
  1182.         if attr is ipipe.noitem:
  1183.             curses.beep()
  1184.             self.report(CommandError('no attribute'))
  1185.             return None
  1186.         
  1187.         try:
  1188.             item = level.items[level.cury].item
  1189.         except IndexError:
  1190.             attr is ipipe.noitem
  1191.             attr is ipipe.noitem
  1192.             self.report(CommandError('No object'))
  1193.             curses.beep()
  1194.         except:
  1195.             attr is ipipe.noitem
  1196.  
  1197.         
  1198.         try:
  1199.             item = attr.value(item)
  1200.         except (KeyboardInterrupt, SystemExit):
  1201.             attr is ipipe.noitem
  1202.             attr is ipipe.noitem
  1203.             raise 
  1204.         except Exception:
  1205.             exc = None
  1206.             self.report(exc)
  1207.         except:
  1208.             attr is ipipe.noitem
  1209.  
  1210.         self.report('entering detail view for attribute %s...' % attr.name())
  1211.         attrs = [ ipipe.AttributeDetail(item, attr) for attr in ipipe.xattrs(item, 'detail') ]
  1212.         self.enter(attrs)
  1213.  
  1214.     
  1215.     def cmd_tooglemark(self):
  1216.         level = self.levels[-1]
  1217.         self.report('toggle mark')
  1218.         
  1219.         try:
  1220.             item = level.items[level.cury]
  1221.         except IndexError:
  1222.             pass
  1223.  
  1224.  
  1225.     
  1226.     def cmd_sortattrasc(self):
  1227.         level = self.levels[-1]
  1228.         attr = level.displayattr[1]
  1229.         if attr is ipipe.noitem:
  1230.             curses.beep()
  1231.             self.report(CommandError('no column under cursor'))
  1232.             return None
  1233.         self.report('sort by %s (ascending)' % attr.name())
  1234.         
  1235.         def key(item):
  1236.             
  1237.             try:
  1238.                 return attr.value(item)
  1239.             except (KeyboardInterrupt, SystemExit):
  1240.                 raise 
  1241.             except Exception:
  1242.                 return None
  1243.  
  1244.  
  1245.         level.sort(key)
  1246.  
  1247.     
  1248.     def cmd_sortattrdesc(self):
  1249.         level = self.levels[-1]
  1250.         attr = level.displayattr[1]
  1251.         if attr is ipipe.noitem:
  1252.             curses.beep()
  1253.             self.report(CommandError('no column under cursor'))
  1254.             return None
  1255.         self.report('sort by %s (descending)' % attr.name())
  1256.         
  1257.         def key(item):
  1258.             
  1259.             try:
  1260.                 return attr.value(item)
  1261.             except (KeyboardInterrupt, SystemExit):
  1262.                 raise 
  1263.             except Exception:
  1264.                 return None
  1265.  
  1266.  
  1267.         level.sort(key, reverse = True)
  1268.  
  1269.     
  1270.     def cmd_hideattr(self):
  1271.         level = self.levels[-1]
  1272.         if level.displayattr[0] is None:
  1273.             self.beep()
  1274.         else:
  1275.             self.report('hideattr')
  1276.             level.hiddenattrs.add(level.displayattr[1])
  1277.             level.moveto(level.curx, level.cury, refresh = True)
  1278.  
  1279.     
  1280.     def cmd_unhideattrs(self):
  1281.         level = self.levels[-1]
  1282.         self.report('unhideattrs')
  1283.         level.hiddenattrs.clear()
  1284.         level.moveto(level.curx, level.cury, refresh = True)
  1285.  
  1286.     
  1287.     def cmd_goto(self):
  1288.         self.startkeyboardinput('goto')
  1289.  
  1290.     
  1291.     def cmd_find(self):
  1292.         self.startkeyboardinput('find')
  1293.  
  1294.     
  1295.     def cmd_findbackwards(self):
  1296.         self.startkeyboardinput('findbackwards')
  1297.  
  1298.     
  1299.     def cmd_refresh(self):
  1300.         level = self.levels[-1]
  1301.         self.report('refresh')
  1302.         level.refresh()
  1303.  
  1304.     
  1305.     def cmd_refreshfind(self):
  1306.         level = self.levels[-1]
  1307.         self.report('refreshfind')
  1308.         level.refreshfind()
  1309.  
  1310.     
  1311.     def cmd_help(self):
  1312.         for level in self.levels:
  1313.             if isinstance(level.input, _BrowserHelp):
  1314.                 curses.beep()
  1315.                 self.report(CommandError('help already active'))
  1316.                 return None
  1317.         
  1318.         self.enter(_BrowserHelp(self))
  1319.  
  1320.     
  1321.     def cmd_quit(self):
  1322.         self.returnvalue = None
  1323.         return True
  1324.  
  1325.     
  1326.     def sigwinchhandler(self, signal, frame):
  1327.         self.resized = True
  1328.  
  1329.     
  1330.     def _dodisplay(self, scr):
  1331.         self.scr = scr
  1332.         curses.halfdelay(1)
  1333.         footery = 2
  1334.         keys = []
  1335.         for cmd in ('quit', 'help'):
  1336.             key = self.keymap.findkey(cmd, None)
  1337.             if key is not None:
  1338.                 keys.append('%s=%s' % (self.keylabel(key), cmd))
  1339.                 continue
  1340.         
  1341.         helpmsg = ' | %s' % ' '.join(keys)
  1342.         scr.clear()
  1343.         msg = 'Fetching first batch of objects...'
  1344.         (self.scrsizey, self.scrsizex) = scr.getmaxyx()
  1345.         scr.addstr(self.scrsizey // 2, (self.scrsizex - len(msg)) // 2, msg)
  1346.         scr.refresh()
  1347.         lastc = -1
  1348.         self.levels = []
  1349.         self.enter(self.input, *self.attrs)
  1350.         self._calcheaderlines(None)
  1351.         while True:
  1352.             level = self.levels[-1]
  1353.             (self.scrsizey, self.scrsizex) = scr.getmaxyx()
  1354.             level.mainsizey = self.scrsizey - 1 - self._headerlines - footery
  1355.             for i in xrange(self._firstheaderline, self._firstheaderline + self._headerlines):
  1356.                 lv = self.levels[i]
  1357.                 posx = 0
  1358.                 posy = i - self._firstheaderline
  1359.                 endx = self.scrsizex
  1360.                 if i:
  1361.                     msg = ' (%d/%d' % (self.levels[i - 1].cury, len(self.levels[i - 1].items))
  1362.                     if not self.levels[i - 1].exhausted:
  1363.                         msg += '+'
  1364.                     
  1365.                     msg += ') '
  1366.                     endx -= len(msg) + 1
  1367.                 
  1368.                 posx += self.addstr(posy, posx, 0, endx, ' ibrowse #%d: ' % i, self.style_objheadertext)
  1369.                 for style, text in lv.header:
  1370.                     posx += self.addstr(posy, posx, 0, endx, text, self.style_objheaderobject)
  1371.                     if posx >= endx:
  1372.                         break
  1373.                         continue
  1374.                 
  1375.                 if i:
  1376.                     posx += self.addstr(posy, posx, 0, self.scrsizex, msg, self.style_objheadernumber)
  1377.                 
  1378.                 posx += self.addchr(posy, posx, 0, self.scrsizex, ' ', self.scrsizex - posx, self.style_objheadernumber)
  1379.             
  1380.             if not level.items:
  1381.                 self.addchr(self._headerlines, 0, 0, self.scrsizex, ' ', self.scrsizex, self.style_colheader)
  1382.                 self.addstr(self._headerlines + 1, 0, 0, self.scrsizex, ' <empty>', astyle.style_error)
  1383.                 scr.clrtobot()
  1384.             else:
  1385.                 scr.move(self._headerlines, 0)
  1386.                 scr.addstr(' %*s ' % (level.numbersizex, '#'), self.getstyle(self.style_colheader))
  1387.                 scr.addstr(self.headersepchar, self.getstyle(self.style_colheadersep))
  1388.                 begx = level.numbersizex + 3
  1389.                 posx = begx - level.datastartx
  1390.                 for attr in level.displayattrs:
  1391.                     attrname = attr.name()
  1392.                     cwidth = level.colwidths[attr]
  1393.                     header = attrname.ljust(cwidth)
  1394.                     if attr is level.displayattr[1]:
  1395.                         style = self.style_colheaderhere
  1396.                     else:
  1397.                         style = self.style_colheader
  1398.                     posx += self.addstr(self._headerlines, posx, begx, self.scrsizex, header, style)
  1399.                     posx += self.addstr(self._headerlines, posx, begx, self.scrsizex, self.headersepchar, self.style_colheadersep)
  1400.                     if posx >= self.scrsizex:
  1401.                         break
  1402.                         continue
  1403.                 
  1404.                 posy = self._headerlines + 1 + level.datastarty
  1405.                 for i in xrange(level.datastarty, min(level.datastarty + level.mainsizey, len(level.items))):
  1406.                     cache = level.items[i]
  1407.                     if i == level.cury:
  1408.                         style = self.style_numberhere
  1409.                     else:
  1410.                         style = self.style_number
  1411.                     posy = self._headerlines + 1 + i - level.datastarty
  1412.                     posx = begx - level.datastartx
  1413.                     scr.move(posy, 0)
  1414.                     scr.addstr(' %*d%s' % (level.numbersizex, i, ' !'[cache.marked]), self.getstyle(style))
  1415.                     scr.addstr(self.headersepchar, self.getstyle(self.style_sep))
  1416.                     for attrname in level.displayattrs:
  1417.                         cwidth = level.colwidths[attrname]
  1418.                         
  1419.                         try:
  1420.                             (align, length, parts) = level.displayrows[i - level.datastarty][attrname]
  1421.                         except KeyError:
  1422.                             align = 2
  1423.                             style = astyle.style_nodata
  1424.                             if i == level.cury:
  1425.                                 style = self.getstylehere(style)
  1426.                             
  1427.                         except:
  1428.                             i == level.cury
  1429.  
  1430.                         padstyle = self.style_datapad
  1431.                         sepstyle = self.style_sep
  1432.                         if i == level.cury:
  1433.                             padstyle = self.getstylehere(padstyle)
  1434.                             sepstyle = self.getstylehere(sepstyle)
  1435.                         
  1436.                         if align == 2:
  1437.                             posx += self.addchr(posy, posx, begx, self.scrsizex, self.nodatachar, cwidth, style)
  1438.                         elif align == 1:
  1439.                             posx += self.addchr(posy, posx, begx, self.scrsizex, self.datapadchar, cwidth - length, padstyle)
  1440.                         elif align == 0:
  1441.                             pad1 = (cwidth - length) // 2
  1442.                             pad2 = cwidth - length - len(pad1)
  1443.                             posx += self.addchr(posy, posx, begx, self.scrsizex, self.datapadchar, pad1, padstyle)
  1444.                         
  1445.                         for style, text in parts:
  1446.                             if i == level.cury:
  1447.                                 style = self.getstylehere(style)
  1448.                             
  1449.                             posx += self.addstr(posy, posx, begx, self.scrsizex, text, style)
  1450.                             if posx >= self.scrsizex:
  1451.                                 break
  1452.                                 continue
  1453.                         
  1454.                         if align == -1:
  1455.                             posx += self.addchr(posy, posx, begx, self.scrsizex, self.datapadchar, cwidth - length, padstyle)
  1456.                         elif align == 0:
  1457.                             posx += self.addchr(posy, posx, begx, self.scrsizex, self.datapadchar, pad2, padstyle)
  1458.                         
  1459.                         posx += self.addstr(posy, posx, begx, self.scrsizex, self.datasepchar, sepstyle)
  1460.                     
  1461.                 
  1462.                 for posy in xrange(posy + 1, self.scrsizey - 2):
  1463.                     scr.addstr(posy, 0, ' ' * (level.numbersizex + 2), self.getstyle(self.style_colheader))
  1464.                     scr.clrtoeol()
  1465.                 
  1466.             posy = self.scrsizey - footery
  1467.             scr.addstr(posy, 0, ' ' * self.scrsizex, self.getstyle(self.style_footer))
  1468.             if level.exhausted:
  1469.                 flag = ''
  1470.             else:
  1471.                 flag = '+'
  1472.             endx = self.scrsizex - len(helpmsg) - 1
  1473.             scr.addstr(posy, endx, helpmsg, self.getstyle(self.style_footer))
  1474.             posx = 0
  1475.             msg = ' %d%s objects (%d marked): ' % (len(level.items), flag, level.marked)
  1476.             posx += self.addstr(posy, posx, 0, endx, msg, self.style_footer)
  1477.             
  1478.             try:
  1479.                 item = level.items[level.cury].item
  1480.             except IndexError:
  1481.                 pass
  1482.  
  1483.             for nostyle, text in ipipe.xrepr(item, 'footer'):
  1484.                 if not isinstance(nostyle, int):
  1485.                     posx += self.addstr(posy, posx, 0, endx, text, self.style_footer)
  1486.                     if posx >= endx:
  1487.                         break
  1488.                     
  1489.                 posx >= endx
  1490.             
  1491.             attrstyle = [
  1492.                 (astyle.style_default, 'no attribute')]
  1493.             attr = level.displayattr[1]
  1494.             if attr is not ipipe.noitem and not isinstance(attr, ipipe.SelfDescriptor):
  1495.                 posx += self.addstr(posy, posx, 0, endx, ' | ', self.style_footer)
  1496.                 posx += self.addstr(posy, posx, 0, endx, attr.name(), self.style_footer)
  1497.                 posx += self.addstr(posy, posx, 0, endx, ': ', self.style_footer)
  1498.                 
  1499.                 try:
  1500.                     value = attr.value(item)
  1501.                 except (SystemExit, KeyboardInterrupt):
  1502.                     raise 
  1503.                 except Exception:
  1504.                     exc = None
  1505.                     value = exc
  1506.  
  1507.                 if value is not ipipe.noitem:
  1508.                     attrstyle = ipipe.xrepr(value, 'footer')
  1509.                 
  1510.                 for nostyle, text in attrstyle:
  1511.                     if not isinstance(nostyle, int):
  1512.                         posx += self.addstr(posy, posx, 0, endx, text, self.style_footer)
  1513.                         if posx >= endx:
  1514.                             break
  1515.                         
  1516.                     posx >= endx
  1517.                 
  1518.             
  1519.             
  1520.             try:
  1521.                 if self.mode in self.prompts:
  1522.                     history = self.prompts[self.mode]
  1523.                     posx = 0
  1524.                     posy = self.scrsizey - 1
  1525.                     posx += self.addstr(posy, posx, 0, endx, history.prompt, astyle.style_default)
  1526.                     posx += self.addstr(posy, posx, 0, endx, ' [', astyle.style_default)
  1527.                     if history.cury == -1:
  1528.                         text = 'new'
  1529.                     else:
  1530.                         text = str(history.cury + 1)
  1531.                     posx += self.addstr(posy, posx, 0, endx, text, astyle.style_type_number)
  1532.                     if history.history:
  1533.                         posx += self.addstr(posy, posx, 0, endx, '/', astyle.style_default)
  1534.                         posx += self.addstr(posy, posx, 0, endx, str(len(history.history)), astyle.style_type_number)
  1535.                     
  1536.                     posx += self.addstr(posy, posx, 0, endx, ']: ', astyle.style_default)
  1537.                     inputstartx = posx
  1538.                     posx += self.addstr(posy, posx, 0, endx, history.input, astyle.style_default)
  1539.                 elif self._report is not None:
  1540.                     if isinstance(self._report, Exception):
  1541.                         style = self.getstyle(astyle.style_error)
  1542.                         if self._report.__class__.__module__ == 'exceptions':
  1543.                             msg = '%s: %s' % (self._report.__class__.__name__, self._report)
  1544.                         else:
  1545.                             msg = '%s.%s: %s' % (self._report.__class__.__module__, self._report.__class__.__name__, self._report)
  1546.                     else:
  1547.                         style = self.getstyle(self.style_report)
  1548.                         msg = self._report
  1549.                     scr.addstr(self.scrsizey - 1, 0, msg[:self.scrsizex], style)
  1550.                     self._report = None
  1551.                 else:
  1552.                     scr.move(self.scrsizey - 1, 0)
  1553.             except curses.error:
  1554.                 pass
  1555.  
  1556.             scr.clrtoeol()
  1557.             if self.mode in self.prompts:
  1558.                 history = self.prompts[self.mode]
  1559.                 scr.move(self.scrsizey - 1, inputstartx + history.curx)
  1560.             else:
  1561.                 scr.move(1 + self._headerlines + level.cury - level.datastarty, level.numbersizex + 3 + level.curx - level.datastartx)
  1562.             scr.refresh()
  1563.             while True:
  1564.                 c = scr.getch()
  1565.                 if self.resized:
  1566.                     size = fcntl.ioctl(0, tty.TIOCGWINSZ, '12345678')
  1567.                     size = struct.unpack('4H', size)
  1568.                     oldsize = scr.getmaxyx()
  1569.                     scr.erase()
  1570.                     curses.resize_term(size[0], size[1])
  1571.                     newsize = scr.getmaxyx()
  1572.                     scr.erase()
  1573.                     for l in self.levels:
  1574.                         l.mainsizey += newsize[0] - oldsize[0]
  1575.                         l.moveto(l.curx, l.cury, refresh = True)
  1576.                     
  1577.                     scr.refresh()
  1578.                     self.resized = False
  1579.                     break
  1580.                 
  1581.                 if self.mode in self.prompts:
  1582.                     if self.prompts[self.mode].handlekey(self, c):
  1583.                         break
  1584.                     
  1585.                 self.prompts[self.mode].handlekey(self, c)
  1586.                 if c == -1:
  1587.                     self.stepx = 1
  1588.                     self.stepy = 1
  1589.                     self._dobeep = True
  1590.                     continue
  1591.                 if c != lastc:
  1592.                     lastc = c
  1593.                     self.stepx = 1
  1594.                     self.stepy = 1
  1595.                     self._dobeep = True
  1596.                 
  1597.                 cmdname = self.keymap.get(c, None)
  1598.                 if cmdname is None:
  1599.                     self.report(UnassignedKeyError('Unassigned key %s' % self.keylabel(c)))
  1600.                 else:
  1601.                     cmdfunc = getattr(self, 'cmd_%s' % cmdname, None)
  1602.                     if cmdfunc is None:
  1603.                         self.report(UnknownCommandError('Unknown command %r' % (cmdname,)))
  1604.                     elif cmdfunc():
  1605.                         returnvalue = self.returnvalue
  1606.                         self.returnvalue = None
  1607.                         return returnvalue
  1608.                 self.stepx = self.nextstepx(self.stepx)
  1609.                 self.stepy = self.nextstepy(self.stepy)
  1610.                 curses.flushinp()
  1611.                 break
  1612.         self.scr = None
  1613.  
  1614.     
  1615.     def display(self):
  1616.         if hasattr(curses, 'resize_term'):
  1617.             oldhandler = signal.signal(signal.SIGWINCH, self.sigwinchhandler)
  1618.             
  1619.             try:
  1620.                 return curses.wrapper(self._dodisplay)
  1621.             finally:
  1622.                 signal.signal(signal.SIGWINCH, oldhandler)
  1623.  
  1624.         else:
  1625.             return curses.wrapper(self._dodisplay)
  1626.         return hasattr(curses, 'resize_term')
  1627.  
  1628.  
  1629.