##// END OF EJS Templates
Merging upstread changes from trunk.
Merging upstread changes from trunk.

File last commit:

r2079:3b6b0915
r2241:078115b9 merge
Show More
ibrowse.py
1767 lines | 62.0 KiB | text/x-python | PythonLexer
walter.doerwald
Move ibrowse into a separate module.
r272 # -*- coding: iso-8859-1 -*-
walter.doerwald
Put the documentation of the keyboard commands into the...
r340 import curses, fcntl, signal, struct, tty, textwrap, inspect
walter.doerwald
Move ibrowse into a separate module.
r272
Brian Granger
Refactored iptest.py to work with new package org....
r2079 from IPython.core import ipapi
walter.doerwald
IPython/Extensions/ipipe.py: Added a Table ihist that can be used to...
r683
walter.doerwald
Move ibrowse into a separate module.
r272 import astyle, ipipe
walter.doerwald
Add two new commands to ibrowse: hideattr (mapped to "h")...
r332 # Python 2.3 compatibility
try:
set
except NameError:
import sets
set = sets.Set
walter.doerwald
IPython/Extensions/ipipe.py: xrepr(), xiter() and xattrs() are now...
r415 # Python 2.3 compatibility
try:
sorted
except NameError:
from ipipe import sorted
walter.doerwald
Add two new commands to ibrowse: hideattr (mapped to "h")...
r332
walter.doerwald
Move ibrowse into a separate module.
r272 class UnassignedKeyError(Exception):
"""
Exception that is used for reporting unassigned keys.
"""
class UnknownCommandError(Exception):
"""
walter.doerwald
IPython/Extensions/ipipe.py: xrepr(), xiter() and xattrs() are now...
r415 Exception that is used for reporting unknown commands (this should never
walter.doerwald
Move ibrowse into a separate module.
r272 happen).
"""
class CommandError(Exception):
"""
Exception that is used for reporting that a command can't be executed.
"""
walter.doerwald
Replace the plain dictionaries used for keymaps with a custom class...
r338 class Keymap(dict):
"""
Stores mapping of keys to commands.
"""
def __init__(self):
self._keymap = {}
def __setitem__(self, key, command):
if isinstance(key, str):
for c in key:
dict.__setitem__(self, ord(c), command)
else:
dict.__setitem__(self, key, command)
def __getitem__(self, key):
if isinstance(key, str):
key = ord(key)
return dict.__getitem__(self, key)
walter.doerwald
Add a __delitem__() method to Keymap.
r341 def __detitem__(self, key):
if isinstance(key, str):
key = ord(key)
dict.__detitem__(self, key)
def register(self, command, *keys):
for key in keys:
self[key] = command
walter.doerwald
Replace the plain dictionaries used for keymaps with a custom class...
r338 def get(self, key, default=None):
if isinstance(key, str):
key = ord(key)
return dict.get(self, key, default)
def findkey(self, command, default=ipipe.noitem):
for (key, commandcandidate) in self.iteritems():
if commandcandidate == command:
return key
if default is ipipe.noitem:
raise KeyError(command)
return default
walter.doerwald
Move ibrowse into a separate module.
r272 class _BrowserCachedItem(object):
# This is used internally by ``ibrowse`` to store a item together with its
# marked status.
__slots__ = ("item", "marked")
def __init__(self, item):
self.item = item
self.marked = False
class _BrowserHelp(object):
walter.doerwald
Give the ibrowse cursor row a blue background....
r346 style_header = astyle.Style.fromstr("yellow:black:bold")
walter.doerwald
Move ibrowse into a separate module.
r272 # This is used internally by ``ibrowse`` for displaying the help screen.
def __init__(self, browser):
self.browser = browser
def __xrepr__(self, mode):
yield (-1, True)
if mode == "header" or mode == "footer":
yield (astyle.style_default, "ibrowse help screen")
else:
yield (astyle.style_default, repr(self))
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 def __iter__(self):
walter.doerwald
Move ibrowse into a separate module.
r272 # Get reverse key mapping
allkeys = {}
for (key, cmd) in self.browser.keymap.iteritems():
allkeys.setdefault(cmd, []).append(key)
fields = ("key", "description")
walter.doerwald
Put the documentation of the keyboard commands into the...
r340 commands = []
for name in dir(self.browser):
if name.startswith("cmd_"):
command = getattr(self.browser, name)
commands.append((inspect.getsourcelines(command)[-1], name[4:], command))
commands.sort()
commands = [(c[1], c[2]) for c in commands]
for (i, (name, command)) in enumerate(commands):
walter.doerwald
Move ibrowse into a separate module.
r272 if i:
walter.doerwald
Move textwrap import to where it's needed....
r278 yield ipipe.Fields(fields, key="", description="")
walter.doerwald
Move ibrowse into a separate module.
r272
walter.doerwald
Put the documentation of the keyboard commands into the...
r340 description = command.__doc__
if description is None:
lines = []
else:
lines = [l.strip() for l in description.splitlines() if l.strip()]
description = "\n".join(lines)
lines = textwrap.wrap(description, 60)
walter.doerwald
Move ibrowse into a separate module.
r272 keys = allkeys.get(name, [])
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 yield ipipe.Fields(fields, key="", description=astyle.Text((self.style_header, name)))
walter.doerwald
Move ibrowse into a separate module.
r272 for i in xrange(max(len(keys), len(lines))):
try:
key = self.browser.keylabel(keys[i])
except IndexError:
key = ""
try:
line = lines[i]
except IndexError:
line = ""
walter.doerwald
Move textwrap import to where it's needed....
r278 yield ipipe.Fields(fields, key=key, description=line)
walter.doerwald
Move ibrowse into a separate module.
r272
class _BrowserLevel(object):
# This is used internally to store the state (iterator, fetch items,
# position of cursor and screen, etc.) of one browser level
# An ``ibrowse`` object keeps multiple ``_BrowserLevel`` objects in
# a stack.
walter.doerwald
IPython/Extensions/ipipe.py (xiter): Make sure that iterating...
r513 def __init__(self, browser, input, mainsizey, *attrs):
walter.doerwald
Move ibrowse into a separate module.
r272 self.browser = browser
self.input = input
self.header = [x for x in ipipe.xrepr(input, "header") if not isinstance(x[0], int)]
# iterator for the input
walter.doerwald
Add two new commands to ibrowse:...
r471 self.iterator = ipipe.xiter(input)
walter.doerwald
Move ibrowse into a separate module.
r272
# is the iterator exhausted?
self.exhausted = False
# attributes to be display (autodetected if empty)
self.attrs = attrs
# fetched items (+ marked flag)
self.items = ipipe.deque()
# Number of marked objects
self.marked = 0
# Vertical cursor position
self.cury = 0
# Horizontal cursor position
self.curx = 0
# Index of first data column
self.datastartx = 0
# Index of first data line
self.datastarty = 0
# height of the data display area
self.mainsizey = mainsizey
# width of the data display area (changes when scrolling)
self.mainsizex = 0
# Size of row number (changes when scrolling)
self.numbersizex = 0
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 # Attributes to display (in this order)
walter.doerwald
Move ibrowse into a separate module.
r272 self.displayattrs = []
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 # index and attribute under the cursor
walter.doerwald
Rename ipipe._default to ipipe.noitem (which makes...
r274 self.displayattr = (None, ipipe.noitem)
walter.doerwald
Move ibrowse into a separate module.
r272
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 # Maps attributes to column widths
walter.doerwald
Move ibrowse into a separate module.
r272 self.colwidths = {}
walter.doerwald
Add two new commands to ibrowse: hideattr (mapped to "h")...
r332 # Set of hidden attributes
self.hiddenattrs = set()
walter.doerwald
Change _BrowserLevel.moveto() so that the call to fetch() always tries to...
r329 # This takes care of all the caches etc.
self.moveto(0, 0, refresh=True)
walter.doerwald
Move ibrowse into a separate module.
r272
def fetch(self, count):
# Try to fill ``self.items`` with at least ``count`` objects.
have = len(self.items)
while not self.exhausted and have < count:
try:
item = self.iterator.next()
except StopIteration:
self.exhausted = True
break
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 except (KeyboardInterrupt, SystemExit):
raise
except Exception, exc:
have += 1
self.items.append(_BrowserCachedItem(exc))
self.exhausted = True
break
walter.doerwald
Move ibrowse into a separate module.
r272 else:
have += 1
self.items.append(_BrowserCachedItem(item))
def calcdisplayattrs(self):
# Calculate which attributes are available from the objects that are
# currently visible on screen (and store it in ``self.displayattrs``)
walter.doerwald
Add two new commands to ibrowse: hideattr (mapped to "h")...
r332
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 attrs = set()
walter.doerwald
Add two new commands to ibrowse: hideattr (mapped to "h")...
r332 self.displayattrs = []
walter.doerwald
Move ibrowse into a separate module.
r272 if self.attrs:
walter.doerwald
Add two new commands to ibrowse: hideattr (mapped to "h")...
r332 # If the browser object specifies a fixed list of attributes,
# simply use it (removing hidden attributes).
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 for attr in self.attrs:
attr = ipipe.upgradexattr(attr)
if attr not in attrs and attr not in self.hiddenattrs:
self.displayattrs.append(attr)
attrs.add(attr)
walter.doerwald
Move ibrowse into a separate module.
r272 else:
endy = min(self.datastarty+self.mainsizey, len(self.items))
for i in xrange(self.datastarty, endy):
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 for attr in ipipe.xattrs(self.items[i].item, "default"):
if attr not in attrs and attr not in self.hiddenattrs:
self.displayattrs.append(attr)
attrs.add(attr)
walter.doerwald
Move ibrowse into a separate module.
r272
def getrow(self, i):
walter.doerwald
Fix docstrings.
r364 # Return a dictionary with the attributes for the object
walter.doerwald
Move ibrowse into a separate module.
r272 # ``self.items[i]``. Attribute names are taken from
# ``self.displayattrs`` so ``calcdisplayattrs()`` must have been
# called before.
row = {}
item = self.items[i].item
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 for attr in self.displayattrs:
walter.doerwald
Move ibrowse into a separate module.
r272 try:
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 value = attr.value(item)
walter.doerwald
Move ibrowse into a separate module.
r272 except (KeyboardInterrupt, SystemExit):
raise
except Exception, exc:
value = exc
# only store attribute if it exists (or we got an exception)
walter.doerwald
Rename ipipe._default to ipipe.noitem (which makes...
r274 if value is not ipipe.noitem:
walter.doerwald
Only use alignment specification if it's the first...
r282 # remember alignment, length and colored text
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 row[attr] = ipipe.xformat(value, "cell", self.browser.maxattrlength)
walter.doerwald
Move ibrowse into a separate module.
r272 return row
def calcwidths(self):
walter.doerwald
Change _BrowserLevel.moveto() so that the call to fetch() always tries to...
r329 # Recalculate the displayed fields and their widths.
walter.doerwald
Move ibrowse into a separate module.
r272 # ``calcdisplayattrs()'' must have been called and the cache
# for attributes of the objects on screen (``self.displayrows``)
walter.doerwald
Fix docstrings.
r364 # must have been filled. This sets ``self.colwidths`` which maps
# attribute descriptors to widths.
walter.doerwald
Move ibrowse into a separate module.
r272 self.colwidths = {}
for row in self.displayrows:
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 for attr in self.displayattrs:
walter.doerwald
Move ibrowse into a separate module.
r272 try:
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 length = row[attr][1]
walter.doerwald
Move ibrowse into a separate module.
r272 except KeyError:
length = 0
# always add attribute to colwidths, even if it doesn't exist
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 if attr not in self.colwidths:
self.colwidths[attr] = len(attr.name())
newwidth = max(self.colwidths[attr], length)
self.colwidths[attr] = newwidth
walter.doerwald
Move ibrowse into a separate module.
r272
walter.doerwald
Change _BrowserLevel.moveto() so that the call to fetch() always tries to...
r329 # How many characters do we need to paint the largest item number?
walter.doerwald
Move ibrowse into a separate module.
r272 self.numbersizex = len(str(self.datastarty+self.mainsizey-1))
# How must space have we got to display data?
self.mainsizex = self.browser.scrsizex-self.numbersizex-3
# width of all columns
self.datasizex = sum(self.colwidths.itervalues()) + len(self.colwidths)
def calcdisplayattr(self):
walter.doerwald
Change _BrowserLevel.moveto() so that the call to fetch() always tries to...
r329 # Find out which attribute the cursor is on and store this
walter.doerwald
Move ibrowse into a separate module.
r272 # information in ``self.displayattr``.
pos = 0
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 for (i, attr) in enumerate(self.displayattrs):
if pos+self.colwidths[attr] >= self.curx:
self.displayattr = (i, attr)
walter.doerwald
Move ibrowse into a separate module.
r272 break
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 pos += self.colwidths[attr]+1
walter.doerwald
Move ibrowse into a separate module.
r272 else:
walter.doerwald
Rename ipipe._default to ipipe.noitem (which makes...
r274 self.displayattr = (None, ipipe.noitem)
walter.doerwald
Move ibrowse into a separate module.
r272
def moveto(self, x, y, refresh=False):
# Move the cursor to the position ``(x,y)`` (in data coordinates,
# not in screen coordinates). If ``refresh`` is true, all cached
# values will be recalculated (e.g. because the list has been
# resorted, so screen positions etc. are no longer valid).
olddatastarty = self.datastarty
oldx = self.curx
oldy = self.cury
x = int(x+0.5)
y = int(y+0.5)
newx = x # remember where we wanted to move
newy = y # remember where we wanted to move
scrollbordery = min(self.browser.scrollbordery, self.mainsizey//2)
scrollborderx = min(self.browser.scrollborderx, self.mainsizex//2)
# Make sure that the cursor didn't leave the main area vertically
if y < 0:
y = 0
walter.doerwald
Change _BrowserLevel.moveto() so that the call to fetch() always tries to...
r329 # try to get enough items to fill the screen
self.fetch(max(y+scrollbordery+1, self.mainsizey))
walter.doerwald
Move ibrowse into a separate module.
r272 if y >= len(self.items):
y = max(0, len(self.items)-1)
# Make sure that the cursor stays on screen vertically
if y < self.datastarty+scrollbordery:
self.datastarty = max(0, y-scrollbordery)
elif y >= self.datastarty+self.mainsizey-scrollbordery:
self.datastarty = max(0, min(y-self.mainsizey+scrollbordery+1,
len(self.items)-self.mainsizey))
if refresh: # Do we need to refresh the complete display?
self.calcdisplayattrs()
endy = min(self.datastarty+self.mainsizey, len(self.items))
self.displayrows = map(self.getrow, xrange(self.datastarty, endy))
self.calcwidths()
# Did we scroll vertically => update displayrows
# and various other attributes
elif self.datastarty != olddatastarty:
# Recalculate which attributes we have to display
olddisplayattrs = self.displayattrs
self.calcdisplayattrs()
# If there are new attributes, recreate the cache
if self.displayattrs != olddisplayattrs:
endy = min(self.datastarty+self.mainsizey, len(self.items))
self.displayrows = map(self.getrow, xrange(self.datastarty, endy))
elif self.datastarty<olddatastarty: # we did scroll up
# drop rows from the end
del self.displayrows[self.datastarty-olddatastarty:]
# fetch new items
walter.doerwald
Give the ibrowse cursor row a blue background....
r346 for i in xrange(min(olddatastarty, self.datastarty+self.mainsizey)-1,
walter.doerwald
Move ibrowse into a separate module.
r272 self.datastarty-1, -1):
try:
row = self.getrow(i)
except IndexError:
# we didn't have enough objects to fill the screen
break
self.displayrows.insert(0, row)
else: # we did scroll down
# drop rows from the start
del self.displayrows[:self.datastarty-olddatastarty]
# fetch new items
walter.doerwald
Give the ibrowse cursor row a blue background....
r346 for i in xrange(max(olddatastarty+self.mainsizey, self.datastarty),
walter.doerwald
Move ibrowse into a separate module.
r272 self.datastarty+self.mainsizey):
try:
row = self.getrow(i)
except IndexError:
# we didn't have enough objects to fill the screen
break
self.displayrows.append(row)
self.calcwidths()
# Make sure that the cursor didn't leave the data area horizontally
if x < 0:
x = 0
elif x >= self.datasizex:
x = max(0, self.datasizex-1)
# Make sure that the cursor stays on screen horizontally
if x < self.datastartx+scrollborderx:
self.datastartx = max(0, x-scrollborderx)
elif x >= self.datastartx+self.mainsizex-scrollborderx:
self.datastartx = max(0, min(x-self.mainsizex+scrollborderx+1,
self.datasizex-self.mainsizex))
if x == oldx and y == oldy and (x != newx or y != newy): # couldn't move
self.browser.beep()
else:
self.curx = x
self.cury = y
self.calcdisplayattr()
def sort(self, key, reverse=False):
"""
Sort the currently list of items using the key function ``key``. If
``reverse`` is true the sort order is reversed.
"""
curitem = self.items[self.cury] # Remember where the cursor is now
# Sort items
def realkey(item):
return key(item.item)
self.items = ipipe.deque(sorted(self.items, key=realkey, reverse=reverse))
# Find out where the object under the cursor went
cury = self.cury
for (i, item) in enumerate(self.items):
if item is curitem:
cury = i
break
self.moveto(self.curx, cury, refresh=True)
walter.doerwald
Add two new commands to ibrowse:...
r471 def refresh(self):
"""
Restart iterating the input.
"""
self.iterator = ipipe.xiter(self.input)
self.items.clear()
self.exhausted = False
walter.doerwald
Reset scroll position when refreshing.
r474 self.datastartx = self.datastarty = 0
walter.doerwald
Add two new commands to ibrowse:...
r471 self.moveto(0, 0, refresh=True)
def refreshfind(self):
"""
Restart iterating the input and go back to the same object as before
(if it can be found in the new iterator).
"""
try:
oldobject = self.items[self.cury].item
except IndexError:
oldobject = ipipe.noitem
self.iterator = ipipe.xiter(self.input)
self.items.clear()
self.exhausted = False
while True:
self.fetch(len(self.items)+1)
if self.exhausted:
curses.beep()
walter.doerwald
Reset scroll position when refreshing.
r474 self.datastartx = self.datastarty = 0
walter.doerwald
Enhance cmd_refreshfind docstring....
r473 self.moveto(self.curx, 0, refresh=True)
walter.doerwald
Add two new commands to ibrowse:...
r471 break
if self.items[-1].item == oldobject:
walter.doerwald
Reset scroll position when refreshing.
r474 self.datastartx = self.datastarty = 0
walter.doerwald
Add two new commands to ibrowse:...
r471 self.moveto(self.curx, len(self.items)-1, refresh=True)
break
walter.doerwald
Move ibrowse into a separate module.
r272
walter.doerwald
Add a class _CommandInput that implements the basic functionality of...
r326 class _CommandInput(object):
walter.doerwald
Replace the plain dictionaries used for keymaps with a custom class...
r338 keymap = Keymap()
keymap.register("left", curses.KEY_LEFT)
keymap.register("right", curses.KEY_RIGHT)
keymap.register("home", curses.KEY_HOME, "\x01") # Ctrl-A
keymap.register("end", curses.KEY_END, "\x05") # Ctrl-E
# FIXME: What's happening here?
walter.doerwald
Remove "x" as a backspace key in _CommandInput..
r343 keymap.register("backspace", curses.KEY_BACKSPACE, "\x08\x7f")
walter.doerwald
Replace the plain dictionaries used for keymaps with a custom class...
r338 keymap.register("delete", curses.KEY_DC)
keymap.register("delend", 0x0b) # Ctrl-K
keymap.register("execute", "\r\n")
keymap.register("up", curses.KEY_UP)
keymap.register("down", curses.KEY_DOWN)
keymap.register("incsearchup", curses.KEY_PPAGE)
keymap.register("incsearchdown", curses.KEY_NPAGE)
keymap.register("exit", "\x18"), # Ctrl-X
walter.doerwald
Add a class _CommandInput that implements the basic functionality of...
r326
def __init__(self, prompt):
self.prompt = prompt
self.history = []
self.maxhistory = 100
self.input = ""
self.curx = 0
self.cury = -1 # blank line
def start(self):
self.input = ""
self.curx = 0
self.cury = -1 # blank line
def handlekey(self, browser, key):
cmdname = self.keymap.get(key, None)
if cmdname is not None:
cmdfunc = getattr(self, "cmd_%s" % cmdname, None)
if cmdfunc is not None:
return cmdfunc(browser)
curses.beep()
elif key != -1:
try:
char = chr(key)
except ValueError:
curses.beep()
else:
return self.handlechar(browser, char)
def handlechar(self, browser, char):
self.input = self.input[:self.curx] + char + self.input[self.curx:]
self.curx += 1
return True
def dohistory(self):
self.history.insert(0, self.input)
del self.history[:-self.maxhistory]
def cmd_backspace(self, browser):
if self.curx:
self.input = self.input[:self.curx-1] + self.input[self.curx:]
self.curx -= 1
return True
else:
curses.beep()
def cmd_delete(self, browser):
if self.curx<len(self.input):
self.input = self.input[:self.curx] + self.input[self.curx+1:]
return True
else:
curses.beep()
walter.doerwald
Add three new commands to the input mode for "find" and friends:...
r335 def cmd_delend(self, browser):
if self.curx<len(self.input):
self.input = self.input[:self.curx]
return True
walter.doerwald
Add a class _CommandInput that implements the basic functionality of...
r326 def cmd_left(self, browser):
if self.curx:
self.curx -= 1
return True
else:
curses.beep()
def cmd_right(self, browser):
if self.curx < len(self.input):
self.curx += 1
return True
else:
curses.beep()
def cmd_home(self, browser):
if self.curx:
self.curx = 0
return True
else:
curses.beep()
def cmd_end(self, browser):
if self.curx < len(self.input):
self.curx = len(self.input)
return True
else:
curses.beep()
def cmd_up(self, browser):
if self.cury < len(self.history)-1:
self.cury += 1
self.input = self.history[self.cury]
self.curx = len(self.input)
return True
else:
curses.beep()
def cmd_down(self, browser):
if self.cury >= 0:
self.cury -= 1
if self.cury>=0:
self.input = self.history[self.cury]
else:
self.input = ""
self.curx = len(self.input)
return True
else:
curses.beep()
walter.doerwald
Add three new commands to the input mode for "find" and friends:...
r335 def cmd_incsearchup(self, browser):
prefix = self.input[:self.curx]
cury = self.cury
while True:
cury += 1
if cury >= len(self.history):
break
if self.history[cury].startswith(prefix):
self.input = self.history[cury]
self.cury = cury
return True
curses.beep()
def cmd_incsearchdown(self, browser):
prefix = self.input[:self.curx]
cury = self.cury
while True:
cury -= 1
if cury <= 0:
break
if self.history[cury].startswith(prefix):
self.input = self.history[self.cury]
self.cury = cury
return True
curses.beep()
walter.doerwald
Add a class _CommandInput that implements the basic functionality of...
r326 def cmd_exit(self, browser):
browser.mode = "default"
return True
def cmd_execute(self, browser):
raise NotImplementedError
class _CommandGoto(_CommandInput):
def __init__(self):
_CommandInput.__init__(self, "goto object #")
def handlechar(self, browser, char):
# Only accept digits
if not "0" <= char <= "9":
curses.beep()
else:
return _CommandInput.handlechar(self, browser, char)
def cmd_execute(self, browser):
level = browser.levels[-1]
if self.input:
self.dohistory()
level.moveto(level.curx, int(self.input))
browser.mode = "default"
return True
class _CommandFind(_CommandInput):
def __init__(self):
_CommandInput.__init__(self, "find expression")
def cmd_execute(self, browser):
level = browser.levels[-1]
if self.input:
self.dohistory()
while True:
cury = level.cury
level.moveto(level.curx, cury+1)
if cury == level.cury:
curses.beep()
break # hit end
item = level.items[level.cury].item
try:
globals = ipipe.getglobals(None)
if eval(self.input, globals, ipipe.AttrNamespace(item)):
break # found something
except (KeyboardInterrupt, SystemExit):
raise
except Exception, exc:
browser.report(exc)
curses.beep()
break # break on error
browser.mode = "default"
return True
class _CommandFindBackwards(_CommandInput):
def __init__(self):
_CommandInput.__init__(self, "find backwards expression")
def cmd_execute(self, browser):
level = browser.levels[-1]
if self.input:
self.dohistory()
while level.cury:
level.moveto(level.curx, level.cury-1)
item = level.items[level.cury].item
try:
globals = ipipe.getglobals(None)
if eval(self.input, globals, ipipe.AttrNamespace(item)):
break # found something
except (KeyboardInterrupt, SystemExit):
raise
except Exception, exc:
browser.report(exc)
curses.beep()
break # break on error
else:
curses.beep()
browser.mode = "default"
return True
walter.doerwald
Move ibrowse into a separate module.
r272 class ibrowse(ipipe.Display):
# Show this many lines from the previous screen when paging horizontally
pageoverlapx = 1
# Show this many lines from the previous screen when paging vertically
pageoverlapy = 1
# Start scrolling when the cursor is less than this number of columns
# away from the left or right screen edge
scrollborderx = 10
# Start scrolling when the cursor is less than this number of lines
# away from the top or bottom screen edge
scrollbordery = 5
# Accelerate by this factor when scrolling horizontally
acceleratex = 1.05
# Accelerate by this factor when scrolling vertically
acceleratey = 1.05
# The maximum horizontal scroll speed
# (as a factor of the screen width (i.e. 0.5 == half a screen width)
maxspeedx = 0.5
# The maximum vertical scroll speed
# (as a factor of the screen height (i.e. 0.5 == half a screen height)
maxspeedy = 0.5
# The maximum number of header lines for browser level
# if the nesting is deeper, only the innermost levels are displayed
maxheaders = 5
# The approximate maximum length of a column entry
maxattrlength = 200
# Styles for various parts of the GUI
style_objheadertext = astyle.Style.fromstr("white:black:bold|reverse")
style_objheadernumber = astyle.Style.fromstr("white:blue:bold|reverse")
style_objheaderobject = astyle.Style.fromstr("white:black:reverse")
style_colheader = astyle.Style.fromstr("blue:white:reverse")
style_colheaderhere = astyle.Style.fromstr("green:black:bold|reverse")
style_colheadersep = astyle.Style.fromstr("blue:black:reverse")
style_number = astyle.Style.fromstr("blue:white:reverse")
style_numberhere = astyle.Style.fromstr("green:black:bold|reverse")
style_sep = astyle.Style.fromstr("blue:black")
style_data = astyle.Style.fromstr("white:black")
style_datapad = astyle.Style.fromstr("blue:black:bold")
style_footer = astyle.Style.fromstr("black:white")
style_report = astyle.Style.fromstr("white:black")
# Column separator in header
headersepchar = "|"
# Character for padding data cell entries
datapadchar = "."
# Column separator in data area
datasepchar = "|"
# Character to use for "empty" cell (i.e. for non-existing attributes)
nodatachar = "-"
# Prompts for modes that require keyboard input
prompts = {
walter.doerwald
Add a class _CommandInput that implements the basic functionality of...
r326 "goto": _CommandGoto(),
"find": _CommandFind(),
"findbackwards": _CommandFindBackwards()
walter.doerwald
Move ibrowse into a separate module.
r272 }
# Maps curses key codes to "function" names
walter.doerwald
Replace the plain dictionaries used for keymaps with a custom class...
r338 keymap = Keymap()
keymap.register("quit", "q")
keymap.register("up", curses.KEY_UP)
keymap.register("down", curses.KEY_DOWN)
keymap.register("pageup", curses.KEY_PPAGE)
keymap.register("pagedown", curses.KEY_NPAGE)
keymap.register("left", curses.KEY_LEFT)
keymap.register("right", curses.KEY_RIGHT)
keymap.register("home", curses.KEY_HOME, "\x01")
keymap.register("end", curses.KEY_END, "\x05")
keymap.register("prevattr", "<\x1b")
keymap.register("nextattr", ">\t")
keymap.register("pick", "p")
keymap.register("pickattr", "P")
keymap.register("pickallattrs", "C")
keymap.register("pickmarked", "m")
keymap.register("pickmarkedattr", "M")
walter.doerwald
IPython/Extensions/ipipe.py: Added a Table ihist that can be used to...
r683 keymap.register("pickinput", "i")
keymap.register("pickinputattr", "I")
walter.doerwald
Replace the plain dictionaries used for keymaps with a custom class...
r338 keymap.register("hideattr", "h")
keymap.register("unhideattrs", "H")
keymap.register("help", "?")
walter.doerwald
IPython/Extensions/astyle.py: Do a relative import of ipipe, so that...
r443 keymap.register("enter", "\r\n")
walter.doerwald
Replace the plain dictionaries used for keymaps with a custom class...
r338 keymap.register("enterattr", "E")
walter.doerwald
IPython/Extensions/ipipe.py: xrepr(), xiter() and xattrs() are now...
r415 # FIXME: What's happening here?
keymap.register("leave", curses.KEY_BACKSPACE, "x\x08\x7f")
walter.doerwald
Replace the plain dictionaries used for keymaps with a custom class...
r338 keymap.register("detail", "d")
keymap.register("detailattr", "D")
keymap.register("tooglemark", " ")
walter.doerwald
Add two new commands to ibrowse:...
r471 keymap.register("markrange", "%")
walter.doerwald
Replace the plain dictionaries used for keymaps with a custom class...
r338 keymap.register("sortattrasc", "v")
keymap.register("sortattrdesc", "V")
keymap.register("goto", "g")
keymap.register("find", "f")
keymap.register("findbackwards", "b")
walter.doerwald
Add two new commands to ibrowse:...
r471 keymap.register("refresh", "r")
keymap.register("refreshfind", "R")
walter.doerwald
Move ibrowse into a separate module.
r272
walter.doerwald
Add an input argument to *all* Display constructors....
r953 def __init__(self, input=None, *attrs):
walter.doerwald
Move ibrowse into a separate module.
r272 """
Create a new browser. If ``attrs`` is not empty, it is the list
of attributes that will be displayed in the browser, otherwise
these will be determined by the objects on screen.
"""
walter.doerwald
Add an input argument to *all* Display constructors....
r953 ipipe.Display.__init__(self, input)
walter.doerwald
The input object can now be passed to the constructor of ibrowse/igrid....
r951
walter.doerwald
Move ibrowse into a separate module.
r272 self.attrs = attrs
# Stack of browser levels
self.levels = []
# how many colums to scroll (Changes when accelerating)
self.stepx = 1.
# how many rows to scroll (Changes when accelerating)
self.stepy = 1.
# Beep on the edges of the data area? (Will be set to ``False``
# once the cursor hits the edge of the screen, so we don't get
# multiple beeps).
self._dobeep = True
# Cache for registered ``curses`` colors and styles.
self._styles = {}
self._colors = {}
self._maxcolor = 1
# How many header lines do we want to paint (the numbers of levels
# we have, but with an upper bound)
self._headerlines = 1
# Index of first header line
self._firstheaderline = 0
# curses window
self.scr = None
# report in the footer line (error, executed command etc.)
self._report = None
# value to be returned to the caller (set by commands)
self.returnvalue = None
# The mode the browser is in
# e.g. normal browsing or entering an argument for a command
self.mode = "default"
walter.doerwald
If running under Python 2.5, ibrowse now properly handles terminal resizing.
r336 # set by the SIGWINCH signal handler
self.resized = False
walter.doerwald
Move ibrowse into a separate module.
r272 def nextstepx(self, step):
"""
Accelerate horizontally.
"""
return max(1., min(step*self.acceleratex,
self.maxspeedx*self.levels[-1].mainsizex))
def nextstepy(self, step):
"""
Accelerate vertically.
"""
return max(1., min(step*self.acceleratey,
self.maxspeedy*self.levels[-1].mainsizey))
def getstyle(self, style):
"""
Register the ``style`` with ``curses`` or get it from the cache,
if it has been registered before.
"""
try:
return self._styles[style.fg, style.bg, style.attrs]
except KeyError:
attrs = 0
for b in astyle.A2CURSES:
if style.attrs & b:
attrs |= astyle.A2CURSES[b]
try:
color = self._colors[style.fg, style.bg]
except KeyError:
curses.init_pair(
self._maxcolor,
astyle.COLOR2CURSES[style.fg],
astyle.COLOR2CURSES[style.bg]
)
color = curses.color_pair(self._maxcolor)
self._colors[style.fg, style.bg] = color
self._maxcolor += 1
c = color | attrs
self._styles[style.fg, style.bg, style.attrs] = c
return c
def addstr(self, y, x, begx, endx, text, style):
"""
A version of ``curses.addstr()`` that can handle ``x`` coordinates
that are outside the screen.
"""
text2 = text[max(0, begx-x):max(0, endx-x)]
if text2:
self.scr.addstr(y, max(x, begx), text2, self.getstyle(style))
return len(text)
def addchr(self, y, x, begx, endx, c, l, style):
x0 = max(x, begx)
x1 = min(x+l, endx)
if x1>x0:
self.scr.addstr(y, x0, c*(x1-x0), self.getstyle(style))
return l
def _calcheaderlines(self, levels):
# Calculate how many headerlines do we have to display, if we have
# ``levels`` browser levels
if levels is None:
levels = len(self.levels)
self._headerlines = min(self.maxheaders, levels)
self._firstheaderline = levels-self._headerlines
def getstylehere(self, style):
"""
Return a style for displaying the original style ``style``
in the row the cursor is on.
"""
walter.doerwald
Give the ibrowse cursor row a blue background....
r346 return astyle.Style(style.fg, astyle.COLOR_BLUE, style.attrs | astyle.A_BOLD)
walter.doerwald
Move ibrowse into a separate module.
r272
def report(self, msg):
"""
Store the message ``msg`` for display below the footer line. This
will be displayed as soon as the screen is redrawn.
"""
self._report = msg
walter.doerwald
IPython/Extensions/ipipe.py: xrepr(), xiter() and xattrs() are now...
r415 def enter(self, item, *attrs):
walter.doerwald
Move ibrowse into a separate module.
r272 """
walter.doerwald
IPython/Extensions/ipipe.py: xrepr(), xiter() and xattrs() are now...
r415 Enter the object ``item``. If ``attrs`` is specified, it will be used
as a fixed list of attributes to display.
walter.doerwald
Move ibrowse into a separate module.
r272 """
walter.doerwald
IPython/Extensions/ipipe.py (xiter): Make sure that iterating...
r513 if self.levels and item is self.levels[-1].input:
walter.doerwald
Add two new commands to ibrowse:...
r471 curses.beep()
walter.doerwald
IPython/Extensions/ipipe.py (xiter): Make sure that iterating...
r513 self.report(CommandError("Recursion on input object"))
walter.doerwald
Add two new commands to ibrowse:...
r471 else:
walter.doerwald
IPython/Extensions/ipipe.py (xiter): Make sure that iterating...
r513 oldlevels = len(self.levels)
self._calcheaderlines(oldlevels+1)
try:
level = _BrowserLevel(
self,
item,
self.scrsizey-1-self._headerlines-2,
*attrs
)
except (KeyboardInterrupt, SystemExit):
raise
except Exception, exc:
walter.doerwald
If entering the first object level (i.e. the object...
r521 if not self.levels:
raise
walter.doerwald
IPython/Extensions/ipipe.py (xiter): Make sure that iterating...
r513 self._calcheaderlines(oldlevels)
curses.beep()
self.report(exc)
else:
self.levels.append(level)
walter.doerwald
Move ibrowse into a separate module.
r272
def startkeyboardinput(self, mode):
"""
Enter mode ``mode``, which requires keyboard input.
"""
self.mode = mode
walter.doerwald
Add a class _CommandInput that implements the basic functionality of...
r326 self.prompts[mode].start()
walter.doerwald
Move ibrowse into a separate module.
r272
def keylabel(self, keycode):
"""
Return a pretty name for the ``curses`` key ``keycode`` (used in the
help screen and in reports about unassigned keys).
"""
if keycode <= 0xff:
specialsnames = {
ord("\n"): "RETURN",
ord(" "): "SPACE",
ord("\t"): "TAB",
ord("\x7f"): "DELETE",
ord("\x08"): "BACKSPACE",
}
if keycode in specialsnames:
return specialsnames[keycode]
walter.doerwald
Display keycodes in the range 0x01-0x1F as CTRL-xx....
r333 elif 0x00 < keycode < 0x20:
return "CTRL-%s" % chr(keycode + 64)
walter.doerwald
Move ibrowse into a separate module.
r272 return repr(chr(keycode))
for name in dir(curses):
if name.startswith("KEY_") and getattr(curses, name) == keycode:
return name
return str(keycode)
def beep(self, force=False):
if force or self._dobeep:
curses.beep()
# don't beep again (as long as the same key is pressed)
self._dobeep = False
def cmd_up(self):
walter.doerwald
Put the documentation of the keyboard commands into the...
r340 """
Move the cursor to the previous row.
"""
walter.doerwald
Move ibrowse into a separate module.
r272 level = self.levels[-1]
self.report("up")
level.moveto(level.curx, level.cury-self.stepy)
def cmd_down(self):
walter.doerwald
Put the documentation of the keyboard commands into the...
r340 """
Move the cursor to the next row.
"""
walter.doerwald
Move ibrowse into a separate module.
r272 level = self.levels[-1]
self.report("down")
level.moveto(level.curx, level.cury+self.stepy)
def cmd_pageup(self):
walter.doerwald
Put the documentation of the keyboard commands into the...
r340 """
Move the cursor up one page.
"""
walter.doerwald
Move ibrowse into a separate module.
r272 level = self.levels[-1]
self.report("page up")
level.moveto(level.curx, level.cury-level.mainsizey+self.pageoverlapy)
def cmd_pagedown(self):
walter.doerwald
Put the documentation of the keyboard commands into the...
r340 """
Move the cursor down one page.
"""
walter.doerwald
Move ibrowse into a separate module.
r272 level = self.levels[-1]
self.report("page down")
level.moveto(level.curx, level.cury+level.mainsizey-self.pageoverlapy)
def cmd_left(self):
walter.doerwald
Put the documentation of the keyboard commands into the...
r340 """
Move the cursor left.
"""
walter.doerwald
Move ibrowse into a separate module.
r272 level = self.levels[-1]
self.report("left")
level.moveto(level.curx-self.stepx, level.cury)
def cmd_right(self):
walter.doerwald
Put the documentation of the keyboard commands into the...
r340 """
Move the cursor right.
"""
walter.doerwald
Move ibrowse into a separate module.
r272 level = self.levels[-1]
self.report("right")
level.moveto(level.curx+self.stepx, level.cury)
def cmd_home(self):
walter.doerwald
Put the documentation of the keyboard commands into the...
r340 """
Move the cursor to the first column.
"""
walter.doerwald
Move ibrowse into a separate module.
r272 level = self.levels[-1]
self.report("home")
level.moveto(0, level.cury)
def cmd_end(self):
walter.doerwald
Put the documentation of the keyboard commands into the...
r340 """
Move the cursor to the last column.
"""
walter.doerwald
Move ibrowse into a separate module.
r272 level = self.levels[-1]
self.report("end")
level.moveto(level.datasizex+level.mainsizey-self.pageoverlapx, level.cury)
def cmd_prevattr(self):
walter.doerwald
Put the documentation of the keyboard commands into the...
r340 """
Move the cursor one attribute column to the left.
"""
walter.doerwald
Move ibrowse into a separate module.
r272 level = self.levels[-1]
if level.displayattr[0] is None or level.displayattr[0] == 0:
self.beep()
else:
self.report("prevattr")
pos = 0
for (i, attrname) in enumerate(level.displayattrs):
if i == level.displayattr[0]-1:
break
pos += level.colwidths[attrname] + 1
level.moveto(pos, level.cury)
def cmd_nextattr(self):
walter.doerwald
Put the documentation of the keyboard commands into the...
r340 """
Move the cursor one attribute column to the right.
"""
walter.doerwald
Move ibrowse into a separate module.
r272 level = self.levels[-1]
if level.displayattr[0] is None or level.displayattr[0] == len(level.displayattrs)-1:
self.beep()
else:
self.report("nextattr")
pos = 0
for (i, attrname) in enumerate(level.displayattrs):
if i == level.displayattr[0]+1:
break
pos += level.colwidths[attrname] + 1
level.moveto(pos, level.cury)
def cmd_pick(self):
walter.doerwald
Put the documentation of the keyboard commands into the...
r340 """
'Pick' the object under the cursor (i.e. the row the cursor is on).
This leaves the browser and returns the picked object to the caller.
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 (In IPython this object will be available as the ``_`` variable.)
walter.doerwald
Put the documentation of the keyboard commands into the...
r340 """
walter.doerwald
Move ibrowse into a separate module.
r272 level = self.levels[-1]
self.returnvalue = level.items[level.cury].item
return True
def cmd_pickattr(self):
walter.doerwald
Put the documentation of the keyboard commands into the...
r340 """
'Pick' the attribute under the cursor (i.e. the row/column the
cursor is on).
"""
walter.doerwald
Move ibrowse into a separate module.
r272 level = self.levels[-1]
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 attr = level.displayattr[1]
if attr is ipipe.noitem:
walter.doerwald
Move ibrowse into a separate module.
r272 curses.beep()
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 self.report(CommandError("no column under cursor"))
walter.doerwald
Move ibrowse into a separate module.
r272 return
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 value = attr.value(level.items[level.cury].item)
if value is ipipe.noitem:
walter.doerwald
Move ibrowse into a separate module.
r272 curses.beep()
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 self.report(AttributeError(attr.name()))
walter.doerwald
Move ibrowse into a separate module.
r272 else:
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 self.returnvalue = value
walter.doerwald
Move ibrowse into a separate module.
r272 return True
def cmd_pickallattrs(self):
walter.doerwald
Put the documentation of the keyboard commands into the...
r340 """
Pick' the complete column under the cursor (i.e. the attribute under
the cursor) from all currently fetched objects. These attributes
will be returned as a list.
"""
walter.doerwald
Move ibrowse into a separate module.
r272 level = self.levels[-1]
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 attr = level.displayattr[1]
if attr is ipipe.noitem:
walter.doerwald
Move ibrowse into a separate module.
r272 curses.beep()
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 self.report(CommandError("no column under cursor"))
walter.doerwald
Move ibrowse into a separate module.
r272 return
result = []
for cache in level.items:
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 value = attr.value(cache.item)
if value is not ipipe.noitem:
result.append(value)
walter.doerwald
Move ibrowse into a separate module.
r272 self.returnvalue = result
return True
def cmd_pickmarked(self):
walter.doerwald
Put the documentation of the keyboard commands into the...
r340 """
'Pick' marked objects. Marked objects will be returned as a list.
"""
walter.doerwald
Move ibrowse into a separate module.
r272 level = self.levels[-1]
self.returnvalue = [cache.item for cache in level.items if cache.marked]
return True
def cmd_pickmarkedattr(self):
walter.doerwald
Put the documentation of the keyboard commands into the...
r340 """
'Pick' the attribute under the cursor from all marked objects
(This returns a list).
"""
walter.doerwald
Move ibrowse into a separate module.
r272 level = self.levels[-1]
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 attr = level.displayattr[1]
if attr is ipipe.noitem:
walter.doerwald
Move ibrowse into a separate module.
r272 curses.beep()
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 self.report(CommandError("no column under cursor"))
walter.doerwald
Move ibrowse into a separate module.
r272 return
result = []
for cache in level.items:
if cache.marked:
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 value = attr.value(cache.item)
if value is not ipipe.noitem:
result.append(value)
walter.doerwald
Move ibrowse into a separate module.
r272 self.returnvalue = result
return True
walter.doerwald
IPython/Extensions/ipipe.py: Added a Table ihist that can be used to...
r683 def cmd_pickinput(self):
"""
Use the object under the cursor (i.e. the row the cursor is on) as
the next input line. This leaves the browser and puts the picked object
in the input.
"""
level = self.levels[-1]
value = level.items[level.cury].item
self.returnvalue = None
api = ipapi.get()
api.set_next_input(str(value))
return True
def cmd_pickinputattr(self):
"""
Use the attribute under the cursor i.e. the row/column the cursor is on)
as the next input line. This leaves the browser and puts the picked
object in the input.
"""
level = self.levels[-1]
attr = level.displayattr[1]
if attr is ipipe.noitem:
curses.beep()
self.report(CommandError("no column under cursor"))
return
value = attr.value(level.items[level.cury].item)
if value is ipipe.noitem:
curses.beep()
self.report(AttributeError(attr.name()))
self.returnvalue = None
api = ipapi.get()
api.set_next_input(str(value))
return True
walter.doerwald
Move ibrowse into a separate module.
r272 def cmd_markrange(self):
walter.doerwald
Put the documentation of the keyboard commands into the...
r340 """
Mark all objects from the last marked object before the current cursor
position to the cursor position.
"""
walter.doerwald
Move ibrowse into a separate module.
r272 level = self.levels[-1]
self.report("markrange")
start = None
if level.items:
for i in xrange(level.cury, -1, -1):
if level.items[i].marked:
start = i
break
if start is None:
self.report(CommandError("no mark before cursor"))
curses.beep()
else:
for i in xrange(start, level.cury+1):
cache = level.items[i]
if not cache.marked:
cache.marked = True
level.marked += 1
walter.doerwald
IPython/Extensions/ipipe.py: xrepr(), xiter() and xattrs() are now...
r415 def cmd_enter(self):
walter.doerwald
Put the documentation of the keyboard commands into the...
r340 """
Enter the object under the cursor. (what this mean depends on the object
walter.doerwald
IPython/Extensions/ipipe.py: xrepr(), xiter() and xattrs() are now...
r415 itself (i.e. how it implements iteration). This opens a new browser 'level'.
walter.doerwald
Put the documentation of the keyboard commands into the...
r340 """
walter.doerwald
Move ibrowse into a separate module.
r272 level = self.levels[-1]
try:
item = level.items[level.cury].item
except IndexError:
self.report(CommandError("No object"))
curses.beep()
else:
walter.doerwald
IPython/Extensions/ipipe.py: xrepr(), xiter() and xattrs() are now...
r415 self.report("entering object...")
self.enter(item)
walter.doerwald
Move ibrowse into a separate module.
r272
def cmd_leave(self):
walter.doerwald
Put the documentation of the keyboard commands into the...
r340 """
Leave the current browser level and go back to the previous one.
"""
walter.doerwald
Move ibrowse into a separate module.
r272 self.report("leave")
if len(self.levels) > 1:
self._calcheaderlines(len(self.levels)-1)
self.levels.pop(-1)
else:
self.report(CommandError("This is the last level"))
curses.beep()
def cmd_enterattr(self):
walter.doerwald
Put the documentation of the keyboard commands into the...
r340 """
Enter the attribute under the cursor.
"""
walter.doerwald
Move ibrowse into a separate module.
r272 level = self.levels[-1]
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 attr = level.displayattr[1]
if attr is ipipe.noitem:
walter.doerwald
Move ibrowse into a separate module.
r272 curses.beep()
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 self.report(CommandError("no column under cursor"))
walter.doerwald
Move ibrowse into a separate module.
r272 return
try:
item = level.items[level.cury].item
except IndexError:
self.report(CommandError("No object"))
curses.beep()
else:
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 value = attr.value(item)
name = attr.name()
if value is ipipe.noitem:
self.report(AttributeError(name))
walter.doerwald
Move ibrowse into a separate module.
r272 else:
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 self.report("entering object attribute %s..." % name)
walter.doerwald
IPython/Extensions/ipipe.py: xrepr(), xiter() and xattrs() are now...
r415 self.enter(value)
walter.doerwald
Move ibrowse into a separate module.
r272
def cmd_detail(self):
walter.doerwald
Put the documentation of the keyboard commands into the...
r340 """
Show a detail view of the object under the cursor. This shows the
name, type, doc string and value of the object attributes (and it
might show more attributes than in the list view, depending on
the object).
"""
walter.doerwald
Move ibrowse into a separate module.
r272 level = self.levels[-1]
try:
item = level.items[level.cury].item
except IndexError:
self.report(CommandError("No object"))
curses.beep()
else:
self.report("entering detail view for object...")
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 attrs = [ipipe.AttributeDetail(item, attr) for attr in ipipe.xattrs(item, "detail")]
walter.doerwald
IPython/Extensions/ipipe.py: xrepr(), xiter() and xattrs() are now...
r415 self.enter(attrs)
walter.doerwald
Move ibrowse into a separate module.
r272
def cmd_detailattr(self):
walter.doerwald
Put the documentation of the keyboard commands into the...
r340 """
Show a detail view of the attribute under the cursor.
"""
walter.doerwald
Move ibrowse into a separate module.
r272 level = self.levels[-1]
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 attr = level.displayattr[1]
if attr is ipipe.noitem:
walter.doerwald
Move ibrowse into a separate module.
r272 curses.beep()
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 self.report(CommandError("no attribute"))
walter.doerwald
Move ibrowse into a separate module.
r272 return
try:
item = level.items[level.cury].item
except IndexError:
self.report(CommandError("No object"))
curses.beep()
else:
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 try:
item = attr.value(item)
except (KeyboardInterrupt, SystemExit):
raise
except Exception, exc:
self.report(exc)
walter.doerwald
Move ibrowse into a separate module.
r272 else:
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 self.report("entering detail view for attribute %s..." % attr.name())
attrs = [ipipe.AttributeDetail(item, attr) for attr in ipipe.xattrs(item, "detail")]
walter.doerwald
IPython/Extensions/ipipe.py: xrepr(), xiter() and xattrs() are now...
r415 self.enter(attrs)
walter.doerwald
Move ibrowse into a separate module.
r272
def cmd_tooglemark(self):
walter.doerwald
Put the documentation of the keyboard commands into the...
r340 """
Mark/unmark the object under the cursor. Marked objects have a '!'
after the row number).
"""
walter.doerwald
Move ibrowse into a separate module.
r272 level = self.levels[-1]
self.report("toggle mark")
try:
item = level.items[level.cury]
except IndexError: # no items?
pass
else:
if item.marked:
item.marked = False
level.marked -= 1
else:
item.marked = True
level.marked += 1
def cmd_sortattrasc(self):
walter.doerwald
Put the documentation of the keyboard commands into the...
r340 """
Sort the objects (in ascending order) using the attribute under
the cursor as the sort key.
"""
walter.doerwald
Move ibrowse into a separate module.
r272 level = self.levels[-1]
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 attr = level.displayattr[1]
if attr is ipipe.noitem:
walter.doerwald
Move ibrowse into a separate module.
r272 curses.beep()
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 self.report(CommandError("no column under cursor"))
walter.doerwald
Move ibrowse into a separate module.
r272 return
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 self.report("sort by %s (ascending)" % attr.name())
walter.doerwald
Move ibrowse into a separate module.
r272 def key(item):
try:
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 return attr.value(item)
walter.doerwald
Move ibrowse into a separate module.
r272 except (KeyboardInterrupt, SystemExit):
raise
except Exception:
return None
level.sort(key)
def cmd_sortattrdesc(self):
walter.doerwald
Put the documentation of the keyboard commands into the...
r340 """
Sort the objects (in descending order) using the attribute under
the cursor as the sort key.
"""
walter.doerwald
Move ibrowse into a separate module.
r272 level = self.levels[-1]
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 attr = level.displayattr[1]
if attr is ipipe.noitem:
walter.doerwald
Move ibrowse into a separate module.
r272 curses.beep()
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 self.report(CommandError("no column under cursor"))
walter.doerwald
Move ibrowse into a separate module.
r272 return
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 self.report("sort by %s (descending)" % attr.name())
walter.doerwald
Move ibrowse into a separate module.
r272 def key(item):
try:
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 return attr.value(item)
walter.doerwald
Move ibrowse into a separate module.
r272 except (KeyboardInterrupt, SystemExit):
raise
except Exception:
return None
level.sort(key, reverse=True)
walter.doerwald
Put the documentation of the keyboard commands into the...
r340 def cmd_hideattr(self):
"""
Hide the attribute under the cursor.
"""
level = self.levels[-1]
if level.displayattr[0] is None:
self.beep()
else:
self.report("hideattr")
level.hiddenattrs.add(level.displayattr[1])
level.moveto(level.curx, level.cury, refresh=True)
def cmd_unhideattrs(self):
"""
Make all attributes visible again.
"""
level = self.levels[-1]
self.report("unhideattrs")
level.hiddenattrs.clear()
level.moveto(level.curx, level.cury, refresh=True)
walter.doerwald
Move ibrowse into a separate module.
r272 def cmd_goto(self):
walter.doerwald
Put the documentation of the keyboard commands into the...
r340 """
Jump to a row. The row number can be entered at the
bottom of the screen.
"""
walter.doerwald
Move ibrowse into a separate module.
r272 self.startkeyboardinput("goto")
def cmd_find(self):
walter.doerwald
Put the documentation of the keyboard commands into the...
r340 """
Search forward for a row. The search condition can be entered at the
bottom of the screen.
"""
walter.doerwald
Move ibrowse into a separate module.
r272 self.startkeyboardinput("find")
def cmd_findbackwards(self):
walter.doerwald
Put the documentation of the keyboard commands into the...
r340 """
Search backward for a row. The search condition can be entered at the
bottom of the screen.
"""
walter.doerwald
Move ibrowse into a separate module.
r272 self.startkeyboardinput("findbackwards")
walter.doerwald
Add two new commands to ibrowse:...
r471 def cmd_refresh(self):
"""
Refreshes the display by restarting the iterator.
"""
level = self.levels[-1]
self.report("refresh")
level.refresh()
def cmd_refreshfind(self):
"""
Refreshes the display by restarting the iterator and goes back to the
walter.doerwald
Enhance cmd_refreshfind docstring....
r473 same object the cursor was on before restarting (if this object can't be
found the cursor jumps back to the first object).
walter.doerwald
Add two new commands to ibrowse:...
r471 """
level = self.levels[-1]
self.report("refreshfind")
level.refreshfind()
walter.doerwald
Move ibrowse into a separate module.
r272 def cmd_help(self):
"""
walter.doerwald
Put the documentation of the keyboard commands into the...
r340 Opens the help screen as a new browser level, describing keyboard
shortcuts.
walter.doerwald
Move ibrowse into a separate module.
r272 """
for level in self.levels:
if isinstance(level.input, _BrowserHelp):
curses.beep()
self.report(CommandError("help already active"))
return
walter.doerwald
IPython/Extensions/ipipe.py: xrepr(), xiter() and xattrs() are now...
r415 self.enter(_BrowserHelp(self))
walter.doerwald
Move ibrowse into a separate module.
r272
walter.doerwald
Put the documentation of the keyboard commands into the...
r340 def cmd_quit(self):
"""
Quit the browser and return to the IPython prompt.
"""
self.returnvalue = None
return True
walter.doerwald
If running under Python 2.5, ibrowse now properly handles terminal resizing.
r336 def sigwinchhandler(self, signal, frame):
self.resized = True
walter.doerwald
Move ibrowse into a separate module.
r272 def _dodisplay(self, scr):
"""
This method is the workhorse of the browser. It handles screen
drawing and the keyboard.
"""
self.scr = scr
curses.halfdelay(1)
footery = 2
keys = []
walter.doerwald
Fixed the help message in the footer (which was displaying "quit" twice).
r360 for cmd in ("quit", "help"):
key = self.keymap.findkey(cmd, None)
walter.doerwald
Use a loop to collect the keys that are displayed as a...
r342 if key is not None:
walter.doerwald
Fixed the help message in the footer (which was displaying "quit" twice).
r360 keys.append("%s=%s" % (self.keylabel(key), cmd))
walter.doerwald
Move ibrowse into a separate module.
r272 helpmsg = " | %s" % " ".join(keys)
scr.clear()
msg = "Fetching first batch of objects..."
(self.scrsizey, self.scrsizex) = scr.getmaxyx()
scr.addstr(self.scrsizey//2, (self.scrsizex-len(msg))//2, msg)
scr.refresh()
lastc = -1
self.levels = []
# enter the first level
walter.doerwald
IPython/Extensions/ipipe.py: xrepr(), xiter() and xattrs() are now...
r415 self.enter(self.input, *self.attrs)
walter.doerwald
Move ibrowse into a separate module.
r272
self._calcheaderlines(None)
while True:
level = self.levels[-1]
(self.scrsizey, self.scrsizex) = scr.getmaxyx()
level.mainsizey = self.scrsizey-1-self._headerlines-footery
# Paint object header
for i in xrange(self._firstheaderline, self._firstheaderline+self._headerlines):
lv = self.levels[i]
posx = 0
posy = i-self._firstheaderline
endx = self.scrsizex
if i: # not the first level
msg = " (%d/%d" % (self.levels[i-1].cury, len(self.levels[i-1].items))
if not self.levels[i-1].exhausted:
msg += "+"
msg += ") "
endx -= len(msg)+1
posx += self.addstr(posy, posx, 0, endx, " ibrowse #%d: " % i, self.style_objheadertext)
for (style, text) in lv.header:
posx += self.addstr(posy, posx, 0, endx, text, self.style_objheaderobject)
if posx >= endx:
break
if i:
posx += self.addstr(posy, posx, 0, self.scrsizex, msg, self.style_objheadernumber)
posx += self.addchr(posy, posx, 0, self.scrsizex, " ", self.scrsizex-posx, self.style_objheadernumber)
if not level.items:
self.addchr(self._headerlines, 0, 0, self.scrsizex, " ", self.scrsizex, self.style_colheader)
self.addstr(self._headerlines+1, 0, 0, self.scrsizex, " <empty>", astyle.style_error)
scr.clrtobot()
else:
# Paint column headers
scr.move(self._headerlines, 0)
scr.addstr(" %*s " % (level.numbersizex, "#"), self.getstyle(self.style_colheader))
scr.addstr(self.headersepchar, self.getstyle(self.style_colheadersep))
begx = level.numbersizex+3
posx = begx-level.datastartx
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 for attr in level.displayattrs:
attrname = attr.name()
cwidth = level.colwidths[attr]
header = attrname.ljust(cwidth)
if attr is level.displayattr[1]:
walter.doerwald
Move ibrowse into a separate module.
r272 style = self.style_colheaderhere
else:
style = self.style_colheader
posx += self.addstr(self._headerlines, posx, begx, self.scrsizex, header, style)
posx += self.addstr(self._headerlines, posx, begx, self.scrsizex, self.headersepchar, self.style_colheadersep)
if posx >= self.scrsizex:
break
else:
scr.addstr(" "*(self.scrsizex-posx), self.getstyle(self.style_colheader))
# Paint rows
posy = self._headerlines+1+level.datastarty
for i in xrange(level.datastarty, min(level.datastarty+level.mainsizey, len(level.items))):
cache = level.items[i]
if i == level.cury:
style = self.style_numberhere
else:
style = self.style_number
posy = self._headerlines+1+i-level.datastarty
posx = begx-level.datastartx
scr.move(posy, 0)
scr.addstr(" %*d%s" % (level.numbersizex, i, " !"[cache.marked]), self.getstyle(style))
scr.addstr(self.headersepchar, self.getstyle(self.style_sep))
for attrname in level.displayattrs:
cwidth = level.colwidths[attrname]
try:
(align, length, parts) = level.displayrows[i-level.datastarty][attrname]
except KeyError:
align = 2
style = astyle.style_nodata
walter.doerwald
Make cursor visible over non existing attributes.
r352 if i == level.cury:
style = self.getstylehere(style)
walter.doerwald
Move ibrowse into a separate module.
r272 padstyle = self.style_datapad
sepstyle = self.style_sep
if i == level.cury:
padstyle = self.getstylehere(padstyle)
sepstyle = self.getstylehere(sepstyle)
if align == 2:
posx += self.addchr(posy, posx, begx, self.scrsizex, self.nodatachar, cwidth, style)
else:
if align == 1:
posx += self.addchr(posy, posx, begx, self.scrsizex, self.datapadchar, cwidth-length, padstyle)
elif align == 0:
pad1 = (cwidth-length)//2
pad2 = cwidth-length-len(pad1)
posx += self.addchr(posy, posx, begx, self.scrsizex, self.datapadchar, pad1, padstyle)
for (style, text) in parts:
if i == level.cury:
style = self.getstylehere(style)
posx += self.addstr(posy, posx, begx, self.scrsizex, text, style)
if posx >= self.scrsizex:
break
if align == -1:
posx += self.addchr(posy, posx, begx, self.scrsizex, self.datapadchar, cwidth-length, padstyle)
elif align == 0:
posx += self.addchr(posy, posx, begx, self.scrsizex, self.datapadchar, pad2, padstyle)
posx += self.addstr(posy, posx, begx, self.scrsizex, self.datasepchar, sepstyle)
else:
scr.clrtoeol()
# Add blank row headers for the rest of the screen
for posy in xrange(posy+1, self.scrsizey-2):
scr.addstr(posy, 0, " " * (level.numbersizex+2), self.getstyle(self.style_colheader))
scr.clrtoeol()
posy = self.scrsizey-footery
# Display footer
scr.addstr(posy, 0, " "*self.scrsizex, self.getstyle(self.style_footer))
if level.exhausted:
flag = ""
else:
flag = "+"
endx = self.scrsizex-len(helpmsg)-1
scr.addstr(posy, endx, helpmsg, self.getstyle(self.style_footer))
posx = 0
msg = " %d%s objects (%d marked): " % (len(level.items), flag, level.marked)
posx += self.addstr(posy, posx, 0, endx, msg, self.style_footer)
try:
item = level.items[level.cury].item
except IndexError: # empty
pass
else:
for (nostyle, text) in ipipe.xrepr(item, "footer"):
if not isinstance(nostyle, int):
posx += self.addstr(posy, posx, 0, endx, text, self.style_footer)
if posx >= endx:
break
attrstyle = [(astyle.style_default, "no attribute")]
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 attr = level.displayattr[1]
if attr is not ipipe.noitem and not isinstance(attr, ipipe.SelfDescriptor):
walter.doerwald
Move ibrowse into a separate module.
r272 posx += self.addstr(posy, posx, 0, endx, " | ", self.style_footer)
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 posx += self.addstr(posy, posx, 0, endx, attr.name(), self.style_footer)
walter.doerwald
Move ibrowse into a separate module.
r272 posx += self.addstr(posy, posx, 0, endx, ": ", self.style_footer)
try:
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 value = attr.value(item)
walter.doerwald
Move ibrowse into a separate module.
r272 except (SystemExit, KeyboardInterrupt):
raise
except Exception, exc:
walter.doerwald
IPython/Extensions/ipipe.py: xrepr(), xiter() and xattrs() are now...
r415 value = exc
walter.doerwald
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
r355 if value is not ipipe.noitem:
attrstyle = ipipe.xrepr(value, "footer")
walter.doerwald
Move ibrowse into a separate module.
r272 for (nostyle, text) in attrstyle:
if not isinstance(nostyle, int):
posx += self.addstr(posy, posx, 0, endx, text, self.style_footer)
if posx >= endx:
break
try:
# Display input prompt
if self.mode in self.prompts:
walter.doerwald
Add a class _CommandInput that implements the basic functionality of...
r326 history = self.prompts[self.mode]
walter.doerwald
Display the length of the input history and the position of the...
r327 posx = 0
posy = self.scrsizey-1
posx += self.addstr(posy, posx, 0, endx, history.prompt, astyle.style_default)
posx += self.addstr(posy, posx, 0, endx, " [", astyle.style_default)
if history.cury==-1:
text = "new"
else:
text = str(history.cury+1)
posx += self.addstr(posy, posx, 0, endx, text, astyle.style_type_number)
if history.history:
posx += self.addstr(posy, posx, 0, endx, "/", astyle.style_default)
posx += self.addstr(posy, posx, 0, endx, str(len(history.history)), astyle.style_type_number)
posx += self.addstr(posy, posx, 0, endx, "]: ", astyle.style_default)
inputstartx = posx
posx += self.addstr(posy, posx, 0, endx, history.input, astyle.style_default)
walter.doerwald
Move ibrowse into a separate module.
r272 # Display report
else:
if self._report is not None:
if isinstance(self._report, Exception):
style = self.getstyle(astyle.style_error)
if self._report.__class__.__module__ == "exceptions":
msg = "%s: %s" % \
(self._report.__class__.__name__, self._report)
else:
msg = "%s.%s: %s" % \
(self._report.__class__.__module__,
self._report.__class__.__name__, self._report)
else:
style = self.getstyle(self.style_report)
msg = self._report
scr.addstr(self.scrsizey-1, 0, msg[:self.scrsizex], style)
self._report = None
else:
scr.move(self.scrsizey-1, 0)
except curses.error:
walter.doerwald
Change _BrowserLevel.moveto() so that the call to fetch() always tries to...
r329 # Protect against errors from writing to the last line
walter.doerwald
Move ibrowse into a separate module.
r272 pass
scr.clrtoeol()
# Position cursor
if self.mode in self.prompts:
walter.doerwald
Add a class _CommandInput that implements the basic functionality of...
r326 history = self.prompts[self.mode]
walter.doerwald
Display the length of the input history and the position of the...
r327 scr.move(self.scrsizey-1, inputstartx+history.curx)
walter.doerwald
Move ibrowse into a separate module.
r272 else:
scr.move(
1+self._headerlines+level.cury-level.datastarty,
level.numbersizex+3+level.curx-level.datastartx
)
scr.refresh()
# Check keyboard
while True:
c = scr.getch()
walter.doerwald
If running under Python 2.5, ibrowse now properly handles terminal resizing.
r336 if self.resized:
size = fcntl.ioctl(0, tty.TIOCGWINSZ, "12345678")
size = struct.unpack("4H", size)
oldsize = scr.getmaxyx()
scr.erase()
curses.resize_term(size[0], size[1])
newsize = scr.getmaxyx()
scr.erase()
for l in self.levels:
l.mainsizey += newsize[0]-oldsize[0]
l.moveto(l.curx, l.cury, refresh=True)
scr.refresh()
self.resized = False
break # Redisplay
walter.doerwald
Move ibrowse into a separate module.
r272 if self.mode in self.prompts:
walter.doerwald
Add a class _CommandInput that implements the basic functionality of...
r326 if self.prompts[self.mode].handlekey(self, c):
break # Redisplay
walter.doerwald
Move ibrowse into a separate module.
r272 else:
# if no key is pressed slow down and beep again
if c == -1:
self.stepx = 1.
self.stepy = 1.
self._dobeep = True
else:
# if a different key was pressed slow down and beep too
if c != lastc:
lastc = c
self.stepx = 1.
self.stepy = 1.
self._dobeep = True
cmdname = self.keymap.get(c, None)
if cmdname is None:
self.report(
UnassignedKeyError("Unassigned key %s" %
self.keylabel(c)))
else:
cmdfunc = getattr(self, "cmd_%s" % cmdname, None)
if cmdfunc is None:
self.report(
UnknownCommandError("Unknown command %r" %
(cmdname,)))
elif cmdfunc():
returnvalue = self.returnvalue
self.returnvalue = None
return returnvalue
self.stepx = self.nextstepx(self.stepx)
self.stepy = self.nextstepy(self.stepy)
curses.flushinp() # get rid of type ahead
break # Redisplay
self.scr = None
def display(self):
walter.doerwald
If running under Python 2.5, ibrowse now properly handles terminal resizing.
r336 if hasattr(curses, "resize_term"):
oldhandler = signal.signal(signal.SIGWINCH, self.sigwinchhandler)
try:
return curses.wrapper(self._dodisplay)
finally:
signal.signal(signal.SIGWINCH, oldhandler)
else:
return curses.wrapper(self._dodisplay)