Show More
This diff has been collapsed as it changes many lines, (750 lines changed) Show them Hide them | |||||
@@ -8,7 +8,7 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 |
>>> ienv | isort(" |
|
11 | >>> ienv | isort("key.lower()") | |
12 |
|
12 | |||
13 | This gives a listing of all environment variables sorted by name. |
|
13 | This gives a listing of all environment variables sorted by name. | |
14 |
|
14 | |||
@@ -46,13 +46,22 b' three extensions points (all of them optional):' | |||||
46 | be being displayed. The global function ``xattrs()`` implements this |
|
46 | be being displayed. The global function ``xattrs()`` implements this | |
47 | functionality. |
|
47 | functionality. | |
48 |
|
48 | |||
49 |
* When an object ``foo`` is displayed in the header |
|
49 | * When an object ``foo`` is displayed in the header, footer or table cell of the | |
50 | ``foo.__xrepr__("header")`` (or ``foo.__xrepr__("footer")``) is called. |
|
50 | browser ``foo.__xrepr__(mode)`` is called. Mode can be ``"header"`` or | |
51 | Currently only ``"header"`` and ``"footer"`` are used as the mode argument. |
|
51 | ``"footer"`` for the header or footer line and ``"cell"`` for a table cell. | |
52 | When the method doesn't recognize the mode argument, it should fall back to |
|
52 | ``__xrepr__()```must return an iterable (e.g. by being a generator) which | |
53 | the ``repr()`` output. If the method ``__xrepr__()`` isn't defined the browser |
|
53 | produces the following items: The first item should be a tuple containing | |
54 | falls back to ``repr()``. The global function ``xrepr()`` implements this |
|
54 | the alignment (-1 left aligned, 0 centered and 1 right aligned) and whether | |
55 | functionality. |
|
55 | the complete output must be displayed or if the browser is allowed to stop | |
|
56 | output after enough text has been produced (e.g. a syntax highlighted text | |||
|
57 | line would use ``True``, but for a large data structure (i.e. a nested list, | |||
|
58 | tuple or dictionary) ``False`` would be used). The other output ``__xrepr__()`` | |||
|
59 | may produce is tuples of ``Style```objects and text (which contain the text | |||
|
60 | representation of the object). If ``__xrepr__()`` recursively outputs a data | |||
|
61 | structure the function ``xrepr(object, mode)`` can be used and ``"default"`` | |||
|
62 | must be passed as the mode in these calls. This in turn calls the | |||
|
63 | ``__xrepr__()`` method on ``object`` (or uses ``repr(object)`` as the string | |||
|
64 | representation if ``__xrepr__()`` doesn't exist. | |||
56 |
|
65 | |||
57 | * Objects that can be iterated by ``Pipe``s must implement the method |
|
66 | * Objects that can be iterated by ``Pipe``s must implement the method | |
58 | ``__xiter__(self, mode)``. ``mode`` can take the following values: |
|
67 | ``__xiter__(self, mode)``. ``mode`` can take the following values: | |
@@ -71,7 +80,7 b' three extensions points (all of them optional):' | |||||
71 | possible to use dictionaries and modules in pipeline expressions, for example: |
|
80 | possible to use dictionaries and modules in pipeline expressions, for example: | |
72 |
|
81 | |||
73 | >>> import sys |
|
82 | >>> import sys | |
74 |
>>> sys | ifilter("isinstance( |
|
83 | >>> sys | ifilter("isinstance(value, int)") | idump | |
75 | key |value |
|
84 | key |value | |
76 | api_version| 1012 |
|
85 | api_version| 1012 | |
77 | dllhandle | 503316480 |
|
86 | dllhandle | 503316480 | |
@@ -82,13 +91,12 b' three extensions points (all of them optional):' | |||||
82 | ... |
|
91 | ... | |
83 |
|
92 | |||
84 | Note: The expression strings passed to ``ifilter()`` and ``isort()`` can |
|
93 | Note: The expression strings passed to ``ifilter()`` and ``isort()`` can | |
85 |
refer to the object to be filtered or sorted via the variable ``_`` |
|
94 | refer to the object to be filtered or sorted via the variable ``_`` and to any | |
86 | running under Python 2.4 it's also possible to refer to the attributes of |
|
95 | of the attributes of the object, i.e.: | |
87 | the object directy, i.e.: |
|
|||
88 |
|
96 | |||
89 | >>> sys.modules | ifilter("_.value is not None") | isort("_.key.lower()") |
|
97 | >>> sys.modules | ifilter("_.value is not None") | isort("_.key.lower()") | |
90 |
|
98 | |||
91 | can be replaced with |
|
99 | does the same as | |
92 |
|
100 | |||
93 | >>> sys.modules | ifilter("value is not None") | isort("key.lower()") |
|
101 | >>> sys.modules | ifilter("value is not None") | isort("key.lower()") | |
94 |
|
102 | |||
@@ -105,7 +113,7 b' three extensions points (all of them optional):' | |||||
105 | maxunicode |0xffff |
|
113 | maxunicode |0xffff | |
106 | """ |
|
114 | """ | |
107 |
|
115 | |||
108 | import sys, os, os.path, stat, glob, new, csv, datetime |
|
116 | import sys, os, os.path, stat, glob, new, csv, datetime, types | |
109 | import textwrap, itertools, mimetypes |
|
117 | import textwrap, itertools, mimetypes | |
110 |
|
118 | |||
111 | try: # Python 2.3 compatibility |
|
119 | try: # Python 2.3 compatibility | |
@@ -164,8 +172,6 b' class _AttrNamespace(object):' | |||||
164 | """ |
|
172 | """ | |
165 | Internal helper class that is used for providing a namespace for evaluating |
|
173 | Internal helper class that is used for providing a namespace for evaluating | |
166 | expressions containg attribute names of an object. |
|
174 | expressions containg attribute names of an object. | |
167 |
|
||||
168 | This class can only be used with Python 2.4. |
|
|||
169 | """ |
|
175 | """ | |
170 | def __init__(self, wrapped): |
|
176 | def __init__(self, wrapped): | |
171 | self.wrapped = wrapped |
|
177 | self.wrapped = wrapped | |
@@ -179,13 +185,35 b' class _AttrNamespace(object):' | |||||
179 | raise KeyError(name) |
|
185 | raise KeyError(name) | |
180 |
|
186 | |||
181 | # Python 2.3 compatibility |
|
187 | # Python 2.3 compatibility | |
182 | # fall back to a real dictionary (containing just the object itself) if we can't |
|
188 | # use eval workaround to find out which names are used in the | |
183 | # use the _AttrNamespace class in eval() |
|
189 | # eval string and put them into the locals. This works for most | |
|
190 | # normal uses case, bizarre ones like accessing the locals() | |||
|
191 | # will fail | |||
184 | try: |
|
192 | try: | |
185 | eval("_", None, _AttrNamespace(None)) |
|
193 | eval("_", None, _AttrNamespace(None)) | |
186 | except TypeError: |
|
194 | except TypeError: | |
187 | def _AttrNamespace(wrapped): |
|
195 | real_eval = eval | |
188 | return {"_": wrapped} |
|
196 | def eval(codestring, _globals, _locals): | |
|
197 | """ | |||
|
198 | eval(source[, globals[, locals]]) -> value | |||
|
199 | ||||
|
200 | Evaluate the source in the context of globals and locals. | |||
|
201 | The source may be a string representing a Python expression | |||
|
202 | or a code object as returned by compile(). | |||
|
203 | The globals must be a dictionary and locals can be any mappping. | |||
|
204 | ||||
|
205 | This function is a workaround for the shortcomings of | |||
|
206 | Python 2.3's eval. | |||
|
207 | """ | |||
|
208 | ||||
|
209 | code = compile(codestring, "_eval", "eval") | |||
|
210 | newlocals = {} | |||
|
211 | for name in code.co_names: | |||
|
212 | try: | |||
|
213 | newlocals[name] = _locals[name] | |||
|
214 | except KeyError: | |||
|
215 | pass | |||
|
216 | return real_eval(code, _globals, newlocals) | |||
189 |
|
217 | |||
190 |
|
218 | |||
191 | _default = object() |
|
219 | _default = object() | |
@@ -339,21 +367,211 b' def _attrname(name):' | |||||
339 | return str(name) |
|
367 | return str(name) | |
340 |
|
368 | |||
341 |
|
369 | |||
|
370 | class Style(object): | |||
|
371 | """ | |||
|
372 | Store foreground color, background color and attribute (bold, underlined | |||
|
373 | etc.). | |||
|
374 | """ | |||
|
375 | __slots__ = ("fg", "bg", "attrs") | |||
|
376 | ||||
|
377 | def __init__(self, fg, bg, attrs=0): | |||
|
378 | self.fg = fg | |||
|
379 | self.bg = bg | |||
|
380 | self.attrs = attrs | |||
|
381 | ||||
|
382 | ||||
|
383 | COLOR_BLACK = 0 | |||
|
384 | COLOR_RED = 1 | |||
|
385 | COLOR_GREEN = 2 | |||
|
386 | COLOR_YELLOW = 3 | |||
|
387 | COLOR_BLUE = 4 | |||
|
388 | COLOR_MAGENTA = 5 | |||
|
389 | COLOR_CYAN = 6 | |||
|
390 | COLOR_WHITE = 7 | |||
|
391 | ||||
|
392 | A_BLINK = 1<<0 # Blinking text | |||
|
393 | A_BOLD = 1<<1 # Extra bright or bold text | |||
|
394 | A_DIM = 1<<2 # Half bright text | |||
|
395 | A_REVERSE = 1<<3 # Reverse-video text | |||
|
396 | A_STANDOUT = 1<<4 # The best highlighting mode available | |||
|
397 | A_UNDERLINE = 1<<5 # Underlined text | |||
|
398 | ||||
|
399 | if curses is not None: | |||
|
400 | # This is probably just range(8) | |||
|
401 | COLOR2CURSES = [ | |||
|
402 | COLOR_BLACK, | |||
|
403 | COLOR_RED, | |||
|
404 | COLOR_GREEN, | |||
|
405 | COLOR_YELLOW, | |||
|
406 | COLOR_BLUE, | |||
|
407 | COLOR_MAGENTA, | |||
|
408 | COLOR_CYAN, | |||
|
409 | COLOR_WHITE, | |||
|
410 | ] | |||
|
411 | ||||
|
412 | A2CURSES = { | |||
|
413 | A_BLINK: curses.A_BLINK, | |||
|
414 | A_BOLD: curses.A_BOLD, | |||
|
415 | A_DIM: curses.A_DIM, | |||
|
416 | A_REVERSE: curses.A_REVERSE, | |||
|
417 | A_STANDOUT: curses.A_STANDOUT, | |||
|
418 | A_UNDERLINE: curses.A_UNDERLINE, | |||
|
419 | } | |||
|
420 | ||||
|
421 | ||||
|
422 | # default style | |||
|
423 | style_default = Style(COLOR_WHITE, COLOR_BLACK) | |||
|
424 | ||||
|
425 | # Styles for datatypes | |||
|
426 | style_type_none = Style(COLOR_MAGENTA, COLOR_BLACK) | |||
|
427 | style_type_bool = Style(COLOR_MAGENTA, COLOR_BLACK) | |||
|
428 | style_type_number = Style(COLOR_YELLOW, COLOR_BLACK) | |||
|
429 | style_type_datetime = Style(COLOR_CYAN, COLOR_BLACK) | |||
|
430 | ||||
|
431 | # Style for URLs and filenames | |||
|
432 | style_url = Style(COLOR_GREEN, COLOR_BLACK) | |||
|
433 | ||||
|
434 | # Style for ellipsis (when an output has been shortened | |||
|
435 | style_ellisis = Style(COLOR_RED, COLOR_BLACK) | |||
|
436 | ||||
|
437 | # Style for displaying ewxceptions | |||
|
438 | style_error = Style(COLOR_RED, COLOR_BLACK) | |||
|
439 | ||||
|
440 | ||||
342 | def xrepr(item, mode): |
|
441 | def xrepr(item, mode): | |
343 | try: |
|
442 | try: | |
344 | func = item.__xrepr__ |
|
443 | func = item.__xrepr__ | |
345 | except AttributeError: |
|
444 | except AttributeError: | |
346 | return repr(item) |
|
445 | pass | |
347 | else: |
|
446 | else: | |
348 |
|
|
447 | for x in func(mode): | |
|
448 | yield x | |||
|
449 | return | |||
|
450 | if item is None: | |||
|
451 | yield (-1, True) | |||
|
452 | yield (style_type_none, repr(item)) | |||
|
453 | elif isinstance(item, bool): | |||
|
454 | yield (-1, True) | |||
|
455 | yield (style_type_bool, repr(item)) | |||
|
456 | elif isinstance(item, str): | |||
|
457 | yield (-1, True) | |||
|
458 | if mode == "cell": | |||
|
459 | yield (style_default, repr(item.expandtabs(tab))[1:-1]) | |||
|
460 | else: | |||
|
461 | yield (style_default, repr(item)) | |||
|
462 | elif isinstance(item, unicode): | |||
|
463 | yield (-1, True) | |||
|
464 | if mode == "cell": | |||
|
465 | yield (style_default, repr(item.expandtabs(tab))[2:-1]) | |||
|
466 | else: | |||
|
467 | yield (style_default, repr(item)) | |||
|
468 | elif isinstance(item, (int, long, float)): | |||
|
469 | yield (1, True) | |||
|
470 | yield (style_type_number, repr(item)) | |||
|
471 | elif isinstance(item, complex): | |||
|
472 | yield (-1, True) | |||
|
473 | yield (style_type_number, repr(item)) | |||
|
474 | elif isinstance(item, datetime.datetime): | |||
|
475 | yield (-1, True) | |||
|
476 | if mode == "cell": | |||
|
477 | # Don't use strftime() here, as this requires year >= 1900 | |||
|
478 | yield (style_type_datetime, | |||
|
479 | "%04d-%02d-%02d %02d:%02d:%02d.%06d" % \ | |||
|
480 | (item.year, item.month, item.day, | |||
|
481 | item.hour, item.minute, item.second, | |||
|
482 | item.microsecond), | |||
|
483 | ) | |||
|
484 | else: | |||
|
485 | yield (style_type_datetime, repr(item)) | |||
|
486 | elif isinstance(item, datetime.date): | |||
|
487 | yield (-1, True) | |||
|
488 | if mode == "cell": | |||
|
489 | yield (style_type_datetime, | |||
|
490 | "%04d-%02d-%02d" % (item.year, item.month, item.day)) | |||
|
491 | else: | |||
|
492 | yield (style_type_datetime, repr(item)) | |||
|
493 | elif isinstance(item, datetime.time): | |||
|
494 | yield (-1, True) | |||
|
495 | if mode == "cell": | |||
|
496 | yield (style_type_datetime, | |||
|
497 | "%02d:%02d:%02d.%06d" % \ | |||
|
498 | (item.hour, item.minute, item.second, item.microsecond)) | |||
|
499 | else: | |||
|
500 | yield (style_type_datetime, repr(item)) | |||
|
501 | elif isinstance(item, datetime.timedelta): | |||
|
502 | yield (-1, True) | |||
|
503 | yield (style_type_datetime, repr(item)) | |||
|
504 | elif isinstance(item, Exception): | |||
|
505 | yield (-1, True) | |||
|
506 | if item.__class__.__module__ == "exceptions": | |||
|
507 | classname = item.__class__.__name__ | |||
|
508 | else: | |||
|
509 | classname = "%s.%s: %s" % \ | |||
|
510 | (item.__class__.__module__, item.__class__.__name__) | |||
|
511 | if mode == "header" or mode == "footer": | |||
|
512 | yield (style_error, "%s: %s" % (classname, item)) | |||
|
513 | else: | |||
|
514 | yield (style_error, classname) | |||
|
515 | elif isinstance(item, (list, tuple)): | |||
|
516 | yield (-1, False) | |||
|
517 | if mode == "header" or mode == "footer": | |||
|
518 | if item.__class__.__module__ == "__builtin__": | |||
|
519 | classname = item.__class__.__name__ | |||
|
520 | else: | |||
|
521 | classname = "%s.%s" % \ | |||
|
522 | (item.__class__.__module__,item.__class__.__name__) | |||
|
523 | yield (style_default, | |||
|
524 | "<%s object with %d items at 0x%x>" % \ | |||
|
525 | (classname, len(item), id(item))) | |||
|
526 | else: | |||
|
527 | if isinstance(item, list): | |||
|
528 | yield (style_default, "[") | |||
|
529 | end = "]" | |||
|
530 | else: | |||
|
531 | yield (style_default, "(") | |||
|
532 | end = ")" | |||
|
533 | for (i, subitem) in enumerate(item): | |||
|
534 | if i: | |||
|
535 | yield (style_default, ", ") | |||
|
536 | for part in xrepr(subitem, "default"): | |||
|
537 | yield part | |||
|
538 | yield (style_default, end) | |||
|
539 | elif isinstance(item, (dict, types.DictProxyType)): | |||
|
540 | yield (-1, False) | |||
|
541 | if mode == "header" or mode == "footer": | |||
|
542 | if item.__class__.__module__ == "__builtin__": | |||
|
543 | classname = item.__class__.__name__ | |||
|
544 | else: | |||
|
545 | classname = "%s.%s" % \ | |||
|
546 | (item.__class__.__module__,item.__class__.__name__) | |||
|
547 | yield (style_default, | |||
|
548 | "<%s object with %d items at 0x%x>" % \ | |||
|
549 | (classname, len(item), id(item))) | |||
|
550 | else: | |||
|
551 | if isinstance(item, dict): | |||
|
552 | yield (style_default, "{") | |||
|
553 | end = "}" | |||
|
554 | else: | |||
|
555 | yield (style_default, "dictproxy((") | |||
|
556 | end = "})" | |||
|
557 | for (i, (key, value)) in enumerate(item.iteritems()): | |||
|
558 | if i: | |||
|
559 | yield (style_default, ", ") | |||
|
560 | for part in xrepr(key, "default"): | |||
|
561 | yield part | |||
|
562 | yield (style_default, ": ") | |||
|
563 | for part in xrepr(value, "default"): | |||
|
564 | yield part | |||
|
565 | yield (style_default, end) | |||
|
566 | else: | |||
|
567 | yield (-1, True) | |||
|
568 | yield (style_default, repr(item)) | |||
349 |
|
569 | |||
350 |
|
570 | |||
351 | def xattrs(item, mode): |
|
571 | def xattrs(item, mode): | |
352 | try: |
|
572 | try: | |
353 | func = item.__xattrs__ |
|
573 | func = item.__xattrs__ | |
354 | except AttributeError: |
|
574 | except AttributeError: | |
355 | if isinstance(item, (list, tuple)): |
|
|||
356 | return xrange(len(item)) |
|
|||
357 | return (None,) |
|
575 | return (None,) | |
358 | else: |
|
576 | else: | |
359 | return func(mode) |
|
577 | return func(mode) | |
@@ -368,7 +586,7 b' def xiter(item, mode):' | |||||
368 | try: |
|
586 | try: | |
369 | func = item.__xiter__ |
|
587 | func = item.__xiter__ | |
370 | except AttributeError: |
|
588 | except AttributeError: | |
371 | if isinstance(item, dict): |
|
589 | if isinstance(item, (dict, types.DictProxyType)): | |
372 | def items(item): |
|
590 | def items(item): | |
373 | fields = ("key", "value") |
|
591 | fields = ("key", "value") | |
374 | for (key, value) in item.iteritems(): |
|
592 | for (key, value) in item.iteritems(): | |
@@ -623,15 +841,19 b' class ifile(object):' | |||||
623 | return ("name", "type", "size", "access", "owner", "group", "mdate") |
|
841 | return ("name", "type", "size", "access", "owner", "group", "mdate") | |
624 |
|
842 | |||
625 | def __xrepr__(self, mode): |
|
843 | def __xrepr__(self, mode): | |
626 | if mode == "header" or mode == "footer": |
|
844 | yield (-1, True) | |
|
845 | if mode in "header" or mode == "footer" or mode == "cell": | |||
627 | name = "ifile" |
|
846 | name = "ifile" | |
628 | try: |
|
847 | try: | |
629 | if self.isdir: |
|
848 | if self.isdir: | |
630 | name = "idir" |
|
849 | name = "idir" | |
631 | except IOError: |
|
850 | except IOError: | |
632 | pass |
|
851 | pass | |
633 |
|
|
852 | yield (style_url, "%s(%r)" % (name, self.abspath)) | |
634 | return repr(self) |
|
853 | elif mode == "cell": | |
|
854 | yield (style_url, repr(self.abspath)[1:-1]) | |||
|
855 | else: | |||
|
856 | yield (style_url, repr(self)) | |||
635 |
|
857 | |||
636 | def __xiter__(self, mode): |
|
858 | def __xiter__(self, mode): | |
637 | if self.isdir: |
|
859 | if self.isdir: | |
@@ -687,9 +909,13 b' class ils(Table):' | |||||
687 | return xiter(ifile(self.base), mode) |
|
909 | return xiter(ifile(self.base), mode) | |
688 |
|
910 | |||
689 | def __xrepr__(self, mode): |
|
911 | def __xrepr__(self, mode): | |
690 | if mode == "header" or mode == "footer": |
|
912 | yield (-1, True) | |
691 | return "idir(%r)" % (os.path.abspath(self.base)) |
|
913 | if mode == "header" or mode == "footer" or mode == "cell": | |
692 | return repr(self) |
|
914 | yield (style_url, "idir(%r)" % (os.path.abspath(self.base))) | |
|
915 | elif mode == "cell": | |||
|
916 | yield (style_url, repr(os.path.abspath(self.base))[1:-1]) | |||
|
917 | else: | |||
|
918 | yield (style_url, repr(self)) | |||
693 |
|
919 | |||
694 | def __repr__(self): |
|
920 | def __repr__(self): | |
695 | return "%s.%s(%r)" % \ |
|
921 | return "%s.%s(%r)" % \ | |
@@ -709,9 +935,11 b' class iglob(Table):' | |||||
709 | yield ifile(name) |
|
935 | yield ifile(name) | |
710 |
|
936 | |||
711 | def __xrepr__(self, mode): |
|
937 | def __xrepr__(self, mode): | |
712 | if mode == "header" or mode == "footer": |
|
938 | yield (-1, True) | |
713 | return "%s(%r)" % (self.__class__.__name__, self.glob) |
|
939 | if mode == "header" or mode == "footer" or mode == "cell": | |
714 | return repr(self) |
|
940 | yield (style_default, "%s(%r)" % (self.__class__.__name__, self.glob)) | |
|
941 | else: | |||
|
942 | yield (style_default, repr(self)) | |||
715 |
|
943 | |||
716 | def __repr__(self): |
|
944 | def __repr__(self): | |
717 | return "%s.%s(%r)" % \ |
|
945 | return "%s.%s(%r)" % \ | |
@@ -738,9 +966,11 b' class iwalk(Table):' | |||||
738 | yield ifile(os.path.join(dirpath, name)) |
|
966 | yield ifile(os.path.join(dirpath, name)) | |
739 |
|
967 | |||
740 | def __xrepr__(self, mode): |
|
968 | def __xrepr__(self, mode): | |
741 | if mode == "header" or mode == "footer": |
|
969 | yield (-1, True) | |
742 | return "%s(%r)" % (self.__class__.__name__, self.base) |
|
970 | if mode == "header" or mode == "footer" or mode == "cell": | |
743 | return repr(self) |
|
971 | yield (style_default, "%s(%r)" % (self.__class__.__name__, self.base)) | |
|
972 | else: | |||
|
973 | yield (style_default, repr(self)) | |||
744 |
|
974 | |||
745 | def __repr__(self): |
|
975 | def __repr__(self): | |
746 | return "%s.%s(%r)" % \ |
|
976 | return "%s.%s(%r)" % \ | |
@@ -820,9 +1050,11 b' class ipwd(Table):' | |||||
820 | yield ipwdentry(entry.pw_name) |
|
1050 | yield ipwdentry(entry.pw_name) | |
821 |
|
1051 | |||
822 | def __xrepr__(self, mode): |
|
1052 | def __xrepr__(self, mode): | |
823 | if mode == "header" or mode == "footer": |
|
1053 | yield (-1, True) | |
824 | return "%s()" % self.__class__.__name__ |
|
1054 | if mode == "header" or mode == "footer" or mode == "cell": | |
825 | return repr(self) |
|
1055 | yield (style_default, "%s()" % self.__class__.__name__) | |
|
1056 | else: | |||
|
1057 | yield (style_default, repr(self)) | |||
826 |
|
1058 | |||
827 |
|
1059 | |||
828 | class igrpentry(object): |
|
1060 | class igrpentry(object): | |
@@ -867,9 +1099,11 b' class igrpentry(object):' | |||||
867 | return ("name", "passwd", "gid", "mem") |
|
1099 | return ("name", "passwd", "gid", "mem") | |
868 |
|
1100 | |||
869 | def __xrepr__(self, mode): |
|
1101 | def __xrepr__(self, mode): | |
870 | if mode == "header" or mode == "footer": |
|
1102 | yield (-1, True) | |
871 | return "group %s" % self.name |
|
1103 | if mode == "header" or mode == "footer" or mode == "cell": | |
872 | return repr(self) |
|
1104 | yield (style_default, "group %s" % self.name) | |
|
1105 | else: | |||
|
1106 | yield (style_default, repr(self)) | |||
873 |
|
1107 | |||
874 | def __xiter__(self, mode): |
|
1108 | def __xiter__(self, mode): | |
875 | for member in self.mem: |
|
1109 | for member in self.mem: | |
@@ -889,9 +1123,11 b' class igrp(Table):' | |||||
889 | yield igrpentry(entry.gr_name) |
|
1123 | yield igrpentry(entry.gr_name) | |
890 |
|
1124 | |||
891 | def __xrepr__(self, mode): |
|
1125 | def __xrepr__(self, mode): | |
|
1126 | yield (-1, False) | |||
892 | if mode == "header" or mode == "footer": |
|
1127 | if mode == "header" or mode == "footer": | |
893 |
|
|
1128 | yield (style_default, "%s()" % self.__class__.__name__) | |
894 | return repr(self) |
|
1129 | else: | |
|
1130 | yield (style_default, repr(self)) | |||
895 |
|
1131 | |||
896 |
|
1132 | |||
897 | class Fields(object): |
|
1133 | class Fields(object): | |
@@ -904,10 +1140,28 b' class Fields(object):' | |||||
904 | return self.__fieldnames |
|
1140 | return self.__fieldnames | |
905 |
|
1141 | |||
906 | def __xrepr__(self, mode): |
|
1142 | def __xrepr__(self, mode): | |
907 | if mode == "header" or mode == "footer": |
|
1143 | yield (-1, False) | |
908 | args = ["%s=%r" % (f, getattr(self, f)) for f in self.__fieldnames] |
|
1144 | if mode == "header" or mode == "cell": | |
909 |
|
|
1145 | yield (style_default, self.__class__.__name__) | |
910 | return repr(self) |
|
1146 | yield (style_default, "(") | |
|
1147 | for (i, f) in enumerate(self.__fieldnames): | |||
|
1148 | if i: | |||
|
1149 | yield (style_default, ", ") | |||
|
1150 | yield (style_default, f) | |||
|
1151 | yield (style_default, "=") | |||
|
1152 | for part in xrepr(getattr(self, f), "default"): | |||
|
1153 | yield part | |||
|
1154 | yield (style_default, ")") | |||
|
1155 | elif mode == "footer": | |||
|
1156 | yield (style_default, self.__class__.__name__) | |||
|
1157 | yield (style_default, "(") | |||
|
1158 | for (i, f) in enumerate(self.__fieldnames): | |||
|
1159 | if i: | |||
|
1160 | yield (style_default, ", ") | |||
|
1161 | yield (style_default, f) | |||
|
1162 | yield (style_default, ")") | |||
|
1163 | else: | |||
|
1164 | yield (style_default, repr(self)) | |||
911 |
|
1165 | |||
912 |
|
1166 | |||
913 | class FieldTable(Table, list): |
|
1167 | class FieldTable(Table, list): | |
@@ -923,9 +1177,17 b' class FieldTable(Table, list):' | |||||
923 | return list.__iter__(self) |
|
1177 | return list.__iter__(self) | |
924 |
|
1178 | |||
925 | def __xrepr__(self, mode): |
|
1179 | def __xrepr__(self, mode): | |
|
1180 | yield (-1, False) | |||
926 | if mode == "header" or mode == "footer": |
|
1181 | if mode == "header" or mode == "footer": | |
927 | return "FieldTable(%r)" % ", ".join(map(repr, self.fields)) |
|
1182 | yield (style_default, self.__class__.__name__) | |
928 | return repr(self) |
|
1183 | yield (style_default, "(") | |
|
1184 | for (i, f) in enumerate(self.__fieldnames): | |||
|
1185 | if i: | |||
|
1186 | yield (style_default, ", ") | |||
|
1187 | yield (style_default, f) | |||
|
1188 | yield (style_default, ")") | |||
|
1189 | else: | |||
|
1190 | yield (style_default, repr(self)) | |||
929 |
|
1191 | |||
930 | def __repr__(self): |
|
1192 | def __repr__(self): | |
931 | return "<%s.%s object with fields=%r at 0x%x>" % \ |
|
1193 | return "<%s.%s object with fields=%r at 0x%x>" % \ | |
@@ -933,6 +1195,25 b' class FieldTable(Table, list):' | |||||
933 | ", ".join(map(repr, self.fields)), id(self)) |
|
1195 | ", ".join(map(repr, self.fields)), id(self)) | |
934 |
|
1196 | |||
935 |
|
1197 | |||
|
1198 | class List(list): | |||
|
1199 | def __xattrs__(self, mode): | |||
|
1200 | return xrange(len(self)) | |||
|
1201 | ||||
|
1202 | def __xrepr__(self, mode): | |||
|
1203 | yield (-1, False) | |||
|
1204 | if mode == "header" or mode == "cell" or mode == "footer" or mode == "default": | |||
|
1205 | yield (style_default, self.__class__.__name__) | |||
|
1206 | yield (style_default, "(") | |||
|
1207 | for (i, item) in enumerate(self): | |||
|
1208 | if i: | |||
|
1209 | yield (style_default, ", ") | |||
|
1210 | for part in xrepr(item, "default"): | |||
|
1211 | yield part | |||
|
1212 | yield (style_default, ")") | |||
|
1213 | else: | |||
|
1214 | yield (style_default, repr(self)) | |||
|
1215 | ||||
|
1216 | ||||
936 | class ienv(Table): |
|
1217 | class ienv(Table): | |
937 | """ |
|
1218 | """ | |
938 | This ``Table`` lists environment variables. |
|
1219 | This ``Table`` lists environment variables. | |
@@ -944,9 +1225,11 b' class ienv(Table):' | |||||
944 | yield Fields(fields, key=key, value=value) |
|
1225 | yield Fields(fields, key=key, value=value) | |
945 |
|
1226 | |||
946 | def __xrepr__(self, mode): |
|
1227 | def __xrepr__(self, mode): | |
947 | if mode == "header" or mode == "footer": |
|
1228 | yield (-1, True) | |
948 | return "%s()" % self.__class__.__name__ |
|
1229 | if mode == "header" or mode == "cell": | |
949 | return repr(self) |
|
1230 | yield (style_default, "%s()" % self.__class__.__name__) | |
|
1231 | else: | |||
|
1232 | yield (style_default, repr(self)) | |||
950 |
|
1233 | |||
951 |
|
1234 | |||
952 | class icsv(Pipe): |
|
1235 | class icsv(Pipe): | |
@@ -967,18 +1250,27 b' class icsv(Pipe):' | |||||
967 | input = input.open("rb") |
|
1250 | input = input.open("rb") | |
968 | reader = csv.reader(input, **self.csvargs) |
|
1251 | reader = csv.reader(input, **self.csvargs) | |
969 | for line in reader: |
|
1252 | for line in reader: | |
970 | yield line |
|
1253 | yield List(line) | |
971 |
|
1254 | |||
972 | def __xrepr__(self, mode): |
|
1255 | def __xrepr__(self, mode): | |
|
1256 | yield (-1, False) | |||
973 | if mode == "header" or mode == "footer": |
|
1257 | if mode == "header" or mode == "footer": | |
974 | input = getattr(self, "input", None) |
|
1258 | input = getattr(self, "input", None) | |
975 | if input is not None: |
|
1259 | if input is not None: | |
976 |
|
|
1260 | for part in xrepr(input, mode): | |
977 | else: |
|
1261 | yield part | |
978 | prefix = "" |
|
1262 | yield (style_default, " | ") | |
979 | args = ", ".join(["%s=%r" % item for item in self.csvargs.iteritems()]) |
|
1263 | yield (style_default, "%s(" % self.__class__.__name__) | |
980 | return "%s%s(%s)" % (prefix, self.__class__.__name__, args) |
|
1264 | for (i, (name, value)) in enumerate(self.csvargs.iteritems()): | |
981 | return repr(self) |
|
1265 | if i: | |
|
1266 | yield (style_default, ", ") | |||
|
1267 | yield (style_default, name) | |||
|
1268 | yield (style_default, "=") | |||
|
1269 | for part in xrepr(value, "default"): | |||
|
1270 | yield part | |||
|
1271 | yield (style_default, ")") | |||
|
1272 | else: | |||
|
1273 | yield (style_default, repr(self)) | |||
982 |
|
1274 | |||
983 | def __repr__(self): |
|
1275 | def __repr__(self): | |
984 | args = ", ".join(["%s=%r" % item for item in self.csvargs.iteritems()]) |
|
1276 | args = ", ".join(["%s=%r" % item for item in self.csvargs.iteritems()]) | |
@@ -1008,9 +1300,11 b' class ix(Table):' | |||||
1008 | self._pipe = None |
|
1300 | self._pipe = None | |
1009 |
|
1301 | |||
1010 | def __xrepr__(self, mode): |
|
1302 | def __xrepr__(self, mode): | |
|
1303 | yield (-1, True) | |||
1011 | if mode == "header" or mode == "footer": |
|
1304 | if mode == "header" or mode == "footer": | |
1012 |
|
|
1305 | yield (style_default, "%s(%r)" % (self.__class__.__name__, self.cmd)) | |
1013 | return repr(self) |
|
1306 | else: | |
|
1307 | yield (style_default, repr(self)) | |||
1014 |
|
1308 | |||
1015 | def __repr__(self): |
|
1309 | def __repr__(self): | |
1016 | return "%s.%s(%r)" % \ |
|
1310 | return "%s.%s(%r)" % \ | |
@@ -1051,15 +1345,19 b' class ifilter(Pipe):' | |||||
1051 | pass # Ignore errors |
|
1345 | pass # Ignore errors | |
1052 |
|
1346 | |||
1053 | def __xrepr__(self, mode): |
|
1347 | def __xrepr__(self, mode): | |
|
1348 | yield (-1, True) | |||
1054 | if mode == "header" or mode == "footer": |
|
1349 | if mode == "header" or mode == "footer": | |
1055 | input = getattr(self, "input", None) |
|
1350 | input = getattr(self, "input", None) | |
1056 | if input is not None: |
|
1351 | if input is not None: | |
1057 |
|
|
1352 | for part in xrepr(input, mode): | |
1058 | else: |
|
1353 | yield part | |
1059 | prefix = "" |
|
1354 | yield (style_default, " | ") | |
1060 | return "%s%s(%s)"% \ |
|
1355 | yield (style_default, "%s(" % self.__class__.__name__) | |
1061 | (prefix, self.__class__.__name__, xrepr(self.expr, mode)) |
|
1356 | for part in xrepr(self.expr, "default"): | |
1062 | return repr(self) |
|
1357 | yield part | |
|
1358 | yield (style_default, ")") | |||
|
1359 | else: | |||
|
1360 | yield (style_default, repr(self)) | |||
1063 |
|
1361 | |||
1064 | def __repr__(self): |
|
1362 | def __repr__(self): | |
1065 | return "<%s.%s expr=%r at 0x%x>" % \ |
|
1363 | return "<%s.%s expr=%r at 0x%x>" % \ | |
@@ -1098,15 +1396,19 b' class ieval(Pipe):' | |||||
1098 | pass # Ignore errors |
|
1396 | pass # Ignore errors | |
1099 |
|
1397 | |||
1100 | def __xrepr__(self, mode): |
|
1398 | def __xrepr__(self, mode): | |
|
1399 | yield (-1, True) | |||
1101 | if mode == "header" or mode == "footer": |
|
1400 | if mode == "header" or mode == "footer": | |
1102 | input = getattr(self, "input", None) |
|
1401 | input = getattr(self, "input", None) | |
1103 | if input is not None: |
|
1402 | if input is not None: | |
1104 |
|
|
1403 | for part in xrepr(input, mode): | |
1105 | else: |
|
1404 | yield part | |
1106 | prefix = "" |
|
1405 | yield (style_default, " | ") | |
1107 | return "%s%s(%s)" % \ |
|
1406 | yield (style_default, "%s(" % self.__class__.__name__) | |
1108 | (prefix, self.__class__.__name__, xrepr(self.expr, mode)) |
|
1407 | for part in xrepr(self.expr, "default"): | |
1109 | return repr(self) |
|
1408 | yield part | |
|
1409 | yield (style_default, ")") | |||
|
1410 | else: | |||
|
1411 | yield (style_default, repr(self)) | |||
1110 |
|
1412 | |||
1111 | def __repr__(self): |
|
1413 | def __repr__(self): | |
1112 | return "<%s.%s expr=%r at 0x%x>" % \ |
|
1414 | return "<%s.%s expr=%r at 0x%x>" % \ | |
@@ -1154,18 +1456,23 b' class isort(Pipe):' | |||||
1154 | yield item |
|
1456 | yield item | |
1155 |
|
1457 | |||
1156 | def __xrepr__(self, mode): |
|
1458 | def __xrepr__(self, mode): | |
|
1459 | yield (-1, True) | |||
1157 | if mode == "header" or mode == "footer": |
|
1460 | if mode == "header" or mode == "footer": | |
1158 | input = getattr(self, "input", None) |
|
1461 | input = getattr(self, "input", None) | |
1159 | if input is not None: |
|
1462 | if input is not None: | |
1160 |
|
|
1463 | for part in xrepr(input, mode): | |
1161 | else: |
|
1464 | yield part | |
1162 | prefix = "" |
|
1465 | yield (style_default, " | ") | |
|
1466 | yield (style_default, "%s(" % self.__class__.__name__) | |||
|
1467 | for part in xrepr(self.key, "default"): | |||
|
1468 | yield part | |||
1163 | if self.reverse: |
|
1469 | if self.reverse: | |
1164 | return "%s%s(%r, %r)" % \ |
|
1470 | yield (style_default, ", ") | |
1165 | (prefix, self.__class__.__name__, self.key, self.reverse) |
|
1471 | for part in xrepr(True, "default"): | |
1166 | else: |
|
1472 | yield part | |
1167 | return "%s%s(%r)" % (prefix, self.__class__.__name__, self.key) |
|
1473 | yield (style_default, ")") | |
1168 | return repr(self) |
|
1474 | else: | |
|
1475 | yield (style_default, repr(self)) | |||
1169 |
|
1476 | |||
1170 | def __repr__(self): |
|
1477 | def __repr__(self): | |
1171 | return "<%s.%s key=%r reverse=%r at 0x%x>" % \ |
|
1478 | return "<%s.%s key=%r reverse=%r at 0x%x>" % \ | |
@@ -1509,19 +1816,6 b' if curses is not None:' | |||||
1509 | """ |
|
1816 | """ | |
1510 |
|
1817 | |||
1511 |
|
1818 | |||
1512 | class Style(object): |
|
|||
1513 | """ |
|
|||
1514 | Store foreground color, background color and attribute (bold, underlined |
|
|||
1515 | etc.) for ``curses``. |
|
|||
1516 | """ |
|
|||
1517 | __slots__ = ("fg", "bg", "attrs") |
|
|||
1518 |
|
||||
1519 | def __init__(self, fg, bg, attrs=0): |
|
|||
1520 | self.fg = fg |
|
|||
1521 | self.bg = bg |
|
|||
1522 | self.attrs = attrs |
|
|||
1523 |
|
||||
1524 |
|
||||
1525 | class _BrowserCachedItem(object): |
|
1819 | class _BrowserCachedItem(object): | |
1526 | # This is used internally by ``ibrowse`` to store a item together with its |
|
1820 | # This is used internally by ``ibrowse`` to store a item together with its | |
1527 | # marked status. |
|
1821 | # marked status. | |
@@ -1580,7 +1874,7 b' if curses is not None:' | |||||
1580 | def __init__(self, browser, input, iterator, mainsizey, *attrs): |
|
1874 | def __init__(self, browser, input, iterator, mainsizey, *attrs): | |
1581 | self.browser = browser |
|
1875 | self.browser = browser | |
1582 | self.input = input |
|
1876 | self.input = input | |
1583 | self.header = xrepr(input, "header") |
|
1877 | self.header = list(x for x in xrepr(input, "header") if not isinstance(x[0], int)) | |
1584 | # iterator for the input |
|
1878 | # iterator for the input | |
1585 | self.iterator = iterator |
|
1879 | self.iterator = iterator | |
1586 |
|
1880 | |||
@@ -1677,11 +1971,31 b' if curses is not None:' | |||||
1677 | except (KeyboardInterrupt, SystemExit): |
|
1971 | except (KeyboardInterrupt, SystemExit): | |
1678 | raise |
|
1972 | raise | |
1679 | except Exception, exc: |
|
1973 | except Exception, exc: | |
1680 |
|
|
1974 | value = exc | |
1681 | else: |
|
1975 | # only store attribute if it exists (or we got an exception) | |
1682 | # only store attribute if it exists |
|
1976 | if value is not _default: | |
1683 |
|
|
1977 | parts = [] | |
1684 | row[attrname] = self.browser.format(value) |
|
1978 | totallength = 0 | |
|
1979 | align = None | |||
|
1980 | full = False | |||
|
1981 | # Collect parts until we have enough | |||
|
1982 | for part in xrepr(value, "cell"): | |||
|
1983 | # part gives (alignment, stop) | |||
|
1984 | # instead of (style, text) | |||
|
1985 | if isinstance(part[0], int): | |||
|
1986 | # only consider the first occurence | |||
|
1987 | if align is None: | |||
|
1988 | align = part[0] | |||
|
1989 | full = part[1] | |||
|
1990 | else: | |||
|
1991 | parts.append(part) | |||
|
1992 | totallength += len(part[1]) | |||
|
1993 | if totallength >= self.browser.maxattrlength and not full: | |||
|
1994 | parts.append((style_ellisis, "...")) | |||
|
1995 | totallength += 3 | |||
|
1996 | break | |||
|
1997 | # remember alignment, length and colored parts | |||
|
1998 | row[attrname] = (align, totallength, parts) | |||
1685 | return row |
|
1999 | return row | |
1686 |
|
2000 | |||
1687 | def calcwidths(self): |
|
2001 | def calcwidths(self): | |
@@ -1693,11 +2007,14 b' if curses is not None:' | |||||
1693 | self.colwidths = {} |
|
2007 | self.colwidths = {} | |
1694 | for row in self.displayrows: |
|
2008 | for row in self.displayrows: | |
1695 | for attrname in self.displayattrs: |
|
2009 | for attrname in self.displayattrs: | |
1696 | (align, text, style) = row.get(attrname, (2, "", None)) |
|
2010 | try: | |
|
2011 | length = row[attrname][1] | |||
|
2012 | except KeyError: | |||
|
2013 | length = 0 | |||
1697 | # always add attribute to colwidths, even if it doesn't exist |
|
2014 | # always add attribute to colwidths, even if it doesn't exist | |
1698 | if attrname not in self.colwidths: |
|
2015 | if attrname not in self.colwidths: | |
1699 | self.colwidths[attrname] = len(_attrname(attrname)) |
|
2016 | self.colwidths[attrname] = len(_attrname(attrname)) | |
1700 |
newwidth = max(self.colwidths[attrname], len |
|
2017 | newwidth = max(self.colwidths[attrname], length) | |
1701 | self.colwidths[attrname] = newwidth |
|
2018 | self.colwidths[attrname] = newwidth | |
1702 |
|
2019 | |||
1703 | # How many characters do we need to paint the item number? |
|
2020 | # How many characters do we need to paint the item number? | |
@@ -1865,29 +2182,24 b' if curses is not None:' | |||||
1865 | # if the nesting is deeper, only the innermost levels are displayed |
|
2182 | # if the nesting is deeper, only the innermost levels are displayed | |
1866 | maxheaders = 5 |
|
2183 | maxheaders = 5 | |
1867 |
|
2184 | |||
|
2185 | # The approximate maximum length of a column entry | |||
|
2186 | maxattrlength = 200 | |||
|
2187 | ||||
1868 | # Styles for various parts of the GUI |
|
2188 | # Styles for various parts of the GUI | |
1869 |
style_objheadertext = Style( |
|
2189 | style_objheadertext = Style(COLOR_WHITE, COLOR_BLACK, A_BOLD|A_REVERSE) | |
1870 |
style_objheadernumber = Style( |
|
2190 | style_objheadernumber = Style(COLOR_WHITE, COLOR_BLUE, A_BOLD|A_REVERSE) | |
1871 |
style_objheaderobject = Style( |
|
2191 | style_objheaderobject = Style(COLOR_WHITE, COLOR_BLACK, A_REVERSE) | |
1872 |
style_colheader = Style( |
|
2192 | style_colheader = Style(COLOR_BLUE, COLOR_WHITE, A_REVERSE) | |
1873 |
style_colheaderhere = Style( |
|
2193 | style_colheaderhere = Style(COLOR_GREEN, COLOR_BLACK, A_BOLD|A_REVERSE) | |
1874 |
style_colheadersep = Style( |
|
2194 | style_colheadersep = Style(COLOR_BLUE, COLOR_BLACK, A_REVERSE) | |
1875 |
style_number = Style( |
|
2195 | style_number = Style(COLOR_BLUE, COLOR_WHITE, A_REVERSE) | |
1876 |
style_numberhere = Style( |
|
2196 | style_numberhere = Style(COLOR_GREEN, COLOR_BLACK, A_BOLD|A_REVERSE) | |
1877 |
style_sep = Style( |
|
2197 | style_sep = Style(COLOR_BLUE, COLOR_BLACK) | |
1878 |
style_data = Style( |
|
2198 | style_data = Style(COLOR_WHITE, COLOR_BLACK) | |
1879 |
style_datapad = Style( |
|
2199 | style_datapad = Style(COLOR_BLUE, COLOR_BLACK, A_BOLD) | |
1880 |
style_footer = Style( |
|
2200 | style_footer = Style(COLOR_BLACK, COLOR_WHITE) | |
1881 |
style_noattr = Style( |
|
2201 | style_noattr = Style(COLOR_RED, COLOR_BLACK) | |
1882 |
style_ |
|
2202 | style_report = Style(COLOR_WHITE, COLOR_BLACK) | |
1883 | style_default = Style(curses.COLOR_WHITE, curses.COLOR_BLACK) |
|
|||
1884 | style_report = Style(curses.COLOR_WHITE, curses.COLOR_BLACK) |
|
|||
1885 |
|
||||
1886 | # Styles for datatypes |
|
|||
1887 | style_type_none = Style(curses.COLOR_MAGENTA, curses.COLOR_BLACK) |
|
|||
1888 | style_type_bool = Style(curses.COLOR_GREEN, curses.COLOR_BLACK) |
|
|||
1889 | style_type_number = Style(curses.COLOR_YELLOW, curses.COLOR_BLACK) |
|
|||
1890 | style_type_datetime = Style(curses.COLOR_CYAN, curses.COLOR_BLACK) |
|
|||
1891 |
|
2203 | |||
1892 | # Column separator in header |
|
2204 | # Column separator in header | |
1893 | headersepchar = "|" |
|
2205 | headersepchar = "|" | |
@@ -1913,7 +2225,9 b' if curses is not None:' | |||||
1913 | curses.KEY_HOME: "home", |
|
2225 | curses.KEY_HOME: "home", | |
1914 | curses.KEY_END: "end", |
|
2226 | curses.KEY_END: "end", | |
1915 | ord("<"): "prevattr", |
|
2227 | ord("<"): "prevattr", | |
|
2228 | 0x1b: "prevattr", # SHIFT-TAB | |||
1916 | ord(">"): "nextattr", |
|
2229 | ord(">"): "nextattr", | |
|
2230 | ord("\t"):"nextattr", # TAB | |||
1917 | ord("p"): "pick", |
|
2231 | ord("p"): "pick", | |
1918 | ord("P"): "pickattr", |
|
2232 | ord("P"): "pickattr", | |
1919 | ord("C"): "pickallattrs", |
|
2233 | ord("C"): "pickallattrs", | |
@@ -1957,7 +2271,8 b' if curses is not None:' | |||||
1957 | # multiple beeps). |
|
2271 | # multiple beeps). | |
1958 | self._dobeep = True |
|
2272 | self._dobeep = True | |
1959 |
|
2273 | |||
1960 | # Cache for registered ``curses`` colors. |
|
2274 | # Cache for registered ``curses`` colors and styles. | |
|
2275 | self._styles = {} | |||
1961 | self._colors = {} |
|
2276 | self._colors = {} | |
1962 | self._maxcolor = 1 |
|
2277 | self._maxcolor = 1 | |
1963 |
|
2278 | |||
@@ -1996,60 +2311,62 b' if curses is not None:' | |||||
1996 | if it has been registered before. |
|
2311 | if it has been registered before. | |
1997 | """ |
|
2312 | """ | |
1998 | try: |
|
2313 | try: | |
1999 |
return self._ |
|
2314 | return self._styles[style.fg, style.bg, style.attrs] | |
2000 | except KeyError: |
|
2315 | except KeyError: | |
2001 | curses.init_pair(self._maxcolor, style.fg, style.bg) |
|
2316 | attrs = 0 | |
2002 | pair = curses.color_pair(self._maxcolor) |
|
2317 | for b in A2CURSES: | |
2003 | self._colors[style.fg, style.bg] = pair |
|
2318 | if style.attrs & b: | |
2004 |
|
|
2319 | attrs |= A2CURSES[b] | |
2005 |
|
|
2320 | try: | |
|
2321 | color = self._colors[style.fg, style.bg] | |||
|
2322 | except KeyError: | |||
|
2323 | curses.init_pair( | |||
|
2324 | self._maxcolor, | |||
|
2325 | COLOR2CURSES[style.fg], | |||
|
2326 | COLOR2CURSES[style.bg] | |||
|
2327 | ) | |||
|
2328 | color = curses.color_pair(self._maxcolor) | |||
|
2329 | self._colors[style.fg, style.bg] = color | |||
|
2330 | self._maxcolor += 1 | |||
|
2331 | c = color | attrs | |||
|
2332 | self._styles[style.fg, style.bg, style.attrs] = c | |||
2006 | return c |
|
2333 | return c | |
2007 |
|
2334 | |||
2008 | def addstr(self, y, x, begx, endx, s, style): |
|
|||
2009 | """ |
|
|||
2010 | A version of ``curses.addstr()`` that can handle ``x`` coordinates |
|
|||
2011 | that are outside the screen. |
|
|||
2012 | """ |
|
|||
2013 | s2 = s[max(0, begx-x):max(0, endx-x)] |
|
|||
2014 | if s2: |
|
|||
2015 | self.scr.addstr(y, max(x, begx), s2, self.getstyle(style)) |
|
|||
2016 | return len(s) |
|
|||
2017 |
|
||||
2018 | def format(self, value): |
|
2335 | def format(self, value): | |
2019 | """ |
|
2336 | """ | |
2020 | Formats one attribute and returns an ``(alignment, string, style)`` |
|
2337 | Formats one attribute and returns an ``(alignment, string, style)`` | |
2021 | tuple. |
|
2338 | tuple. | |
2022 | """ |
|
2339 | """ | |
2023 | if value is None: |
|
2340 | if value is None: | |
2024 |
return (-1, repr(value), |
|
2341 | return (-1, repr(value), style_type_none) | |
2025 | elif isinstance(value, str): |
|
2342 | elif isinstance(value, str): | |
2026 |
return (-1, repr(value.expandtabs(tab))[1:-1], |
|
2343 | return (-1, repr(value.expandtabs(tab))[1:-1], style_default) | |
2027 | elif isinstance(value, unicode): |
|
2344 | elif isinstance(value, unicode): | |
2028 |
return (-1, repr(value.expandtabs(tab))[2:-1], |
|
2345 | return (-1, repr(value.expandtabs(tab))[2:-1], style_default) | |
2029 | elif isinstance(value, datetime.datetime): |
|
2346 | elif isinstance(value, datetime.datetime): | |
2030 | # Don't use strftime() here, as this requires year >= 1900 |
|
2347 | # Don't use strftime() here, as this requires year >= 1900 | |
2031 | return (-1, "%04d-%02d-%02d %02d:%02d:%02d.%06d" % \ |
|
2348 | return (-1, "%04d-%02d-%02d %02d:%02d:%02d.%06d" % \ | |
2032 | (value.year, value.month, value.day, |
|
2349 | (value.year, value.month, value.day, | |
2033 | value.hour, value.minute, value.second, |
|
2350 | value.hour, value.minute, value.second, | |
2034 | value.microsecond), |
|
2351 | value.microsecond), | |
2035 |
|
|
2352 | style_type_datetime) | |
2036 | elif isinstance(value, datetime.date): |
|
2353 | elif isinstance(value, datetime.date): | |
2037 | return (-1, "%04d-%02d-%02d" % \ |
|
2354 | return (-1, "%04d-%02d-%02d" % \ | |
2038 | (value.year, value.month, value.day), |
|
2355 | (value.year, value.month, value.day), | |
2039 |
|
|
2356 | style_type_datetime) | |
2040 | elif isinstance(value, datetime.time): |
|
2357 | elif isinstance(value, datetime.time): | |
2041 | return (-1, "%02d:%02d:%02d.%06d" % \ |
|
2358 | return (-1, "%02d:%02d:%02d.%06d" % \ | |
2042 | (value.hour, value.minute, value.second, |
|
2359 | (value.hour, value.minute, value.second, | |
2043 | value.microsecond), |
|
2360 | value.microsecond), | |
2044 |
|
|
2361 | style_type_datetime) | |
2045 | elif isinstance(value, datetime.timedelta): |
|
2362 | elif isinstance(value, datetime.timedelta): | |
2046 |
return (-1, repr(value), |
|
2363 | return (-1, repr(value), style_type_datetime) | |
2047 | elif isinstance(value, bool): |
|
2364 | elif isinstance(value, bool): | |
2048 |
return (-1, repr(value), |
|
2365 | return (-1, repr(value), style_type_bool) | |
2049 | elif isinstance(value, (int, long, float)): |
|
2366 | elif isinstance(value, (int, long, float)): | |
2050 |
return (1, repr(value), |
|
2367 | return (1, repr(value), style_type_number) | |
2051 | elif isinstance(value, complex): |
|
2368 | elif isinstance(value, complex): | |
2052 |
return (-1, repr(value), |
|
2369 | return (-1, repr(value), style_type_number) | |
2053 | elif isinstance(value, Exception): |
|
2370 | elif isinstance(value, Exception): | |
2054 | if value.__class__.__module__ == "exceptions": |
|
2371 | if value.__class__.__module__ == "exceptions": | |
2055 | value = "%s: %s" % (value.__class__.__name__, value) |
|
2372 | value = "%s: %s" % (value.__class__.__name__, value) | |
@@ -2057,8 +2374,25 b' if curses is not None:' | |||||
2057 | value = "%s.%s: %s" % \ |
|
2374 | value = "%s.%s: %s" % \ | |
2058 | (value.__class__.__module__, value.__class__.__name__, |
|
2375 | (value.__class__.__module__, value.__class__.__name__, | |
2059 | value) |
|
2376 | value) | |
2060 |
return (-1, value, |
|
2377 | return (-1, value, style_error) | |
2061 |
return (-1, repr(value), |
|
2378 | return (-1, repr(value), style_default) | |
|
2379 | ||||
|
2380 | def addstr(self, y, x, begx, endx, text, style): | |||
|
2381 | """ | |||
|
2382 | A version of ``curses.addstr()`` that can handle ``x`` coordinates | |||
|
2383 | that are outside the screen. | |||
|
2384 | """ | |||
|
2385 | text2 = text[max(0, begx-x):max(0, endx-x)] | |||
|
2386 | if text2: | |||
|
2387 | self.scr.addstr(y, max(x, begx), text2, self.getstyle(style)) | |||
|
2388 | return len(text) | |||
|
2389 | ||||
|
2390 | def addchr(self, y, x, begx, endx, c, l, style): | |||
|
2391 | x0 = max(x, begx) | |||
|
2392 | x1 = min(x+l, endx) | |||
|
2393 | if x1>x0: | |||
|
2394 | self.scr.addstr(y, x0, c*(x1-x0), self.getstyle(style)) | |||
|
2395 | return l | |||
2062 |
|
2396 | |||
2063 | def _calcheaderlines(self, levels): |
|
2397 | def _calcheaderlines(self, levels): | |
2064 | # Calculate how many headerlines do we have to display, if we have |
|
2398 | # Calculate how many headerlines do we have to display, if we have | |
@@ -2073,7 +2407,7 b' if curses is not None:' | |||||
2073 | Return a style for displaying the original style ``style`` |
|
2407 | Return a style for displaying the original style ``style`` | |
2074 | in the row the cursor is on. |
|
2408 | in the row the cursor is on. | |
2075 | """ |
|
2409 | """ | |
2076 |
return Style(style.fg, style.bg, style.attrs | |
|
2410 | return Style(style.fg, style.bg, style.attrs | A_BOLD) | |
2077 |
|
2411 | |||
2078 | def report(self, msg): |
|
2412 | def report(self, msg): | |
2079 | """ |
|
2413 | """ | |
@@ -2406,7 +2740,7 b' if curses is not None:' | |||||
2406 | for (key, cmd) in self.keymap.iteritems(): |
|
2740 | for (key, cmd) in self.keymap.iteritems(): | |
2407 | if cmd == "help": |
|
2741 | if cmd == "help": | |
2408 | keys.append("%s=%s" % (self.keylabel(key), cmd)) |
|
2742 | keys.append("%s=%s" % (self.keylabel(key), cmd)) | |
2409 | helpmsg = " %s" % " ".join(keys) |
|
2743 | helpmsg = " | %s" % " ".join(keys) | |
2410 |
|
2744 | |||
2411 | scr.clear() |
|
2745 | scr.clear() | |
2412 | msg = "Fetching first batch of objects..." |
|
2746 | msg = "Fetching first batch of objects..." | |
@@ -2431,16 +2765,22 b' if curses is not None:' | |||||
2431 | for i in xrange(self._firstheaderline, self._firstheaderline+self._headerlines): |
|
2765 | for i in xrange(self._firstheaderline, self._firstheaderline+self._headerlines): | |
2432 | lv = self.levels[i] |
|
2766 | lv = self.levels[i] | |
2433 | posx = 0 |
|
2767 | posx = 0 | |
2434 | posx += self.addstr(i-self._firstheaderline, posx, 0, self.scrsizex, " ibrowse #%d: " % i, self.style_objheadertext) |
|
2768 | posy = i-self._firstheaderline | |
2435 | posx += self.addstr(i-self._firstheaderline, posx, 0, self.scrsizex, lv.header, self.style_objheaderobject) |
|
2769 | endx = self.scrsizex | |
2436 | if i: # not the first level |
|
2770 | if i: # not the first level | |
2437 | posx += self.addstr(i-self._firstheaderline, posx, 0, self.scrsizex, " == ", self.style_objheadertext) |
|
2771 | msg = " (%d/%d" % (self.levels[i-1].cury, len(self.levels[i-1].items)) | |
2438 | msg = "%d/%d" % (self.levels[i-1].cury, len(self.levels[i-1].items)) |
|
|||
2439 | if not self.levels[i-1].exhausted: |
|
2772 | if not self.levels[i-1].exhausted: | |
2440 | msg += "+" |
|
2773 | msg += "+" | |
2441 | posx += self.addstr(i-self._firstheaderline, posx, 0, self.scrsizex, msg, self.style_objheadernumber) |
|
2774 | msg += ") " | |
2442 | if posx < self.scrsizex: |
|
2775 | endx -= len(msg)+1 | |
2443 |
|
|
2776 | posx += self.addstr(posy, posx, 0, endx, " ibrowse #%d: " % i, self.style_objheadertext) | |
|
2777 | for (style, text) in lv.header: | |||
|
2778 | posx += self.addstr(posy, posx, 0, endx, text, self.style_objheaderobject) | |||
|
2779 | if posx >= endx: | |||
|
2780 | break | |||
|
2781 | if i: | |||
|
2782 | posx += self.addstr(posy, posx, 0, self.scrsizex, msg, self.style_objheadernumber) | |||
|
2783 | posx += self.addchr(posy, posx, 0, self.scrsizex, " ", self.scrsizex-posx, self.style_objheadernumber) | |||
2444 |
|
2784 | |||
2445 | # Paint column headers |
|
2785 | # Paint column headers | |
2446 | scr.move(self._headerlines, 0) |
|
2786 | scr.move(self._headerlines, 0) | |
@@ -2481,33 +2821,35 b' if curses is not None:' | |||||
2481 |
|
2821 | |||
2482 | for attrname in level.displayattrs: |
|
2822 | for attrname in level.displayattrs: | |
2483 | cwidth = level.colwidths[attrname] |
|
2823 | cwidth = level.colwidths[attrname] | |
2484 | (align, text, style) = level.displayrows[i-level.datastarty].get(attrname, (2, None, self.style_noattr)) |
|
2824 | try: | |
|
2825 | (align, length, parts) = level.displayrows[i-level.datastarty][attrname] | |||
|
2826 | except KeyError: | |||
|
2827 | align = 2 | |||
2485 | padstyle = self.style_datapad |
|
2828 | padstyle = self.style_datapad | |
2486 | sepstyle = self.style_sep |
|
2829 | sepstyle = self.style_sep | |
2487 | if i == level.cury: |
|
2830 | if i == level.cury: | |
2488 | style = self.getstylehere(style) |
|
|||
2489 | padstyle = self.getstylehere(padstyle) |
|
2831 | padstyle = self.getstylehere(padstyle) | |
2490 | sepstyle = self.getstylehere(sepstyle) |
|
2832 | sepstyle = self.getstylehere(sepstyle) | |
2491 | if align == 2: |
|
2833 | if align == 2: | |
2492 |
|
|
2834 | posx += self.addchr(posy, posx, begx, self.scrsizex, self.nodatachar, cwidth, style) | |
2493 | posx += self.addstr(posy, posx, begx, self.scrsizex, text, style) |
|
2835 | else: | |
2494 |
|
|
2836 | if align == 1: | |
2495 |
|
|
2837 | posx += self.addchr(posy, posx, begx, self.scrsizex, self.datapadchar, cwidth-length, padstyle) | |
2496 | posx += self.addstr(posy, posx, begx, self.scrsizex, text, style) |
|
2838 | elif align == 0: | |
2497 | posx += self.addstr(posy, posx, begx, self.scrsizex, pad, padstyle) |
|
2839 | pad1 = (cwidth-length)//2 | |
2498 | elif align == 0: |
|
2840 | pad2 = cwidth-length-len(pad1) | |
2499 | pad1 = self.datapadchar*((cwidth-len(text))//2) |
|
2841 | posx += self.addchr(posy, posx, begx, self.scrsizex, self.datapadchar, pad1, padstyle) | |
2500 |
|
|
2842 | for (style, text) in parts: | |
2501 | posx += self.addstr(posy, posx, begx, self.scrsizex, pad1, padstyle) |
|
2843 | if i == level.cury: | |
2502 | posx += self.addstr(posy, posx, begx, self.scrsizex, text, style) |
|
2844 | style = self.getstylehere(style) | |
2503 |
posx += self.addstr(posy, posx, begx, self.scrsizex, |
|
2845 | posx += self.addstr(posy, posx, begx, self.scrsizex, text, style) | |
2504 |
|
|
2846 | if posx >= self.scrsizex: | |
2505 | pad = self.datapadchar*(cwidth-len(text)) |
|
2847 | break | |
2506 | posx += self.addstr(posy, posx, begx, self.scrsizex, pad, padstyle) |
|
2848 | if align == -1: | |
2507 |
posx += self.add |
|
2849 | posx += self.addchr(posy, posx, begx, self.scrsizex, self.datapadchar, cwidth-length, padstyle) | |
|
2850 | elif align == 0: | |||
|
2851 | posx += self.addchr(posy, posx, begx, self.scrsizex, self.datapadchar, pad2, padstyle) | |||
2508 | posx += self.addstr(posy, posx, begx, self.scrsizex, self.datasepchar, sepstyle) |
|
2852 | posx += self.addstr(posy, posx, begx, self.scrsizex, self.datasepchar, sepstyle) | |
2509 | if posx >= self.scrsizex: |
|
|||
2510 | break |
|
|||
2511 | else: |
|
2853 | else: | |
2512 | scr.clrtoeol() |
|
2854 | scr.clrtoeol() | |
2513 |
|
2855 | |||
@@ -2516,31 +2858,51 b' if curses is not None:' | |||||
2516 | scr.addstr(posy, 0, " " * (level.numbersizex+2), self.getstyle(self.style_colheader)) |
|
2858 | scr.addstr(posy, 0, " " * (level.numbersizex+2), self.getstyle(self.style_colheader)) | |
2517 | scr.clrtoeol() |
|
2859 | scr.clrtoeol() | |
2518 |
|
2860 | |||
|
2861 | posy = self.scrsizey-footery | |||
2519 | # Display footer |
|
2862 | # Display footer | |
2520 |
scr.addstr(s |
|
2863 | scr.addstr(posy, 0, " "*self.scrsizex, self.getstyle(self.style_footer)) | |
2521 |
|
2864 | |||
2522 | if level.exhausted: |
|
2865 | if level.exhausted: | |
2523 | flag = "" |
|
2866 | flag = "" | |
2524 | else: |
|
2867 | else: | |
2525 | flag = "+" |
|
2868 | flag = "+" | |
2526 |
|
2869 | |||
2527 | scr.addstr(self.scrsizey-footery, self.scrsizex-len(helpmsg)-1, helpmsg, self.getstyle(self.style_footer)) |
|
2870 | endx = self.scrsizex-len(helpmsg)-1 | |
|
2871 | scr.addstr(posy, endx, helpmsg, self.getstyle(self.style_footer)) | |||
2528 |
|
2872 | |||
2529 | msg = "%d%s objects (%d marked)" % (len(level.items), flag, level.marked) |
|
2873 | posx = 0 | |
2530 | attrname = level.displayattr[1] |
|
2874 | msg = " %d%s objects (%d marked): " % (len(level.items), flag, level.marked) | |
|
2875 | posx += self.addstr(posy, posx, 0, endx, msg, self.style_footer) | |||
2531 | try: |
|
2876 | try: | |
2532 | if attrname is not _default: |
|
2877 | item = level.items[level.cury].item | |
2533 | msg += ": %s > %s" % (xrepr(level.items[level.cury].item, "footer"), _attrname(attrname)) |
|
|||
2534 | else: |
|
|||
2535 | msg += ": %s > no attribute" % xrepr(level.items[level.cury].item, "footer") |
|
|||
2536 | except IndexError: # empty |
|
2878 | except IndexError: # empty | |
2537 | pass |
|
2879 | pass | |
2538 | self.addstr(self.scrsizey-footery, 1, 1, self.scrsizex-len(helpmsg)-1, msg, self.style_footer) |
|
2880 | else: | |
|
2881 | for (nostyle, text) in xrepr(item, "footer"): | |||
|
2882 | if not isinstance(nostyle, int): | |||
|
2883 | posx += self.addstr(posy, posx, 0, endx, text, self.style_footer) | |||
|
2884 | if posx >= endx: | |||
|
2885 | break | |||
|
2886 | attrname = level.displayattr[1] | |||
|
2887 | if attrname is not _default and attrname is not None: | |||
|
2888 | posx += self.addstr(posy, posx, 0, endx, " | ", self.style_footer) | |||
|
2889 | posx += self.addstr(posy, posx, 0, endx, _attrname(attrname), self.style_footer) | |||
|
2890 | posx += self.addstr(posy, posx, 0, endx, ": ", self.style_footer) | |||
|
2891 | attr = _getattr(item, attrname) | |||
|
2892 | for (nostyle, text) in xrepr(attr, "footer"): | |||
|
2893 | if not isinstance(nostyle, int): | |||
|
2894 | posx += self.addstr(posy, posx, 0, endx, text, self.style_footer) | |||
|
2895 | if posx >= endx: | |||
|
2896 | break | |||
|
2897 | ||||
|
2898 | #else: | |||
|
2899 | #msg += ": %s > no attribute" % xrepr(level.items[level.cury].item, "footer") | |||
|
2900 | #self.addstr(posy, 1, 1, self.scrsizex-len(helpmsg)-1, msg, self.style_footer) | |||
2539 |
|
2901 | |||
2540 | # Display report |
|
2902 | # Display report | |
2541 | if self._report is not None: |
|
2903 | if self._report is not None: | |
2542 | if isinstance(self._report, Exception): |
|
2904 | if isinstance(self._report, Exception): | |
2543 |
style = self.getstyle( |
|
2905 | style = self.getstyle(style_error) | |
2544 | if self._report.__class__.__module__ == "exceptions": |
|
2906 | if self._report.__class__.__module__ == "exceptions": | |
2545 | msg = "%s: %s" % \ |
|
2907 | msg = "%s: %s" % \ | |
2546 | (self._report.__class__.__name__, self._report) |
|
2908 | (self._report.__class__.__name__, self._report) |
General Comments 0
You need to be logged in to leave comments.
Login now