##// END OF EJS Templates
Walter's ipipe patch:...
vivainio -
Show More
@@ -8,10 +8,10 b' objects imported this way starts with ``i`` to minimize collisions.'
8 ``ipipe`` supports "pipeline expressions", which is something resembling Unix
8 ``ipipe`` supports "pipeline expressions", which is something resembling Unix
9 pipes. An example is:
9 pipes. An example is:
10
10
11 iwalk | ifilter("name.endswith('.py')") | isort("size")
11 >>> ienv | isort("_.key.lower()")
12
13 This gives a listing of all environment variables sorted by name.
12
14
13 This gives a listing of all files in the current directory (and subdirectories)
14 whose name ends with '.py' sorted by size.
15
15
16 There are three types of objects in a pipeline expression:
16 There are three types of objects in a pipeline expression:
17
17
@@ -31,6 +31,78 b' There are three types of objects in a pipeline expression:'
31 expression. If a pipeline expression doesn't end in a display object a default
31 expression. If a pipeline expression doesn't end in a display object a default
32 display objects will be used. One example is `οΏ½browse`` which is a ``curses``
32 display objects will be used. One example is `οΏ½browse`` which is a ``curses``
33 based browser.
33 based browser.
34
35
36 Adding support for pipeline expressions to your own objects can be done through
37 three extensions points (all of them optional):
38
39 * An object that will be displayed as a row by a ``Display`` object should
40 implement the method ``__xattrs__(self, mode)``. This method must return a
41 sequence of attribute names. This sequence may also contain integers, which
42 will be treated as sequence indizes. Also supported is ``None``, which uses
43 the object itself and callables which will be called with the object as the
44 an argument. If ``__xattrs__()`` isn't implemented ``(None,)`` will be used as
45 the attribute sequence (i.e. the object itself (it's ``repr()`` format) will
46 be being displayed. The global function ``xattrs()`` implements this
47 functionality.
48
49 * When an object ``foo`` is displayed in the header (or footer) of the browser
50 ``foo.__xrepr__("header")`` (or ``foo.__xrepr__("footer")``) is called.
51 Currently only ``"header"`` and ``"footer"`` are used as the mode argument.
52 When the method doesn't recognize the mode argument, it should fall back to
53 the ``repr()`` output. If the method ``__xrepr__()`` isn't defined the browser
54 falls back to ``repr()``. The global function ``xrepr()`` implements this
55 functionality.
56
57 * Objects that can be iterated by ``Pipe``s must implement the method
58 ``__xiter__(self, mode)``. ``mode`` can take the following values:
59
60 - ``"default"``: This is the default value and ist always used by pipeline
61 expressions. Other values are only used in the browser.
62 - ``None``: This value is passed by the browser. The object must return an
63 iterable of ``XMode`` objects describing all modes supported by the object.
64 (This should never include ``"default"`` or ``None``).
65 - Any other value that the object supports.
66
67 The global function ``xiter()`` can be called to get such an iterator. If
68 the method ``_xiter__`` isn't implemented, ``xiter()`` falls back to
69 ``__iter__``. In addition to that, dictionaries and modules receive special
70 treatment (returning an iterator over ``(key, value)`` pairs). This makes it
71 possible to use dictionaries and modules in pipeline expressions, for example:
72
73 >>> import sys
74 >>> sys | ifilter("isinstance(_.value, int)") | idump
75 key |value
76 api_version| 1012
77 dllhandle | 503316480
78 hexversion | 33817328
79 maxint |2147483647
80 maxunicode | 65535
81 >>> sys.modules | ifilter("_.value is not None") | isort("_.key.lower()")
82 ...
83
84 Note: The expression strings passed to ``ifilter()`` and ``isort()`` can
85 refer to the object to be filtered or sorted via the variable ``_``. When
86 running under Python 2.4 it's also possible to refer to the attributes of
87 the object directy, i.e.:
88
89 >>> sys.modules | ifilter("_.value is not None") | isort("_.key.lower()")
90
91 can be replaced with
92
93 >>> sys.modules | ifilter("value is not None") | isort("key.lower()")
94
95 In addition to expression strings, it's possible to pass callables (taking
96 the object as an argument) to ``ifilter()``, ``isort()`` and ``ieval()``:
97
98 >>> sys | ifilter(lambda _:isinstance(_.value, int)) \
99 ... | ieval(lambda _: (_.key, hex(_.value))) | idump
100 0 |1
101 api_version|0x3f4
102 dllhandle |0x1e000000
103 hexversion |0x20402f0
104 maxint |0x7fffffff
105 maxunicode |0xffff
34 """
106 """
35
107
36 import sys, os, os.path, stat, glob, new, csv, datetime
108 import sys, os, os.path, stat, glob, new, csv, datetime
@@ -88,6 +160,34 b' __all__ = ['
88 os.stat_float_times(True) # enable microseconds
160 os.stat_float_times(True) # enable microseconds
89
161
90
162
163 class _AttrNamespace(object):
164 """
165 Internal helper class that is used for providing a namespace for evaluating
166 expressions containg attribute names of an object.
167
168 This class can only be used with Python 2.4.
169 """
170 def __init__(self, wrapped):
171 self.wrapped = wrapped
172
173 def __getitem__(self, name):
174 if name == "_":
175 return self.wrapped
176 try:
177 return getattr(self.wrapped, name)
178 except AttributeError:
179 raise KeyError(name)
180
181 # Python 2.3 compatibility
182 # fall back to a real dictionary (containing just the object itself) if we can't
183 # use the _AttrNamespace class in eval()
184 try:
185 eval("_", None, _AttrNamespace(None))
186 except TypeError:
187 def _AttrNamespace(wrapped):
188 return {"_": wrapped}
189
190
91 _default = object()
191 _default = object()
92
192
93 def item(iterator, index, default=_default):
193 def item(iterator, index, default=_default):
@@ -124,23 +224,6 b' def item(iterator, index, default=_default):'
124 return default
224 return default
125
225
126
226
127 class _AttrNamespace(object):
128 """
129 Internal helper that is used for providing a namespace for evaluating
130 expressions containg attribute names of an object.
131 """
132 def __init__(self, wrapped):
133 self.wrapped = wrapped
134
135 def __getitem__(self, name):
136 if name == "_":
137 return self.wrapped
138 try:
139 return getattr(self.wrapped, name)
140 except AttributeError:
141 raise KeyError(name)
142
143
144 class Table(object):
227 class Table(object):
145 """
228 """
146 A ``Table`` is an object that produces items (just like a normal Python
229 A ``Table`` is an object that produces items (just like a normal Python
@@ -148,6 +231,10 b' class Table(object):'
148 expression. The displayhook will open the default browser for such an object
231 expression. The displayhook will open the default browser for such an object
149 (instead of simply printing the ``repr()`` result).
232 (instead of simply printing the ``repr()`` result).
150 """
233 """
234
235 # We want to support ``foo`` and ``foo()`` in pipeline expression:
236 # So we implement the required operators (``|`` and ``+``) in the metaclass,
237 # instantiate the class and forward the operator to the instance
151 class __metaclass__(type):
238 class __metaclass__(type):
152 def __iter__(self):
239 def __iter__(self):
153 return iter(self())
240 return iter(self())
@@ -174,18 +261,23 b' class Table(object):'
174 return False
261 return False
175
262
176 def __or__(self, other):
263 def __or__(self, other):
264 # autoinstantiate right hand side
177 if isinstance(other, type) and issubclass(other, (Table, Display)):
265 if isinstance(other, type) and issubclass(other, (Table, Display)):
178 other = other()
266 other = other()
267 # treat simple strings and functions as ``ieval`` instances
179 elif not isinstance(other, Display) and not isinstance(other, Table):
268 elif not isinstance(other, Display) and not isinstance(other, Table):
180 other = ieval(other)
269 other = ieval(other)
270 # forward operations to the right hand side
181 return other.__ror__(self)
271 return other.__ror__(self)
182
272
183 def __add__(self, other):
273 def __add__(self, other):
274 # autoinstantiate right hand side
184 if isinstance(other, type) and issubclass(other, Table):
275 if isinstance(other, type) and issubclass(other, Table):
185 other = other()
276 other = other()
186 return ichain(self, other)
277 return ichain(self, other)
187
278
188 def __radd__(self, other):
279 def __radd__(self, other):
280 # autoinstantiate left hand side
189 if isinstance(other, type) and issubclass(other, Table):
281 if isinstance(other, type) and issubclass(other, Table):
190 other = other()
282 other = other()
191 return ichain(other, self)
283 return ichain(other, self)
@@ -206,6 +298,7 b' class Pipe(Table):'
206 return input | self()
298 return input | self()
207
299
208 def __ror__(self, input):
300 def __ror__(self, input):
301 # autoinstantiate left hand side
209 if isinstance(input, type) and issubclass(input, Table):
302 if isinstance(input, type) and issubclass(input, Table):
210 input = input()
303 input = input()
211 self.input = input
304 self.input = input
@@ -249,9 +342,7 b' def _attrname(name):'
249 def xrepr(item, mode):
342 def xrepr(item, mode):
250 try:
343 try:
251 func = item.__xrepr__
344 func = item.__xrepr__
252 except (KeyboardInterrupt, SystemExit):
345 except AttributeError:
253 raise
254 except Exception:
255 return repr(item)
346 return repr(item)
256 else:
347 else:
257 return func(mode)
348 return func(mode)
@@ -287,7 +378,7 b' def xiter(item, mode):'
287 def items(item):
378 def items(item):
288 fields = ("key", "value")
379 fields = ("key", "value")
289 for key in sorted(item.__dict__):
380 for key in sorted(item.__dict__):
290 yield Fields(fields, key, getattr(item, key))
381 yield Fields(fields, key=key, value=getattr(item, key))
291 return items(item)
382 return items(item)
292 elif isinstance(item, basestring):
383 elif isinstance(item, basestring):
293 if not len(item):
384 if not len(item):
@@ -526,7 +617,7 b' class ifile(object):'
526 "size", "blocks", "blksize", "isdir", "islink",
617 "size", "blocks", "blksize", "isdir", "islink",
527 "mimetype", "encoding"
618 "mimetype", "encoding"
528 )
619 )
529 return ("name","type", "size", "access", "owner", "group", "mdate")
620 return ("name", "type", "size", "access", "owner", "group", "mdate")
530
621
531 def __xrepr__(self, mode):
622 def __xrepr__(self, mode):
532 if mode == "header" or mode == "footer":
623 if mode == "header" or mode == "footer":
@@ -1085,6 +1176,7 b' class idump(Display):'
1085 row[attrname] = (value, text)
1176 row[attrname] = (value, text)
1086 rows.append(row)
1177 rows.append(row)
1087
1178
1179 stream.write("\n")
1088 for (i, attrname) in enumerate(self.attrs):
1180 for (i, attrname) in enumerate(self.attrs):
1089 stream.write(_attrname(attrname))
1181 stream.write(_attrname(attrname))
1090 spc = colwidths[attrname] - len(_attrname(attrname))
1182 spc = colwidths[attrname] - len(_attrname(attrname))
@@ -1157,7 +1249,16 b' class idump(Display):'
1157
1249
1158
1250
1159 class XMode(object):
1251 class XMode(object):
1252 """
1253 An ``XMode`` object describes one enter mode available for an object
1254 """
1160 def __init__(self, object, mode, title=None, description=None):
1255 def __init__(self, object, mode, title=None, description=None):
1256 """
1257 Create a new ``XMode`` object for the object ``object``. This object
1258 must support the enter mode ``mode`` (i.e. ``object.__xiter__(mode)``
1259 must return an iterable). ``title`` and ``description`` will be
1260 displayed in the browser when selecting among the available modes.
1261 """
1161 self.object = object
1262 self.object = object
1162 self.mode = mode
1263 self.mode = mode
1163 self.title = title
1264 self.title = title
@@ -1234,7 +1335,7 b' pagedown'
1234 Move the cursor down one page (minus overlap).
1335 Move the cursor down one page (minus overlap).
1235
1336
1236 pageup
1337 pageup
1237 Move the cursor up one page.
1338 Move the cursor up one page (minus overlap).
1238
1339
1239 left
1340 left
1240 Move the cursor left.
1341 Move the cursor left.
@@ -1257,8 +1358,8 b' pickattr'
1257 'Pick' the attribute under the cursor (i.e. the row/column the cursor is on).
1358 'Pick' the attribute under the cursor (i.e. the row/column the cursor is on).
1258
1359
1259 pickallattrs
1360 pickallattrs
1260 Pick' the complete column under the cursor (i.e. the attribute under the cursor
1361 Pick' the complete column under the cursor (i.e. the attribute under the cursor)
1261 from all currently fetched objects). The attributes will be returned as a list.
1362 from all currently fetched objects. These attributes will be returned as a list.
1262
1363
1263 tooglemark
1364 tooglemark
1264 Mark/unmark the object under the cursor. Marked objects have a '!' after the
1365 Mark/unmark the object under the cursor. Marked objects have a '!' after the
@@ -1269,16 +1370,17 b' pickmarked'
1269
1370
1270 pickmarkedattr
1371 pickmarkedattr
1271 'Pick' the attribute under the cursor from all marked objects (This returns a
1372 'Pick' the attribute under the cursor from all marked objects (This returns a
1272 list)
1373 list).
1273
1374
1274 enterdefault
1375 enterdefault
1275 Enter the object under the cursor. (what this mean depends on the object
1376 Enter the object under the cursor. (what this mean depends on the object
1276 itself). This opens a new browser 'level'.
1377 itself (i.e. how it implements the '__xiter__' method). This opens a new browser
1378 'level'.
1277
1379
1278 enter
1380 enter
1279 Enter the object under the cursor. If the object provides different enter modes
1381 Enter the object under the cursor. If the object provides different enter modes
1280 a menu of all modes will be presented, choice one and enter it (via the 'enter'
1382 a menu of all modes will be presented; choice one and enter it (via the 'enter'
1281 or 'enterdefault' command),
1383 or 'enterdefault' command).
1282
1384
1283 enterattr
1385 enterattr
1284 Enter the attribute under the cursor.
1386 Enter the attribute under the cursor.
@@ -1289,7 +1391,7 b' Leave the current browser level and go back to the previous one.'
1289 detail
1391 detail
1290 Show a detail view of the object under the cursor. This shows the name, type,
1392 Show a detail view of the object under the cursor. This shows the name, type,
1291 doc string and value of the object attributes (and it might show more attributes
1393 doc string and value of the object attributes (and it might show more attributes
1292 than in the list view; depending on the object).
1394 than in the list view, depending on the object).
1293
1395
1294 markrange
1396 markrange
1295 Mark all objects from the last marked object before the current cursor position
1397 Mark all objects from the last marked object before the current cursor position
@@ -1310,18 +1412,29 b' This screen.'
1310
1412
1311 if curses is not None:
1413 if curses is not None:
1312 class UnassignedKeyError(Exception):
1414 class UnassignedKeyError(Exception):
1313 pass
1415 """
1416 Exception that is used for reporting unassigned keys.
1417 """
1314
1418
1315
1419
1316 class UnknownCommandError(Exception):
1420 class UnknownCommandError(Exception):
1317 pass
1421 """
1422 Exception that is used for reporting unknown command (this should never
1423 happen).
1424 """
1318
1425
1319
1426
1320 class CommandError(Exception):
1427 class CommandError(Exception):
1321 pass
1428 """
1429 Exception that is used for reporting that a command can't be executed.
1430 """
1322
1431
1323
1432
1324 class Style(object):
1433 class Style(object):
1434 """
1435 Store foreground color, background color and attribute (bold, underlined
1436 etc.) for ``curses``.
1437 """
1325 __slots__ = ("fg", "bg", "attrs")
1438 __slots__ = ("fg", "bg", "attrs")
1326
1439
1327 def __init__(self, fg, bg, attrs=0):
1440 def __init__(self, fg, bg, attrs=0):
@@ -1331,6 +1444,8 b' if curses is not None:'
1331
1444
1332
1445
1333 class _BrowserCachedItem(object):
1446 class _BrowserCachedItem(object):
1447 # This is used internally by ``ibrowse`` to store a item together with its
1448 # marked status.
1334 __slots__ = ("item", "marked")
1449 __slots__ = ("item", "marked")
1335
1450
1336 def __init__(self, item):
1451 def __init__(self, item):
@@ -1339,6 +1454,7 b' if curses is not None:'
1339
1454
1340
1455
1341 class _BrowserHelp(object):
1456 class _BrowserHelp(object):
1457 # This is used internally by ``ibrowse`` for displaying the help screen.
1342 def __init__(self, browser):
1458 def __init__(self, browser):
1343 self.browser = browser
1459 self.browser = browser
1344
1460
@@ -1378,6 +1494,10 b' if curses is not None:'
1378
1494
1379
1495
1380 class _BrowserLevel(object):
1496 class _BrowserLevel(object):
1497 # This is used internally to store the state (iterator, fetch items,
1498 # position of cursor and screen, etc.) of one browser level
1499 # An ``ibrowse`` object keeps multiple ``_BrowserLevel`` objects in
1500 # a stack.
1381 def __init__(self, browser, input, iterator, mainsizey, *attrs):
1501 def __init__(self, browser, input, iterator, mainsizey, *attrs):
1382 self.browser = browser
1502 self.browser = browser
1383 self.input = input
1503 self.input = input
@@ -1407,6 +1527,7 b' if curses is not None:'
1407 self.calcdisplayattr()
1527 self.calcdisplayattr()
1408
1528
1409 def fetch(self, count):
1529 def fetch(self, count):
1530 # Try to fill ``self.items`` with at least ``count`` objects.
1410 have = len(self.items)
1531 have = len(self.items)
1411 while not self.exhausted and have < count:
1532 while not self.exhausted and have < count:
1412 try:
1533 try:
@@ -1419,7 +1540,11 b' if curses is not None:'
1419 self.items.append(_BrowserCachedItem(item))
1540 self.items.append(_BrowserCachedItem(item))
1420
1541
1421 def calcdisplayattrs(self):
1542 def calcdisplayattrs(self):
1543 # Calculate which attributes are available from the objects that are
1544 # currently visible on screen (and store it in ``self.displayattrs``)
1422 attrnames = set()
1545 attrnames = set()
1546 # If the browser object specifies a fixed list of attributes,
1547 # simply use it.
1423 if self.attrs:
1548 if self.attrs:
1424 self.displayattrs = self.attrs
1549 self.displayattrs = self.attrs
1425 else:
1550 else:
@@ -1432,6 +1557,10 b' if curses is not None:'
1432 attrnames.add(attrname)
1557 attrnames.add(attrname)
1433
1558
1434 def getrow(self, i):
1559 def getrow(self, i):
1560 # Return a dictinary with the attributes for the object
1561 # ``self.items[i]``. Attribute names are taken from
1562 # ``self.displayattrs`` so ``calcdisplayattrs()`` must have been
1563 # called before.
1435 row = {}
1564 row = {}
1436 item = self.items[i].item
1565 item = self.items[i].item
1437 for attrname in self.displayattrs:
1566 for attrname in self.displayattrs:
@@ -1448,7 +1577,11 b' if curses is not None:'
1448 return row
1577 return row
1449
1578
1450 def calcwidths(self):
1579 def calcwidths(self):
1451 # Recalculate the displayed fields and their width
1580 # Recalculate the displayed fields and their width.
1581 # ``calcdisplayattrs()'' must have been called and the cache
1582 # for attributes of the objects on screen (``self.displayrows``)
1583 # must have been filled. This returns a dictionary mapping
1584 # colmn names to width.
1452 self.colwidths = {}
1585 self.colwidths = {}
1453 for row in self.displayrows:
1586 for row in self.displayrows:
1454 for attrname in self.displayattrs:
1587 for attrname in self.displayattrs:
@@ -1467,7 +1600,8 b' if curses is not None:'
1467 self.datasizex = sum(self.colwidths.itervalues()) + len(self.colwidths)
1600 self.datasizex = sum(self.colwidths.itervalues()) + len(self.colwidths)
1468
1601
1469 def calcdisplayattr(self):
1602 def calcdisplayattr(self):
1470 # Find out on which attribute the cursor is on
1603 # Find out on which attribute the cursor is on and store this
1604 # information in ``self.displayattr``.
1471 pos = 0
1605 pos = 0
1472 for attrname in self.displayattrs:
1606 for attrname in self.displayattrs:
1473 if pos+self.colwidths[attrname] >= self.curx:
1607 if pos+self.colwidths[attrname] >= self.curx:
@@ -1478,6 +1612,10 b' if curses is not None:'
1478 self.displayattr = None
1612 self.displayattr = None
1479
1613
1480 def moveto(self, x, y, refresh=False):
1614 def moveto(self, x, y, refresh=False):
1615 # Move the cursor to the position ``(x,y)`` (in data coordinates,
1616 # not in screen coordinates). If ``refresh`` is true, all cached
1617 # values will be recalculated (e.g. because the list has been
1618 # resorted to screen position etc. are no longer valid).
1481 olddatastarty = self.datastarty
1619 olddatastarty = self.datastarty
1482 oldx = self.curx
1620 oldx = self.curx
1483 oldy = self.cury
1621 oldy = self.cury
@@ -1506,7 +1644,6 b' if curses is not None:'
1506 endy = min(self.datastarty+self.mainsizey, len(self.items))
1644 endy = min(self.datastarty+self.mainsizey, len(self.items))
1507 self.displayrows = map(self.getrow, xrange(self.datastarty, endy))
1645 self.displayrows = map(self.getrow, xrange(self.datastarty, endy))
1508 self.calcwidths()
1646 self.calcwidths()
1509
1510 # Did we scroll vertically => update displayrows
1647 # Did we scroll vertically => update displayrows
1511 # and various other attributes
1648 # and various other attributes
1512 elif self.datastarty != olddatastarty:
1649 elif self.datastarty != olddatastarty:
@@ -1690,27 +1827,61 b' if curses is not None:'
1690 }
1827 }
1691
1828
1692 def __init__(self, *attrs):
1829 def __init__(self, *attrs):
1830 """
1831 Create a new browser. If ``attrs`` is not empty, it is the list
1832 of attributes that will be displayed in the browser, otherwise
1833 these will be determined by the objects on screen.
1834 """
1693 self.attrs = attrs
1835 self.attrs = attrs
1836
1837 # Stack of browser levels
1694 self.levels = []
1838 self.levels = []
1695 self.stepx = 1. # how many colums to scroll
1839 # how many colums to scroll (Changes when accelerating)
1696 self.stepy = 1. # how many rows to scroll
1840 self.stepx = 1.
1697 self._dobeep = True # Beep on the edges of the data area?
1841
1842 # how many rows to scroll (Changes when accelerating)
1843 self.stepy = 1.
1844
1845 # Beep on the edges of the data area? (Will be set to ``False``
1846 # once the cursor hits the edge of the screen, so we don't get
1847 # multiple beeps).
1848 self._dobeep = True
1849
1850 # Cache for registered ``curses`` colors.
1698 self._colors = {}
1851 self._colors = {}
1699 self._maxcolor = 1
1852 self._maxcolor = 1
1700 self._headerlines = 1 # How many header lines do we want to paint (the numbers of levels we have, but with an upper bound)
1853
1701 self._firstheaderline = 0 # Index of first header line
1854 # How many header lines do we want to paint (the numbers of levels
1702 self.scr = None # curses window
1855 # we have, but with an upper bound)
1703 self._report = None # report in the footer line
1856 self._headerlines = 1
1857
1858 # Index of first header line
1859 self._firstheaderline = 0
1860
1861 # curses window
1862 self.scr = None
1863 # report in the footer line (error, executed command etc.)
1864 self._report = None
1704
1865
1705 def nextstepx(self, step):
1866 def nextstepx(self, step):
1867 """
1868 Accelerate horizontally.
1869 """
1706 return max(1., min(step*self.acceleratex,
1870 return max(1., min(step*self.acceleratex,
1707 self.maxspeedx*self.levels[-1].mainsizex))
1871 self.maxspeedx*self.levels[-1].mainsizex))
1708
1872
1709 def nextstepy(self, step):
1873 def nextstepy(self, step):
1874 """
1875 Accelerate vertically.
1876 """
1710 return max(1., min(step*self.acceleratey,
1877 return max(1., min(step*self.acceleratey,
1711 self.maxspeedy*self.levels[-1].mainsizey))
1878 self.maxspeedy*self.levels[-1].mainsizey))
1712
1879
1713 def getstyle(self, style):
1880 def getstyle(self, style):
1881 """
1882 Register the ``style`` with ``curses`` or get it from the cache,
1883 if it has been registered before.
1884 """
1714 try:
1885 try:
1715 return self._colors[style.fg, style.bg] | style.attrs
1886 return self._colors[style.fg, style.bg] | style.attrs
1716 except KeyError:
1887 except KeyError:
@@ -1722,12 +1893,20 b' if curses is not None:'
1722 return c
1893 return c
1723
1894
1724 def addstr(self, y, x, begx, endx, s, style):
1895 def addstr(self, y, x, begx, endx, s, style):
1896 """
1897 A version of ``curses.addstr()`` that can handle ``x`` coordinates
1898 that are outside the screen.
1899 """
1725 s2 = s[max(0, begx-x):max(0, endx-x)]
1900 s2 = s[max(0, begx-x):max(0, endx-x)]
1726 if s2:
1901 if s2:
1727 self.scr.addstr(y, max(x, begx), s2, self.getstyle(style))
1902 self.scr.addstr(y, max(x, begx), s2, self.getstyle(style))
1728 return len(s)
1903 return len(s)
1729
1904
1730 def format(self, value):
1905 def format(self, value):
1906 """
1907 Formats one attribute and returns an ``(alignment, string, style)``
1908 tuple.
1909 """
1731 if value is None:
1910 if value is None:
1732 return (-1, repr(value), self.style_type_none)
1911 return (-1, repr(value), self.style_type_none)
1733 elif isinstance(value, str):
1912 elif isinstance(value, str):
@@ -1769,6 +1948,8 b' if curses is not None:'
1769 return (-1, repr(value), self.style_default)
1948 return (-1, repr(value), self.style_default)
1770
1949
1771 def _calcheaderlines(self, levels):
1950 def _calcheaderlines(self, levels):
1951 # Calculate how many headerlines do we have to display, if we have
1952 # ``levels`` browser levels
1772 if levels is None:
1953 if levels is None:
1773 levels = len(self.levels)
1954 levels = len(self.levels)
1774 self._headerlines = min(self.maxheaders, levels)
1955 self._headerlines = min(self.maxheaders, levels)
@@ -1782,9 +1963,17 b' if curses is not None:'
1782 return Style(style.fg, style.bg, style.attrs | curses.A_BOLD)
1963 return Style(style.fg, style.bg, style.attrs | curses.A_BOLD)
1783
1964
1784 def report(self, msg):
1965 def report(self, msg):
1966 """
1967 Store the message ``msg`` for display below the footer line. This
1968 will be displayed as soon as the screen is redrawn.
1969 """
1785 self._report = msg
1970 self._report = msg
1786
1971
1787 def enter(self, item, mode, *attrs):
1972 def enter(self, item, mode, *attrs):
1973 """
1974 Enter the object ``item`` in the mode ``mode``. If ``attrs`` is
1975 specified, it will be used as a fixed list of attributes to display.
1976 """
1788 try:
1977 try:
1789 iterator = xiter(item, mode)
1978 iterator = xiter(item, mode)
1790 except (KeyboardInterrupt, SystemExit):
1979 except (KeyboardInterrupt, SystemExit):
@@ -1804,6 +1993,10 b' if curses is not None:'
1804 self.levels.append(level)
1993 self.levels.append(level)
1805
1994
1806 def keylabel(self, keycode):
1995 def keylabel(self, keycode):
1996 """
1997 Return a pretty name for the ``curses`` key ``keycode`` (used in the
1998 help screen and in reports about unassigned keys).
1999 """
1807 if keycode <= 0xff:
2000 if keycode <= 0xff:
1808 specialsnames = {
2001 specialsnames = {
1809 ord("\n"): "RETURN",
2002 ord("\n"): "RETURN",
@@ -1821,6 +2014,9 b' if curses is not None:'
1821 return str(keycode)
2014 return str(keycode)
1822
2015
1823 def cmd_help(self):
2016 def cmd_help(self):
2017 """
2018 The help command
2019 """
1824 for level in self.levels:
2020 for level in self.levels:
1825 if isinstance(level.input, _BrowserHelp):
2021 if isinstance(level.input, _BrowserHelp):
1826 curses.beep()
2022 curses.beep()
@@ -1830,6 +2026,10 b' if curses is not None:'
1830 self.enter(_BrowserHelp(self), "default")
2026 self.enter(_BrowserHelp(self), "default")
1831
2027
1832 def _dodisplay(self, scr):
2028 def _dodisplay(self, scr):
2029 """
2030 This method is the workhorse of the browser. It handles screen
2031 drawing and the keyboard.
2032 """
1833 self.scr = scr
2033 self.scr = scr
1834 curses.halfdelay(1)
2034 curses.halfdelay(1)
1835 footery = 2
2035 footery = 2
@@ -2144,6 +2344,7 b' if curses is not None:'
2144 defaultdisplay = ibrowse
2344 defaultdisplay = ibrowse
2145 __all__.append("ibrowse")
2345 __all__.append("ibrowse")
2146 else:
2346 else:
2347 # No curses (probably Windows) => use ``idump`` as the default display.
2147 defaultdisplay = idump
2348 defaultdisplay = idump
2148
2349
2149
2350
General Comments 0
You need to be logged in to leave comments. Login now