2 Commits

Author SHA1 Message Date
Wladimir van der Laan 4a06f19e4f fix bug when using normal color syntax 2011-04-10 15:50:51 +02:00
Wladimir J. van der Laan a841043b56 RGB color support 2011-04-10 14:52:22 +02:00
23 changed files with 600 additions and 272 deletions
+1
View File
@@ -2,3 +2,4 @@
MANIFEST
*.pyc
.tox
*~
-2
View File
@@ -14,5 +14,3 @@ Patches and Suggestions
- Morgan Goose
- Travis Swicegood
- Will Thames
- Greg Haskins
- Miguel Araujo <maraujop>
-7
View File
@@ -1,13 +1,6 @@
History
-------
0.2.4
+++++
* New eng module
* Win32 Bugfix
0.2.3
+++++
+2 -2
View File
@@ -19,8 +19,8 @@ from .pipes import piped_in
__title__ = 'clint'
__version__ = '0.2.5'
__build__ = 0x000205
__version__ = '0.2.3'
__build__ = 0x000203
__author__ = 'Kenneth Reitz'
__license__ = 'ISC'
__copyright__ = 'Copyright 2011 Kenneth Reitz'
+38 -18
View File
@@ -13,13 +13,33 @@ from __future__ import absolute_import
import os
from sys import argv
from glob import glob
from .packages.ordereddict import OrderedDict
from .utils import expand_path, is_collection
from .utils import 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."""
@@ -90,20 +110,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))
@@ -192,7 +212,7 @@ class Args(object):
return False
else:
return (x in self.all[index])
except IndexError:
return False
@@ -201,7 +221,7 @@ class Args(object):
"""Returns true if argument exists at given index.
Accepts: integer.
"""
try:
self.all[x]
return True
@@ -211,15 +231,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
@@ -246,21 +266,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
@@ -268,7 +288,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:
@@ -307,7 +327,7 @@ class Args(object):
return self.start_with('-')
@property
@property
def not_flags(self):
"""Returns Arg object excluding flagged arguments."""
@@ -321,7 +341,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))
@@ -338,7 +358,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)
-49
View File
@@ -1,49 +0,0 @@
# -*- 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')
+2 -2
View File
@@ -1,6 +1,6 @@
from .initialise import init, deinit, reinit
from .initialise import init
from .ansi import Fore, Back, Style
from .ansitowin32 import AnsiToWin32
VERSION = '0.2.3'
VERSION = '0.1.18'
+36 -24
View File
@@ -2,11 +2,13 @@
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(code):
return CSI + str(code) + 'm'
def code_to_chars(codes):
codes = [str(code) for code in codes]
return CSI + (";".join(codes)) + 'm'
class AnsiCodes(object):
def __init__(self, codes):
@@ -14,34 +16,44 @@ 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:
BLACK = 30
RED = 31
GREEN = 32
YELLOW = 33
BLUE = 34
MAGENTA = 35
CYAN = 36
WHITE = 37
RESET = 39
_caps_method = 'fg'
BLACK = (30,)
RED = (31,)
GREEN = (32,)
YELLOW = (33,)
BLUE = (34,)
MAGENTA = (35,)
CYAN = (36,)
WHITE = (37,)
RESET = (39,)
class AnsiBack:
BLACK = 40
RED = 41
GREEN = 42
YELLOW = 43
BLUE = 44
MAGENTA = 45
CYAN = 46
WHITE = 47
RESET = 49
_caps_method = 'bg'
BLACK = (40,)
RED = (41,)
GREEN = (42,)
YELLOW = (43,)
BLUE = (44,)
MAGENTA = (45,)
CYAN = (46,)
WHITE = (47,)
RESET = (49,)
class AnsiStyle:
BRIGHT = 1
DIM = 2
NORMAL = 22
RESET_ALL = 0
_caps_method = 'style'
BRIGHT = (1,)
DIM = (2,)
NORMAL = (22,)
RESET_ALL = (0,)
Fore = AnsiCodes( AnsiFore )
Back = AnsiCodes( AnsiBack )
+2 -8
View File
@@ -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,))
elif is_a_tty(self.wrapped):
else:
self.wrapped.write(Style.RESET_ALL)
@@ -173,10 +173,4 @@ 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)
+59
View File
@@ -0,0 +1,59 @@
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
+69
View File
@@ -0,0 +1,69 @@
"""
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)
+184
View File
@@ -0,0 +1,184 @@
"""
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
+115
View File
@@ -0,0 +1,115 @@
"""
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)]
+3 -20
View File
@@ -7,9 +7,6 @@ from .ansitowin32 import AnsiToWin32
orig_stdout = sys.stdout
orig_stderr = sys.stderr
wrapped_stdout = sys.stdout
wrapped_stderr = sys.stderr
atexit_done = False
@@ -19,14 +16,11 @@ def reset_all():
def init(autoreset=False, convert=None, strip=None, wrap=True):
if not wrap and any([autoreset, convert, strip]):
if wrap==False and (autoreset==True or convert==True or strip==True):
raise ValueError('wrap=False conflicts with any other arg=True')
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)
sys.stdout = wrap_stream(orig_stdout, convert, strip, autoreset, wrap)
sys.stderr = wrap_stream(orig_stderr, convert, strip, autoreset, wrap)
global atexit_done
if not atexit_done:
@@ -34,16 +28,6 @@ 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,
@@ -52,4 +36,3 @@ def wrap_stream(stream, convert, strip, autoreset, wrap):
stream = wrapper.stream
return stream
+16 -44
View File
@@ -48,16 +48,8 @@ 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=STDOUT):
def GetConsoleScreenBufferInfo(stream_id):
handle = handles[stream_id]
csbi = CONSOLE_SCREEN_BUFFER_INFO()
success = windll.kernel32.GetConsoleScreenBufferInfo(
@@ -70,54 +62,34 @@ else:
def SetConsoleTextAttribute(stream_id, attrs):
handle = handles[stream_id]
return windll.kernel32.SetConsoleTextAttribute(handle, attrs)
success = windll.kernel32.SetConsoleTextAttribute(handle, attrs)
assert success
def SetConsoleCursorPosition(stream_id, position):
position = COORD(*position)
# 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
position = COORD(*position)
success = windll.kernel32.SetConsoleCursorPosition(handle, position)
assert 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)
# Note that this is hard-coded for ANSI (vs wide) bytes.
success = windll.kernel32.FillConsoleOutputCharacterA(
# AttributeError: function 'FillConsoleOutputCharacter' not found
# could it just be that my types are wrong?
success = windll.kernel32.FillConsoleOutputCharacter(
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)
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))
print(x.dwSize)
print(x.dwCursorPosition)
print(x.wAttributes)
print(x.srWindow)
print(x.dwMaximumWindowSize)
+2 -35
View File
@@ -22,7 +22,8 @@ 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
@@ -66,37 +67,3 @@ 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))
+22 -4
View File
@@ -15,6 +15,7 @@ import re
import sys
from ..packages import colorama
from ..packages.colorama.conv import html
__all__ = (
'red', 'green', 'yellow', 'blue',
@@ -27,8 +28,6 @@ DISABLE_COLOR = False
if not sys.stdout.isatty():
DISABLE_COLOR = True
else:
colorama.init(autoreset=True)
class ColoredString(object):
@@ -41,8 +40,9 @@ class ColoredString(object):
@property
def color_str(self):
if sys.stdout.isatty() and not DISABLE_COLOR:
colorama.init(autoreset=True)
return '%s%s%s' % (
getattr(colorama.Fore, self.color), self.s, colorama.Fore.RESET)
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,6 +109,24 @@ 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
+1
View File
@@ -94,6 +94,7 @@ 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):
+4 -2
View File
@@ -15,18 +15,20 @@ 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, empty_char='-', filled_char='='):
def bar(it, label='', width=32, hide=False):
"""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)
+4 -24
View File
@@ -11,29 +11,9 @@ 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):
@@ -57,17 +37,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):
+40
View File
@@ -0,0 +1,40 @@
#!/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])
-31
View File
@@ -1,31 +0,0 @@
#!/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'))