mirror of
https://github.com/kennethreitz/clint.git
synced 2026-06-05 23:00:18 +00:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 53ec4c2e09 | |||
| 7b6138eda6 | |||
| d19650b93c | |||
| 98edec43e9 | |||
| ef48a47b8d | |||
| 3be47add4a | |||
| bf99084ece | |||
| 705cda4443 | |||
| 79cf7a023b | |||
| 7900853dbc | |||
| 96827698df | |||
| 23689f8b0a | |||
| 1a9e15dbba | |||
| a07602fdeb | |||
| 0855525fca | |||
| 872c78a5b9 | |||
| 5d7485c144 | |||
| 25b8d6a10e | |||
| 003411ebcd |
@@ -2,4 +2,3 @@
|
||||
MANIFEST
|
||||
*.pyc
|
||||
.tox
|
||||
*~
|
||||
|
||||
@@ -14,3 +14,5 @@ Patches and Suggestions
|
||||
- Morgan Goose
|
||||
- Travis Swicegood
|
||||
- Will Thames
|
||||
- Greg Haskins
|
||||
- Miguel Araujo <maraujop>
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
History
|
||||
-------
|
||||
|
||||
0.2.4
|
||||
+++++
|
||||
|
||||
* New eng module
|
||||
* Win32 Bugfix
|
||||
|
||||
|
||||
0.2.3
|
||||
+++++
|
||||
|
||||
|
||||
+2
-2
@@ -19,8 +19,8 @@ from .pipes import piped_in
|
||||
|
||||
|
||||
__title__ = 'clint'
|
||||
__version__ = '0.2.3'
|
||||
__build__ = 0x000203
|
||||
__version__ = '0.2.5'
|
||||
__build__ = 0x000205
|
||||
__author__ = 'Kenneth Reitz'
|
||||
__license__ = 'ISC'
|
||||
__copyright__ = 'Copyright 2011 Kenneth Reitz'
|
||||
|
||||
+18
-38
@@ -13,33 +13,13 @@ from __future__ import absolute_import
|
||||
|
||||
import os
|
||||
from sys import argv
|
||||
from glob import glob
|
||||
|
||||
from .packages.ordereddict import OrderedDict
|
||||
from .utils import is_collection
|
||||
|
||||
|
||||
from .utils import expand_path, is_collection
|
||||
|
||||
__all__ = ('Args', )
|
||||
|
||||
|
||||
|
||||
def _expand_path(path):
|
||||
"""Expands directories and globs in given path."""
|
||||
|
||||
paths = []
|
||||
|
||||
if os.path.isdir(path):
|
||||
|
||||
for (dir, dirs, files) in os.walk(path):
|
||||
for file in files:
|
||||
paths.append(os.path.join(dir, file))
|
||||
else:
|
||||
paths.extend(glob(path))
|
||||
|
||||
return paths
|
||||
|
||||
|
||||
class Args(object):
|
||||
"""CLI Argument management."""
|
||||
|
||||
@@ -110,20 +90,20 @@ class Args(object):
|
||||
|
||||
def any_contain(self, x):
|
||||
"""Tests if given string is contained in any stored argument."""
|
||||
|
||||
|
||||
return bool(self.first_with(x))
|
||||
|
||||
|
||||
def contains(self, x):
|
||||
"""Tests if given object is in arguments list.
|
||||
"""Tests if given object is in arguments list.
|
||||
Accepts strings and lists of strings."""
|
||||
|
||||
|
||||
return self.__contains__(x)
|
||||
|
||||
|
||||
def first(self, x):
|
||||
"""Returns first found index of given value (or list of values)"""
|
||||
|
||||
|
||||
def _find( x):
|
||||
try:
|
||||
return self.all.index(str(x))
|
||||
@@ -212,7 +192,7 @@ class Args(object):
|
||||
return False
|
||||
else:
|
||||
return (x in self.all[index])
|
||||
|
||||
|
||||
except IndexError:
|
||||
return False
|
||||
|
||||
@@ -221,7 +201,7 @@ class Args(object):
|
||||
"""Returns true if argument exists at given index.
|
||||
Accepts: integer.
|
||||
"""
|
||||
|
||||
|
||||
try:
|
||||
self.all[x]
|
||||
return True
|
||||
@@ -231,15 +211,15 @@ class Args(object):
|
||||
|
||||
def value_after(self, x):
|
||||
"""Returns value of argument after given found argument (or list thereof)."""
|
||||
|
||||
|
||||
try:
|
||||
try:
|
||||
i = self.all.index(x)
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
|
||||
return self.all[i + 1]
|
||||
|
||||
|
||||
except IndexError:
|
||||
return None
|
||||
|
||||
@@ -266,21 +246,21 @@ class Args(object):
|
||||
|
||||
return collection
|
||||
|
||||
|
||||
|
||||
@property
|
||||
def last(self):
|
||||
"""Returns last argument."""
|
||||
|
||||
|
||||
try:
|
||||
return self.all[-1]
|
||||
except IndexError:
|
||||
return None
|
||||
|
||||
|
||||
|
||||
@property
|
||||
def all(self):
|
||||
"""Returns all arguments."""
|
||||
|
||||
|
||||
return self._args
|
||||
|
||||
|
||||
@@ -288,7 +268,7 @@ class Args(object):
|
||||
"""Returns all arguments containing given string (or list thereof)"""
|
||||
|
||||
_args = []
|
||||
|
||||
|
||||
for arg in self.all:
|
||||
if is_collection(x):
|
||||
for _x in x:
|
||||
@@ -327,7 +307,7 @@ class Args(object):
|
||||
return self.start_with('-')
|
||||
|
||||
|
||||
@property
|
||||
@property
|
||||
def not_flags(self):
|
||||
"""Returns Arg object excluding flagged arguments."""
|
||||
|
||||
@@ -341,7 +321,7 @@ class Args(object):
|
||||
_paths = []
|
||||
|
||||
for arg in self.all:
|
||||
for path in _expand_path(arg):
|
||||
for path in expand_path(arg):
|
||||
if os.path.exists(path):
|
||||
if absolute:
|
||||
_paths.append(os.path.abspath(path))
|
||||
@@ -358,7 +338,7 @@ class Args(object):
|
||||
_args = []
|
||||
|
||||
for arg in self.all:
|
||||
if not len(_expand_path(arg)):
|
||||
if not len(expand_path(arg)):
|
||||
if not os.path.exists(arg):
|
||||
_args.append(arg)
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
clint.eng
|
||||
~~~~~~~~~
|
||||
|
||||
This module provides English language string helpers.
|
||||
|
||||
"""
|
||||
|
||||
MORON_MODE = False
|
||||
COMMA = ','
|
||||
CONJUNCTION = 'and'
|
||||
SPACE = ' '
|
||||
|
||||
|
||||
def join(l, conj=CONJUNCTION, im_a_moron=MORON_MODE, seperator=COMMA):
|
||||
"""Joins lists of words. Oxford comma and all."""
|
||||
|
||||
collector = []
|
||||
left = len(l)
|
||||
seperator = seperator + SPACE
|
||||
conj = conj + SPACE
|
||||
|
||||
for _l in l[:]:
|
||||
|
||||
left += -1
|
||||
|
||||
collector.append(_l)
|
||||
if left == 1:
|
||||
if len(l) == 2 or im_a_moron:
|
||||
collector.append(SPACE)
|
||||
else:
|
||||
collector.append(seperator)
|
||||
|
||||
collector.append(conj)
|
||||
|
||||
elif left is not 0:
|
||||
collector.append(seperator)
|
||||
|
||||
return unicode(str().join(collector))
|
||||
|
||||
if __name__ == '__main__':
|
||||
print join(['blue', 'red', 'yellow'], conj='or', im_a_moron=True)
|
||||
print join(['blue', 'red', 'yellow'], conj='or')
|
||||
print join(['blue', 'red'], conj='or')
|
||||
print join(['blue', 'red'], conj='and')
|
||||
print join(['blue'], conj='and')
|
||||
print join(['blue', 'red', 'yellow', 'green', 'ello'], conj='and')
|
||||
@@ -1,6 +1,6 @@
|
||||
from .initialise import init
|
||||
from .initialise import init, deinit, reinit
|
||||
from .ansi import Fore, Back, Style
|
||||
from .ansitowin32 import AnsiToWin32
|
||||
|
||||
VERSION = '0.1.18'
|
||||
VERSION = '0.2.3'
|
||||
|
||||
|
||||
@@ -2,13 +2,11 @@
|
||||
This module generates ANSI character codes to printing colors to terminals.
|
||||
See: http://en.wikipedia.org/wiki/ANSI_escape_code
|
||||
'''
|
||||
from . import caps
|
||||
|
||||
CSI = '\033['
|
||||
|
||||
def code_to_chars(codes):
|
||||
codes = [str(code) for code in codes]
|
||||
return CSI + (";".join(codes)) + 'm'
|
||||
def code_to_chars(code):
|
||||
return CSI + str(code) + 'm'
|
||||
|
||||
class AnsiCodes(object):
|
||||
def __init__(self, codes):
|
||||
@@ -16,44 +14,34 @@ class AnsiCodes(object):
|
||||
if not name.startswith('_'):
|
||||
value = getattr(codes, name)
|
||||
setattr(self, name, code_to_chars(value))
|
||||
self._method = codes._caps_method
|
||||
|
||||
def __call__(self, code):
|
||||
if isinstance(code, basestring):
|
||||
return getattr(self, code)
|
||||
else: # extended (pass to capability)
|
||||
return code_to_chars(getattr(caps.capability, self._method)(code))
|
||||
|
||||
class AnsiFore:
|
||||
_caps_method = 'fg'
|
||||
BLACK = (30,)
|
||||
RED = (31,)
|
||||
GREEN = (32,)
|
||||
YELLOW = (33,)
|
||||
BLUE = (34,)
|
||||
MAGENTA = (35,)
|
||||
CYAN = (36,)
|
||||
WHITE = (37,)
|
||||
RESET = (39,)
|
||||
BLACK = 30
|
||||
RED = 31
|
||||
GREEN = 32
|
||||
YELLOW = 33
|
||||
BLUE = 34
|
||||
MAGENTA = 35
|
||||
CYAN = 36
|
||||
WHITE = 37
|
||||
RESET = 39
|
||||
|
||||
class AnsiBack:
|
||||
_caps_method = 'bg'
|
||||
BLACK = (40,)
|
||||
RED = (41,)
|
||||
GREEN = (42,)
|
||||
YELLOW = (43,)
|
||||
BLUE = (44,)
|
||||
MAGENTA = (45,)
|
||||
CYAN = (46,)
|
||||
WHITE = (47,)
|
||||
RESET = (49,)
|
||||
BLACK = 40
|
||||
RED = 41
|
||||
GREEN = 42
|
||||
YELLOW = 43
|
||||
BLUE = 44
|
||||
MAGENTA = 45
|
||||
CYAN = 46
|
||||
WHITE = 47
|
||||
RESET = 49
|
||||
|
||||
class AnsiStyle:
|
||||
_caps_method = 'style'
|
||||
BRIGHT = (1,)
|
||||
DIM = (2,)
|
||||
NORMAL = (22,)
|
||||
RESET_ALL = (0,)
|
||||
BRIGHT = 1
|
||||
DIM = 2
|
||||
NORMAL = 22
|
||||
RESET_ALL = 0
|
||||
|
||||
Fore = AnsiCodes( AnsiFore )
|
||||
Back = AnsiCodes( AnsiBack )
|
||||
|
||||
@@ -118,12 +118,12 @@ class AnsiToWin32(object):
|
||||
self.wrapped.flush()
|
||||
if self.autoreset:
|
||||
self.reset_all()
|
||||
|
||||
|
||||
|
||||
def reset_all(self):
|
||||
if self.convert:
|
||||
self.call_win32('m', (0,))
|
||||
else:
|
||||
elif is_a_tty(self.wrapped):
|
||||
self.wrapped.write(Style.RESET_ALL)
|
||||
|
||||
|
||||
@@ -173,4 +173,10 @@ class AnsiToWin32(object):
|
||||
args = func_args[1:]
|
||||
kwargs = dict(on_stderr=self.on_stderr)
|
||||
func(*args, **kwargs)
|
||||
elif command in ('H', 'f'): # set cursor position
|
||||
func = winterm.set_cursor_position
|
||||
func(params, on_stderr=self.on_stderr)
|
||||
elif command in ('J'):
|
||||
func = winterm.erase_data
|
||||
func(params, on_stderr=self.on_stderr)
|
||||
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
from .conv import xterm256
|
||||
from .conv import ansi
|
||||
|
||||
class _Base(object):
|
||||
"""
|
||||
Base 16-color ANSI.
|
||||
All ANSI terminals as well as Windows support this.
|
||||
"""
|
||||
def fg(self, rgb):
|
||||
(colid, bright) = ansi.from_rgb(rgb)
|
||||
if bright:
|
||||
return (1, 30 + colid)
|
||||
else:
|
||||
return (30 + colid,)
|
||||
|
||||
def bg(self, rgb):
|
||||
(colid, bright) = ansi.from_rgb(rgb)
|
||||
# Ignore brightness for background?
|
||||
return (40 + colid)
|
||||
|
||||
def __str__():
|
||||
return "BASE"
|
||||
|
||||
class _XTerm256(object):
|
||||
"""
|
||||
256-color terminal. Most modern terminal emulators support this.
|
||||
Putty, Gnome Terminal, and even oldies like (m)rxvt, xterm.
|
||||
"""
|
||||
def fg(self, rgb):
|
||||
return (38, 5, xterm256.from_rgb(rgb))
|
||||
|
||||
def bg(self, rgb):
|
||||
return (48, 5, xterm256.from_rgb(rgb))
|
||||
|
||||
def __str__():
|
||||
return "XTERM256"
|
||||
|
||||
class _RGB(object):
|
||||
"""
|
||||
Full 24-bit RGB support.
|
||||
As far as I know, only Konsole can do this.
|
||||
"""
|
||||
def fg(self, rgb):
|
||||
return (38, 2) + rgb
|
||||
|
||||
def bg(self, rgb):
|
||||
return (48, 2) + rgb
|
||||
|
||||
def __str__():
|
||||
return "RGB"
|
||||
|
||||
class ColorCapability:
|
||||
ANSI = _Base() # Base 16-color ANSI support
|
||||
XTERM256 = _XTerm256() # xterm256 (GNOME terminal / Putty)
|
||||
RGB = _RGB() # Full RGB (Konsole)
|
||||
|
||||
# Current terminal caps, default to ANSI
|
||||
capability = ColorCapability.ANSI
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
"""
|
||||
ANSI 16-color conversion utilities.
|
||||
"""
|
||||
# Wladimir van der Laan, 2011
|
||||
#
|
||||
# The original ansi colors are defined as follows
|
||||
#
|
||||
# 0 black
|
||||
# 1 red
|
||||
# 2 green
|
||||
# 3 brown (green+red)
|
||||
# 4 blue
|
||||
# 5 magenta (blue+red)
|
||||
# 6 cyan (blue+green)
|
||||
# 7 white
|
||||
#
|
||||
# However, the exact RGB mappings depend on the terminal that
|
||||
# is used.
|
||||
# In addition to these colors, nearly all terminals support 8
|
||||
# colors that are simply brighter versions of the defined colors.
|
||||
|
||||
_colors = [
|
||||
(0,0,0),
|
||||
(128,0,0),
|
||||
(0,128,0),
|
||||
(128,128,0),
|
||||
(0,0,128),
|
||||
(128,0,128),
|
||||
(0,128,128),
|
||||
(192,192,192),
|
||||
(128,128,128),
|
||||
(255,0,0),
|
||||
(0,255,0),
|
||||
(255,255,0),
|
||||
(0,0,255),
|
||||
(255,0,255),
|
||||
(0,255,255),
|
||||
(255,255,255)
|
||||
]
|
||||
|
||||
def to_rgb(color):
|
||||
"""
|
||||
Convert ANSI color tuple (color_id, bright) to RGB tuple.
|
||||
Raise `ValueError` in case of invalid color spec.
|
||||
"""
|
||||
color = (color[1]<<3)|color[0]
|
||||
try:
|
||||
return _colors[color]
|
||||
except IndexError:
|
||||
raise ValueError("Color %i out of range" % color)
|
||||
|
||||
def from_rgb(rgb):
|
||||
"""
|
||||
Convert RGB tuple to ANSI color tuple (color_id, bright).
|
||||
Raise `ValueError` in case of invalid color spec.
|
||||
"""
|
||||
min_d = 1000000
|
||||
closest = None
|
||||
for idx,col in enumerate(_colors):
|
||||
dr = rgb[0]-col[0]
|
||||
dg = rgb[1]-col[1]
|
||||
db = rgb[2]-col[2]
|
||||
d = dr*dr + dg*dg + db*db
|
||||
if d < min_d:
|
||||
min_d = d
|
||||
closest = idx
|
||||
return (closest&7, closest>>3)
|
||||
|
||||
|
||||
@@ -1,184 +0,0 @@
|
||||
"""
|
||||
HTML color conversion utilities.
|
||||
"""
|
||||
# Wladimir van der Laan, 2011
|
||||
|
||||
colors = {
|
||||
'aliceblue': '#F0F8FF',
|
||||
'antiquewhite': '#FAEBD7',
|
||||
'aqua': '#00FFFF',
|
||||
'aquamarine': '#7FFFD4',
|
||||
'azure': '#F0FFFF',
|
||||
'beige': '#F5F5DC',
|
||||
'bisque': '#FFE4C4',
|
||||
'black': '#000000',
|
||||
'blanchedalmond': '#FFEBCD',
|
||||
'blue': '#0000FF',
|
||||
'blueviolet': '#8A2BE2',
|
||||
'brown': '#A52A2A',
|
||||
'burlywood': '#DEB887',
|
||||
'cadetblue': '#5F9EA0',
|
||||
'chartreuse': '#7FFF00',
|
||||
'chocolate': '#D2691E',
|
||||
'coral': '#FF7F50',
|
||||
'cornflowerblue': '#6495ED',
|
||||
'cornsilk': '#FFF8DC',
|
||||
'crimson': '#DC143C',
|
||||
'cyan': '#00FFFF',
|
||||
'darkblue': '#00008B',
|
||||
'darkcyan': '#008B8B',
|
||||
'darkgoldenrod': '#B8860B',
|
||||
'darkgray': '#A9A9A9',
|
||||
'darkgreen': '#006400',
|
||||
'darkgrey': '#A9A9A9',
|
||||
'darkkhaki': '#BDB76B',
|
||||
'darkmagenta': '#8B008B',
|
||||
'darkolivegreen': '#556B2F',
|
||||
'darkorange': '#FF8C00',
|
||||
'darkorchid': '#9932CC',
|
||||
'darkred': '#8B0000',
|
||||
'darksalmon': '#E9967A',
|
||||
'darkseagreen': '#8FBC8F',
|
||||
'darkslateblue': '#483D8B',
|
||||
'darkslategray': '#2F4F4F',
|
||||
'darkslategrey': '#2F4F4F',
|
||||
'darkturquoise': '#00CED1',
|
||||
'darkviolet': '#9400D3',
|
||||
'deeppink': '#FF1493',
|
||||
'deepskyblue': '#00BFFF',
|
||||
'dimgray': '#696969',
|
||||
'dimgrey': '#696969',
|
||||
'dodgerblue': '#1E90FF',
|
||||
'firebrick': '#B22222',
|
||||
'floralwhite': '#FFFAF0',
|
||||
'forestgreen': '#228B22',
|
||||
'fuchsia': '#FF00FF',
|
||||
'gainsboro': '#DCDCDC',
|
||||
'ghostwhite': '#F8F8FF',
|
||||
'gold': '#FFD700',
|
||||
'goldenrod': '#DAA520',
|
||||
'gray': '#808080',
|
||||
'green': '#008000',
|
||||
'greenyellow': '#ADFF2F',
|
||||
'grey': '#808080',
|
||||
'honeydew': '#F0FFF0',
|
||||
'hotpink': '#FF69B4',
|
||||
'indianred ': '#CD5C5C',
|
||||
'indigo ': '#4B0082',
|
||||
'ivory': '#FFFFF0',
|
||||
'khaki': '#F0E68C',
|
||||
'lavender': '#E6E6FA',
|
||||
'lavenderblush': '#FFF0F5',
|
||||
'lawngreen': '#7CFC00',
|
||||
'lemonchiffon': '#FFFACD',
|
||||
'lightblue': '#ADD8E6',
|
||||
'lightcoral': '#F08080',
|
||||
'lightcyan': '#E0FFFF',
|
||||
'lightgoldenrodyellow': '#FAFAD2',
|
||||
'lightgray': '#D3D3D3',
|
||||
'lightgreen': '#90EE90',
|
||||
'lightgrey': '#D3D3D3',
|
||||
'lightpink': '#FFB6C1',
|
||||
'lightsalmon': '#FFA07A',
|
||||
'lightseagreen': '#20B2AA',
|
||||
'lightskyblue': '#87CEFA',
|
||||
'lightslategray': '#778899',
|
||||
'lightslategrey': '#778899',
|
||||
'lightsteelblue': '#B0C4DE',
|
||||
'lightyellow': '#FFFFE0',
|
||||
'lime': '#00FF00',
|
||||
'limegreen': '#32CD32',
|
||||
'linen': '#FAF0E6',
|
||||
'magenta': '#FF00FF',
|
||||
'maroon': '#800000',
|
||||
'mediumaquamarine': '#66CDAA',
|
||||
'mediumblue': '#0000CD',
|
||||
'mediumorchid': '#BA55D3',
|
||||
'mediumpurple': '#9370D8',
|
||||
'mediumseagreen': '#3CB371',
|
||||
'mediumslateblue': '#7B68EE',
|
||||
'mediumspringgreen': '#00FA9A',
|
||||
'mediumturquoise': '#48D1CC',
|
||||
'mediumvioletred': '#C71585',
|
||||
'midnightblue': '#191970',
|
||||
'mintcream': '#F5FFFA',
|
||||
'mistyrose': '#FFE4E1',
|
||||
'moccasin': '#FFE4B5',
|
||||
'navajowhite': '#FFDEAD',
|
||||
'navy': '#000080',
|
||||
'oldlace': '#FDF5E6',
|
||||
'olive': '#808000',
|
||||
'olivedrab': '#6B8E23',
|
||||
'orange': '#FFA500',
|
||||
'orangered': '#FF4500',
|
||||
'orchid': '#DA70D6',
|
||||
'palegoldenrod': '#EEE8AA',
|
||||
'palegreen': '#98FB98',
|
||||
'paleturquoise': '#AFEEEE',
|
||||
'palevioletred': '#D87093',
|
||||
'papayawhip': '#FFEFD5',
|
||||
'peachpuff': '#FFDAB9',
|
||||
'peru': '#CD853F',
|
||||
'pink': '#FFC0CB',
|
||||
'plum': '#DDA0DD',
|
||||
'powderblue': '#B0E0E6',
|
||||
'purple': '#800080',
|
||||
'red': '#FF0000',
|
||||
'rosybrown': '#BC8F8F',
|
||||
'royalblue': '#4169E1',
|
||||
'saddlebrown': '#8B4513',
|
||||
'salmon': '#FA8072',
|
||||
'sandybrown': '#F4A460',
|
||||
'seagreen': '#2E8B57',
|
||||
'seashell': '#FFF5EE',
|
||||
'sienna': '#A0522D',
|
||||
'silver': '#C0C0C0',
|
||||
'skyblue': '#87CEEB',
|
||||
'slateblue': '#6A5ACD',
|
||||
'slategray': '#708090',
|
||||
'slategrey': '#708090',
|
||||
'snow': '#FFFAFA',
|
||||
'springgreen': '#00FF7F',
|
||||
'steelblue': '#4682B4',
|
||||
'tan': '#D2B48C',
|
||||
'teal': '#008080',
|
||||
'thistle': '#D8BFD8',
|
||||
'tomato': '#FF6347',
|
||||
'turquoise': '#40E0D0',
|
||||
'violet': '#EE82EE',
|
||||
'wheat': '#F5DEB3',
|
||||
'white': '#FFFFFF',
|
||||
'whitesmoke': '#F5F5F5',
|
||||
'yellow': '#FFFF00',
|
||||
'yellowgreen': '#9ACD32'}
|
||||
|
||||
def to_rgb(color):
|
||||
"""
|
||||
Parse HTML color specification to RGB tuple.
|
||||
Raise `ValueError` in case of invalid color spec.
|
||||
"""
|
||||
if color in colors:
|
||||
color = colors[color]
|
||||
|
||||
if color.startswith("#"):
|
||||
color = color[1:]
|
||||
|
||||
if len(color) == 6: #RRGGBB
|
||||
rgb = (int(color[0:2],16),
|
||||
int(color[2:4],16),
|
||||
int(color[4:6],16))
|
||||
elif len(color) == 3: #RGB
|
||||
rgb = (int(color[0],16),
|
||||
int(color[1],16),
|
||||
int(color[2],16))
|
||||
rgb = tuple([(x<<4)|x for x in rgb])
|
||||
else:
|
||||
raise ValueError("Invalid color %s" % color)
|
||||
|
||||
return rgb
|
||||
|
||||
def from_rgb(rgb):
|
||||
"""
|
||||
Convert RGB tuple to HTML color specification.
|
||||
"""
|
||||
return "#%02x%02x%02x" % rgb
|
||||
@@ -1,115 +0,0 @@
|
||||
"""
|
||||
256-color xterm conversion utilities.
|
||||
"""
|
||||
# Wladimir van der Laan, 2011
|
||||
|
||||
# whole colortable, filled in later
|
||||
colortable = None
|
||||
|
||||
# the 6 value iterations in the xterm color cube
|
||||
valuerange = [ 0x00, 0x5F, 0x87, 0xAF, 0xD7, 0xFF ]
|
||||
|
||||
# 16 basic ANSI colors + lighter variants
|
||||
# these can be different depending on the terminal settings,
|
||||
# so do not use them when converting from RGB.
|
||||
basic16 = [
|
||||
[ 0x00, 0x00, 0x00 ], # 0
|
||||
[ 0xCD, 0x00, 0x00 ], # 1
|
||||
[ 0x00, 0xCD, 0x00 ], # 2
|
||||
[ 0xCD, 0xCD, 0x00 ], # 3
|
||||
[ 0x00, 0x00, 0xEE ], # 4
|
||||
[ 0xCD, 0x00, 0xCD ], # 5
|
||||
[ 0x00, 0xCD, 0xCD ], # 6
|
||||
[ 0xE5, 0xE5, 0xE5 ], # 7
|
||||
[ 0x7F, 0x7F, 0x7F ], # 8
|
||||
[ 0xFF, 0x00, 0x00 ], # 9
|
||||
[ 0x00, 0xFF, 0x00 ], # 10
|
||||
[ 0xFF, 0xFF, 0x00 ], # 11
|
||||
[ 0x5C, 0x5C, 0xFF ], # 12
|
||||
[ 0xFF, 0x00, 0xFF ], # 13
|
||||
[ 0x00, 0xFF, 0xFF ], # 14
|
||||
[ 0xFF, 0xFF, 0xFF ] # 15
|
||||
]
|
||||
|
||||
# Closest color on RGB color cube (from valuerange)
|
||||
closest6 = [
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5,
|
||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5]
|
||||
|
||||
def _color_dist(c, rgb):
|
||||
"""
|
||||
Return squared Euclidian distance of rgb to color `c`
|
||||
in the color table.
|
||||
"""
|
||||
d0 = colortable[c][0] - rgb[0]
|
||||
d1 = colortable[c][1] - rgb[1]
|
||||
d2 = colortable[c][2] - rgb[2]
|
||||
return d0*d0 + d1*d1 + d2*d2
|
||||
|
||||
def to_rgb(color):
|
||||
"""
|
||||
Convert a xterm256 color value (0-255) to 3 unsigned chars RGB
|
||||
tuple.
|
||||
"""
|
||||
rgb = [0,0,0]
|
||||
if color < 16:
|
||||
# 16 basic colors
|
||||
rgb[0] = basic16[color][0]
|
||||
rgb[1] = basic16[color][1]
|
||||
rgb[2] = basic16[color][2]
|
||||
elif color >= 16 and color <= 231:
|
||||
# color cube color
|
||||
color -= 16
|
||||
rgb[0] = valuerange[(color/36)%6]
|
||||
rgb[1] = valuerange[(color/6)%6]
|
||||
rgb[2] = valuerange[color%6]
|
||||
elif color >= 232 and color <= 255:
|
||||
# gray tone
|
||||
rgb[0] = rgb[1] = rgb[2] = 8+(color-232)*0x0a
|
||||
|
||||
return rgb
|
||||
|
||||
def from_rgb(rgb):
|
||||
"""
|
||||
Convert RGB tuple to xterm256 color value (0-255).
|
||||
"""
|
||||
# Optimized algorithm to find the xterm256 color with Euclidian closest distance to a
|
||||
# provided RGB value: as the palette consists of an independent 6x6x6 RGB cube
|
||||
# and a 24 grey tone scale, determine the closest color in both palettes, then
|
||||
# from these two return the on that's closest to the requested RGB color.
|
||||
|
||||
# Compute closest color on 6x6x6 RGB cube
|
||||
r = [closest6[x] for x in rgb]
|
||||
b = 16 + r[0]*36 + r[1]*6 + r[2]
|
||||
|
||||
# Compute closest point on greyscale line
|
||||
greyscale = sum(rgb)
|
||||
r = (greyscale-9) / 30
|
||||
c = 232 + max(min(r,23),0)
|
||||
|
||||
# Return RGB cube or greyscale color depending
|
||||
# on which is closest.
|
||||
distb = _color_dist(b, rgb)
|
||||
distc = _color_dist(c, rgb)
|
||||
if distb <= distc:
|
||||
color = b
|
||||
else:
|
||||
color = c
|
||||
|
||||
return color
|
||||
|
||||
colortable = [to_rgb(c) for c in xrange(0, 256)]
|
||||
@@ -7,6 +7,9 @@ from .ansitowin32 import AnsiToWin32
|
||||
orig_stdout = sys.stdout
|
||||
orig_stderr = sys.stderr
|
||||
|
||||
wrapped_stdout = sys.stdout
|
||||
wrapped_stderr = sys.stderr
|
||||
|
||||
atexit_done = False
|
||||
|
||||
|
||||
@@ -16,11 +19,14 @@ def reset_all():
|
||||
|
||||
def init(autoreset=False, convert=None, strip=None, wrap=True):
|
||||
|
||||
if wrap==False and (autoreset==True or convert==True or strip==True):
|
||||
if not wrap and any([autoreset, convert, strip]):
|
||||
raise ValueError('wrap=False conflicts with any other arg=True')
|
||||
|
||||
sys.stdout = wrap_stream(orig_stdout, convert, strip, autoreset, wrap)
|
||||
sys.stderr = wrap_stream(orig_stderr, convert, strip, autoreset, wrap)
|
||||
global wrapped_stdout, wrapped_stderr
|
||||
sys.stdout = wrapped_stdout = \
|
||||
wrap_stream(orig_stdout, convert, strip, autoreset, wrap)
|
||||
sys.stderr = wrapped_stderr = \
|
||||
wrap_stream(orig_stderr, convert, strip, autoreset, wrap)
|
||||
|
||||
global atexit_done
|
||||
if not atexit_done:
|
||||
@@ -28,6 +34,16 @@ def init(autoreset=False, convert=None, strip=None, wrap=True):
|
||||
atexit_done = True
|
||||
|
||||
|
||||
def deinit():
|
||||
sys.stdout = orig_stdout
|
||||
sys.stderr = orig_stderr
|
||||
|
||||
|
||||
def reinit():
|
||||
sys.stdout = wrapped_stdout
|
||||
sys.stderr = wrapped_stdout
|
||||
|
||||
|
||||
def wrap_stream(stream, convert, strip, autoreset, wrap):
|
||||
if wrap:
|
||||
wrapper = AnsiToWin32(stream,
|
||||
@@ -36,3 +52,4 @@ def wrap_stream(stream, convert, strip, autoreset, wrap):
|
||||
stream = wrapper.stream
|
||||
return stream
|
||||
|
||||
|
||||
|
||||
@@ -48,8 +48,16 @@ else:
|
||||
("srWindow", SMALL_RECT),
|
||||
("dwMaximumWindowSize", COORD),
|
||||
]
|
||||
def __str__(self):
|
||||
return '(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)' % (
|
||||
self.dwSize.Y, self.dwSize.X
|
||||
, self.dwCursorPosition.Y, self.dwCursorPosition.X
|
||||
, self.wAttributes
|
||||
, self.srWindow.Top, self.srWindow.Left, self.srWindow.Bottom, self.srWindow.Right
|
||||
, self.dwMaximumWindowSize.Y, self.dwMaximumWindowSize.X
|
||||
)
|
||||
|
||||
def GetConsoleScreenBufferInfo(stream_id):
|
||||
def GetConsoleScreenBufferInfo(stream_id=STDOUT):
|
||||
handle = handles[stream_id]
|
||||
csbi = CONSOLE_SCREEN_BUFFER_INFO()
|
||||
success = windll.kernel32.GetConsoleScreenBufferInfo(
|
||||
@@ -62,34 +70,54 @@ else:
|
||||
|
||||
def SetConsoleTextAttribute(stream_id, attrs):
|
||||
handle = handles[stream_id]
|
||||
success = windll.kernel32.SetConsoleTextAttribute(handle, attrs)
|
||||
assert success
|
||||
return windll.kernel32.SetConsoleTextAttribute(handle, attrs)
|
||||
|
||||
def SetConsoleCursorPosition(stream_id, position):
|
||||
handle = handles[stream_id]
|
||||
position = COORD(*position)
|
||||
success = windll.kernel32.SetConsoleCursorPosition(handle, position)
|
||||
assert success
|
||||
# If the position is out of range, do nothing.
|
||||
if position.Y <= 0 or position.X <= 0:
|
||||
return
|
||||
# Adjust for Windows' SetConsoleCursorPosition:
|
||||
# 1. being 0-based, while ANSI is 1-based.
|
||||
# 2. expecting (x,y), while ANSI uses (y,x).
|
||||
adjusted_position = COORD(position.Y - 1, position.X - 1)
|
||||
# Adjust for viewport's scroll position
|
||||
sr = GetConsoleScreenBufferInfo(STDOUT).srWindow
|
||||
adjusted_position.Y += sr.Top
|
||||
adjusted_position.X += sr.Left
|
||||
# Resume normal processing
|
||||
handle = handles[stream_id]
|
||||
success = windll.kernel32.SetConsoleCursorPosition(handle, adjusted_position)
|
||||
return success
|
||||
|
||||
def FillConsoleOutputCharacter(stream_id, char, length, start):
|
||||
handle = handles[stream_id]
|
||||
char = TCHAR(char)
|
||||
length = DWORD(length)
|
||||
start = COORD(*start)
|
||||
num_written = DWORD(0)
|
||||
# AttributeError: function 'FillConsoleOutputCharacter' not found
|
||||
# could it just be that my types are wrong?
|
||||
success = windll.kernel32.FillConsoleOutputCharacter(
|
||||
# Note that this is hard-coded for ANSI (vs wide) bytes.
|
||||
success = windll.kernel32.FillConsoleOutputCharacterA(
|
||||
handle, char, length, start, byref(num_written))
|
||||
assert success
|
||||
return num_written.value
|
||||
|
||||
def FillConsoleOutputAttribute(stream_id, attr, length, start):
|
||||
''' FillConsoleOutputAttribute( hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten )'''
|
||||
handle = handles[stream_id]
|
||||
attribute = WORD(attr)
|
||||
length = DWORD(length)
|
||||
num_written = DWORD(0)
|
||||
# Note that this is hard-coded for ANSI (vs wide) bytes.
|
||||
success = windll.kernel32.FillConsoleOutputAttribute(
|
||||
handle, attribute, length, start, byref(num_written))
|
||||
return success
|
||||
|
||||
|
||||
if __name__=='__main__':
|
||||
x = GetConsoleScreenBufferInfo(STDOUT)
|
||||
print(x.dwSize)
|
||||
print(x.dwCursorPosition)
|
||||
print(x.wAttributes)
|
||||
print(x.srWindow)
|
||||
print(x.dwMaximumWindowSize)
|
||||
print(x)
|
||||
print('dwSize(height,width) = (%d,%d)' % (x.dwSize.Y, x.dwSize.X))
|
||||
print('dwCursorPosition(y,x) = (%d,%d)' % (x.dwCursorPosition.Y, x.dwCursorPosition.X))
|
||||
print('wAttributes(color) = %d = 0x%02x' % (x.wAttributes, x.wAttributes))
|
||||
print('srWindow(Top,Left)-(Bottom,Right) = (%d,%d)-(%d,%d)' % (x.srWindow.Top, x.srWindow.Left, x.srWindow.Bottom, x.srWindow.Right))
|
||||
print('dwMaximumWindowSize(maxHeight,maxWidth) = (%d,%d)' % (x.dwMaximumWindowSize.Y, x.dwMaximumWindowSize.X))
|
||||
|
||||
|
||||
@@ -22,8 +22,7 @@ class WinStyle(object):
|
||||
class WinTerm(object):
|
||||
|
||||
def __init__(self):
|
||||
self._default = \
|
||||
win32.GetConsoleScreenBufferInfo(win32.STDOUT).wAttributes
|
||||
self._default = win32.GetConsoleScreenBufferInfo(win32.STDOUT).wAttributes
|
||||
self.set_attrs(self._default)
|
||||
self._default_fore = self._fore
|
||||
self._default_back = self._back
|
||||
@@ -67,3 +66,37 @@ class WinTerm(object):
|
||||
handle = win32.STDERR
|
||||
win32.SetConsoleTextAttribute(handle, attrs)
|
||||
|
||||
def set_cursor_position(self, position=None, on_stderr=False):
|
||||
if position is None:
|
||||
#I'm not currently tracking the position, so there is no default.
|
||||
#position = self.get_position()
|
||||
return
|
||||
handle = win32.STDOUT
|
||||
if on_stderr:
|
||||
handle = win32.STDERR
|
||||
win32.SetConsoleCursorPosition(handle, position)
|
||||
|
||||
def erase_data(self, mode=0, on_stderr=False):
|
||||
# 0 (or None) should clear from the cursor to the end of the screen.
|
||||
# 1 should clear from the cursor to the beginning of the screen.
|
||||
# 2 should clear the entire screen. (And maybe move cursor to (1,1)?)
|
||||
#
|
||||
# At the moment, I only support mode 2. From looking at the API, it
|
||||
# should be possible to calculate a different number of bytes to clear,
|
||||
# and to do so relative to the cursor position.
|
||||
if mode[0] not in (2,):
|
||||
return
|
||||
handle = win32.STDOUT
|
||||
if on_stderr:
|
||||
handle = win32.STDERR
|
||||
# here's where we'll home the cursor
|
||||
coord_screen = win32.COORD(0,0)
|
||||
csbi = win32.GetConsoleScreenBufferInfo(handle)
|
||||
# get the number of character cells in the current buffer
|
||||
dw_con_size = csbi.dwSize.X * csbi.dwSize.Y
|
||||
# fill the entire screen with blanks
|
||||
win32.FillConsoleOutputCharacter(handle, ord(' '), dw_con_size, coord_screen)
|
||||
# now set the buffer's attributes accordingly
|
||||
win32.FillConsoleOutputAttribute(handle, self.get_attrs(), dw_con_size, coord_screen );
|
||||
# put the cursor at (0, 0)
|
||||
win32.SetConsoleCursorPosition(handle, (coord_screen.X, coord_screen.Y))
|
||||
|
||||
+4
-22
@@ -15,7 +15,6 @@ import re
|
||||
import sys
|
||||
|
||||
from ..packages import colorama
|
||||
from ..packages.colorama.conv import html
|
||||
|
||||
__all__ = (
|
||||
'red', 'green', 'yellow', 'blue',
|
||||
@@ -28,6 +27,8 @@ DISABLE_COLOR = False
|
||||
|
||||
if not sys.stdout.isatty():
|
||||
DISABLE_COLOR = True
|
||||
else:
|
||||
colorama.init(autoreset=True)
|
||||
|
||||
|
||||
class ColoredString(object):
|
||||
@@ -40,9 +41,8 @@ class ColoredString(object):
|
||||
@property
|
||||
def color_str(self):
|
||||
if sys.stdout.isatty() and not DISABLE_COLOR:
|
||||
colorama.init(autoreset=True)
|
||||
return '%s%s%s' % (
|
||||
colorama.Fore(self.color), self.s, colorama.Fore.RESET)
|
||||
getattr(colorama.Fore, self.color), self.s, colorama.Fore.RESET)
|
||||
else:
|
||||
return self.s
|
||||
|
||||
@@ -79,7 +79,7 @@ def clean(s):
|
||||
strip = re.compile("([^-_a-zA-Z0-9!@#%&=,/'\";:~`\$\^\*\(\)\+\[\]\.\{\}\|\?\<\>\\]+|[^\s]+)")
|
||||
txt = strip.sub('', str(s))
|
||||
|
||||
strip = re.compile(r'\[[\d;]+m')
|
||||
strip = re.compile(r'\[\d+m')
|
||||
txt = strip.sub('', txt)
|
||||
|
||||
return txt
|
||||
@@ -109,24 +109,6 @@ def cyan(string):
|
||||
def white(string):
|
||||
return ColoredString('WHITE', string)
|
||||
|
||||
def rgb(color, string):
|
||||
"""
|
||||
RGB-colored text.
|
||||
|
||||
The `color` argument can have the following formats:
|
||||
- #3f3f3f
|
||||
- 3f3f3f
|
||||
- ('3f', '3f', '3f')
|
||||
- (100, 24, 244)
|
||||
"""
|
||||
if isinstance(color, basestring):
|
||||
color = html.to_rgb(color)
|
||||
else:
|
||||
if isinstance(color[0], basestring):
|
||||
color = (int(color[0],16), int(color[1],16), int(color[2],16))
|
||||
|
||||
return ColoredString(color, string)
|
||||
|
||||
def disable():
|
||||
"""Disables colors."""
|
||||
global DISABLE_COLOR
|
||||
|
||||
@@ -94,7 +94,6 @@ def columns(*cols, **kwargs):
|
||||
cols[_big_col][1] = (cwidth - _total_cols) - len(cols)
|
||||
cols[_big_col][0] = max_width(cols[_big_col][0], cols[_big_col][1]).split('\n')
|
||||
|
||||
|
||||
height = len(max([c[0] for c in cols], key=len))
|
||||
|
||||
for i, (strings, width) in enumerate(cols):
|
||||
|
||||
@@ -15,20 +15,18 @@ import sys
|
||||
STREAM = sys.stderr
|
||||
|
||||
BAR_TEMPLATE = '%s[%s%s] %i/%i\r'
|
||||
BAR_EMPTY_CHAR = '-'
|
||||
BAR_FILLED_CHAR = '='
|
||||
|
||||
DOTS_CHAR = '.'
|
||||
|
||||
|
||||
def bar(it, label='', width=32, hide=False):
|
||||
def bar(it, label='', width=32, hide=False, empty_char='-', filled_char='='):
|
||||
"""Progress iterator. Wrap your iterables with it."""
|
||||
|
||||
def _show(_i):
|
||||
x = int(width*_i/count)
|
||||
if not hide:
|
||||
STREAM.write(BAR_TEMPLATE % (
|
||||
label, BAR_FILLED_CHAR*x, BAR_EMPTY_CHAR*(width-x), _i, count))
|
||||
label, bar_filled_char*x, bar_empty_char*(width-x), _i, count))
|
||||
STREAM.flush()
|
||||
|
||||
count = len(it)
|
||||
|
||||
+24
-4
@@ -11,9 +11,29 @@ Various Python helpers used within clint.
|
||||
from __future__ import absolute_import
|
||||
from __future__ import with_statement
|
||||
|
||||
import sys
|
||||
import errno
|
||||
import os.path
|
||||
from os import makedirs
|
||||
from glob import glob
|
||||
|
||||
|
||||
def expand_path(path):
|
||||
"""Expands directories and globs in given path."""
|
||||
|
||||
paths = []
|
||||
path = os.path.expanduser(path)
|
||||
path = os.path.expandvars(path)
|
||||
|
||||
if os.path.isdir(path):
|
||||
|
||||
for (dir, dirs, files) in os.walk(path):
|
||||
for file in files:
|
||||
paths.append(os.path.join(dir, file))
|
||||
else:
|
||||
paths.extend(glob(path))
|
||||
|
||||
return paths
|
||||
|
||||
|
||||
|
||||
def is_collection(obj):
|
||||
@@ -37,17 +57,17 @@ def mkdir_p(path):
|
||||
|
||||
def tsplit(string, delimiters):
|
||||
"""Behaves str.split but supports tuples of delimiters."""
|
||||
|
||||
|
||||
delimiters = tuple(delimiters)
|
||||
stack = [string,]
|
||||
|
||||
|
||||
for delimiter in delimiters:
|
||||
for i, substring in enumerate(stack):
|
||||
substack = substring.split(delimiter)
|
||||
stack.pop(i)
|
||||
for j, _substring in enumerate(substack):
|
||||
stack.insert(i+j, _substring)
|
||||
|
||||
|
||||
return stack
|
||||
|
||||
def schunk(string, size):
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
sys.path.insert(0, os.path.abspath('..'))
|
||||
|
||||
from clint.textui import colored
|
||||
from clint.packages.colorama.conv import html
|
||||
from clint.packages.colorama import caps
|
||||
from clint.textui import columns
|
||||
|
||||
# Force capability to XTERM256 for now, otherwise it's boring
|
||||
# I'm not sure a reliable detection mechanism even exists...
|
||||
caps.capability = caps.ColorCapability.XTERM256
|
||||
|
||||
def colorizer(colors):
|
||||
for color in colors:
|
||||
yield colored.rgb(color, color)
|
||||
|
||||
if __name__ == '__main__':
|
||||
i = iter(colorizer(html.colors))
|
||||
while True:
|
||||
try:
|
||||
a = i.next()
|
||||
except StopIteration:
|
||||
break
|
||||
try:
|
||||
b = i.next()
|
||||
except StopIteration:
|
||||
b = ""
|
||||
try:
|
||||
c = i.next()
|
||||
except StopIteration:
|
||||
c = ""
|
||||
print columns([a,30],[b,30],[c,30])
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
sys.path.insert(0, os.path.abspath('..'))
|
||||
|
||||
from clint.eng import join
|
||||
from clint.textui import colored, indent, puts
|
||||
|
||||
colors = [
|
||||
colored.blue('blue'),
|
||||
colored.red('red'),
|
||||
colored.yellow('yellow'),
|
||||
colored.green('green'),
|
||||
colored.magenta('magenta')
|
||||
]
|
||||
|
||||
colors = map(str, colors)
|
||||
|
||||
|
||||
puts('Smart:')
|
||||
with indent(4):
|
||||
for i in range(len(colors)):
|
||||
puts(join(colors[:i+1]))
|
||||
puts('\n')
|
||||
puts('Stupid:')
|
||||
with indent(4):
|
||||
for i in range(len(colors)):
|
||||
puts(join(colors[:i+1], im_a_moron=True, conj='\'n'))
|
||||
Reference in New Issue
Block a user