Skip to content

Commit 3702f94

Browse files
committed
vendorize colorama. log updates. rm current debug log formatter, going to rewrite log. test this
1 parent ff11c18 commit 3702f94

File tree

11 files changed

+562
-6
lines changed

11 files changed

+562
-6
lines changed

TODO

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ TODO
2121
it.
2222
- Handle case where switching client via ``$ tmuxp load`` or
2323
``$ tmuxp attach-session`` into another socket may cause an error.
24+
- python 2.6 support
2425

2526
Done
2627
''''

requirements.pip

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
kaptan>=0.5.7
2-
colorama
32
argcomplete

tmuxp/_vendor/__init__.py

Whitespace-only changes.

tmuxp/_vendor/colorama/__init__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.
2+
from .initialise import init, deinit, reinit
3+
from .ansi import Fore, Back, Style
4+
from .ansitowin32 import AnsiToWin32
5+
6+
VERSION = '0.2.7'
7+

tmuxp/_vendor/colorama/ansi.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.
2+
'''
3+
This module generates ANSI character codes to printing colors to terminals.
4+
See: http://en.wikipedia.org/wiki/ANSI_escape_code
5+
'''
6+
7+
CSI = '\033['
8+
9+
def code_to_chars(code):
10+
return CSI + str(code) + 'm'
11+
12+
class AnsiCodes(object):
13+
def __init__(self, codes):
14+
for name in dir(codes):
15+
if not name.startswith('_'):
16+
value = getattr(codes, name)
17+
setattr(self, name, code_to_chars(value))
18+
19+
class AnsiFore:
20+
BLACK = 30
21+
RED = 31
22+
GREEN = 32
23+
YELLOW = 33
24+
BLUE = 34
25+
MAGENTA = 35
26+
CYAN = 36
27+
WHITE = 37
28+
RESET = 39
29+
30+
class AnsiBack:
31+
BLACK = 40
32+
RED = 41
33+
GREEN = 42
34+
YELLOW = 43
35+
BLUE = 44
36+
MAGENTA = 45
37+
CYAN = 46
38+
WHITE = 47
39+
RESET = 49
40+
41+
class AnsiStyle:
42+
BRIGHT = 1
43+
DIM = 2
44+
NORMAL = 22
45+
RESET_ALL = 0
46+
47+
Fore = AnsiCodes( AnsiFore )
48+
Back = AnsiCodes( AnsiBack )
49+
Style = AnsiCodes( AnsiStyle )
50+
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.
2+
import re
3+
import sys
4+
5+
from .ansi import AnsiFore, AnsiBack, AnsiStyle, Style
6+
from .winterm import WinTerm, WinColor, WinStyle
7+
from .win32 import windll
8+
9+
10+
if windll is not None:
11+
winterm = WinTerm()
12+
13+
14+
def is_a_tty(stream):
15+
return hasattr(stream, 'isatty') and stream.isatty()
16+
17+
18+
class StreamWrapper(object):
19+
'''
20+
Wraps a stream (such as stdout), acting as a transparent proxy for all
21+
attribute access apart from method 'write()', which is delegated to our
22+
Converter instance.
23+
'''
24+
def __init__(self, wrapped, converter):
25+
# double-underscore everything to prevent clashes with names of
26+
# attributes on the wrapped stream object.
27+
self.__wrapped = wrapped
28+
self.__convertor = converter
29+
30+
def __getattr__(self, name):
31+
return getattr(self.__wrapped, name)
32+
33+
def write(self, text):
34+
self.__convertor.write(text)
35+
36+
37+
class AnsiToWin32(object):
38+
'''
39+
Implements a 'write()' method which, on Windows, will strip ANSI character
40+
sequences from the text, and if outputting to a tty, will convert them into
41+
win32 function calls.
42+
'''
43+
ANSI_RE = re.compile('\033\[((?:\d|;)*)([a-zA-Z])')
44+
45+
def __init__(self, wrapped, convert=None, strip=None, autoreset=False):
46+
# The wrapped stream (normally sys.stdout or sys.stderr)
47+
self.wrapped = wrapped
48+
49+
# should we reset colors to defaults after every .write()
50+
self.autoreset = autoreset
51+
52+
# create the proxy wrapping our output stream
53+
self.stream = StreamWrapper(wrapped, self)
54+
55+
on_windows = sys.platform.startswith('win')
56+
57+
# should we strip ANSI sequences from our output?
58+
if strip is None:
59+
strip = on_windows
60+
self.strip = strip
61+
62+
# should we should convert ANSI sequences into win32 calls?
63+
if convert is None:
64+
convert = on_windows and is_a_tty(wrapped)
65+
self.convert = convert
66+
67+
# dict of ansi codes to win32 functions and parameters
68+
self.win32_calls = self.get_win32_calls()
69+
70+
# are we wrapping stderr?
71+
self.on_stderr = self.wrapped is sys.stderr
72+
73+
74+
def should_wrap(self):
75+
'''
76+
True if this class is actually needed. If false, then the output
77+
stream will not be affected, nor will win32 calls be issued, so
78+
wrapping stdout is not actually required. This will generally be
79+
False on non-Windows platforms, unless optional functionality like
80+
autoreset has been requested using kwargs to init()
81+
'''
82+
return self.convert or self.strip or self.autoreset
83+
84+
85+
def get_win32_calls(self):
86+
if self.convert and winterm:
87+
return {
88+
AnsiStyle.RESET_ALL: (winterm.reset_all, ),
89+
AnsiStyle.BRIGHT: (winterm.style, WinStyle.BRIGHT),
90+
AnsiStyle.DIM: (winterm.style, WinStyle.NORMAL),
91+
AnsiStyle.NORMAL: (winterm.style, WinStyle.NORMAL),
92+
AnsiFore.BLACK: (winterm.fore, WinColor.BLACK),
93+
AnsiFore.RED: (winterm.fore, WinColor.RED),
94+
AnsiFore.GREEN: (winterm.fore, WinColor.GREEN),
95+
AnsiFore.YELLOW: (winterm.fore, WinColor.YELLOW),
96+
AnsiFore.BLUE: (winterm.fore, WinColor.BLUE),
97+
AnsiFore.MAGENTA: (winterm.fore, WinColor.MAGENTA),
98+
AnsiFore.CYAN: (winterm.fore, WinColor.CYAN),
99+
AnsiFore.WHITE: (winterm.fore, WinColor.GREY),
100+
AnsiFore.RESET: (winterm.fore, ),
101+
AnsiBack.BLACK: (winterm.back, WinColor.BLACK),
102+
AnsiBack.RED: (winterm.back, WinColor.RED),
103+
AnsiBack.GREEN: (winterm.back, WinColor.GREEN),
104+
AnsiBack.YELLOW: (winterm.back, WinColor.YELLOW),
105+
AnsiBack.BLUE: (winterm.back, WinColor.BLUE),
106+
AnsiBack.MAGENTA: (winterm.back, WinColor.MAGENTA),
107+
AnsiBack.CYAN: (winterm.back, WinColor.CYAN),
108+
AnsiBack.WHITE: (winterm.back, WinColor.GREY),
109+
AnsiBack.RESET: (winterm.back, ),
110+
}
111+
112+
113+
def write(self, text):
114+
if self.strip or self.convert:
115+
self.write_and_convert(text)
116+
else:
117+
self.wrapped.write(text)
118+
self.wrapped.flush()
119+
if self.autoreset:
120+
self.reset_all()
121+
122+
123+
def reset_all(self):
124+
if self.convert:
125+
self.call_win32('m', (0,))
126+
elif is_a_tty(self.wrapped):
127+
self.wrapped.write(Style.RESET_ALL)
128+
129+
130+
def write_and_convert(self, text):
131+
'''
132+
Write the given text to our wrapped stream, stripping any ANSI
133+
sequences from the text, and optionally converting them into win32
134+
calls.
135+
'''
136+
cursor = 0
137+
for match in self.ANSI_RE.finditer(text):
138+
start, end = match.span()
139+
self.write_plain_text(text, cursor, start)
140+
self.convert_ansi(*match.groups())
141+
cursor = end
142+
self.write_plain_text(text, cursor, len(text))
143+
144+
145+
def write_plain_text(self, text, start, end):
146+
if start < end:
147+
self.wrapped.write(text[start:end])
148+
self.wrapped.flush()
149+
150+
151+
def convert_ansi(self, paramstring, command):
152+
if self.convert:
153+
params = self.extract_params(paramstring)
154+
self.call_win32(command, params)
155+
156+
157+
def extract_params(self, paramstring):
158+
def split(paramstring):
159+
for p in paramstring.split(';'):
160+
if p != '':
161+
yield int(p)
162+
return tuple(split(paramstring))
163+
164+
165+
def call_win32(self, command, params):
166+
if params == []:
167+
params = [0]
168+
if command == 'm':
169+
for param in params:
170+
if param in self.win32_calls:
171+
func_args = self.win32_calls[param]
172+
func = func_args[0]
173+
args = func_args[1:]
174+
kwargs = dict(on_stderr=self.on_stderr)
175+
func(*args, **kwargs)
176+
elif command in ('H', 'f'): # set cursor position
177+
func = winterm.set_cursor_position
178+
func(params, on_stderr=self.on_stderr)
179+
elif command in ('J'):
180+
func = winterm.erase_data
181+
func(params, on_stderr=self.on_stderr)
182+
elif command == 'A':
183+
if params == () or params == None:
184+
num_rows = 1
185+
else:
186+
num_rows = params[0]
187+
func = winterm.cursor_up
188+
func(num_rows, on_stderr=self.on_stderr)
189+
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.
2+
import atexit
3+
import sys
4+
5+
from .ansitowin32 import AnsiToWin32
6+
7+
8+
orig_stdout = sys.stdout
9+
orig_stderr = sys.stderr
10+
11+
wrapped_stdout = sys.stdout
12+
wrapped_stderr = sys.stderr
13+
14+
atexit_done = False
15+
16+
17+
def reset_all():
18+
AnsiToWin32(orig_stdout).reset_all()
19+
20+
21+
def init(autoreset=False, convert=None, strip=None, wrap=True):
22+
23+
if not wrap and any([autoreset, convert, strip]):
24+
raise ValueError('wrap=False conflicts with any other arg=True')
25+
26+
global wrapped_stdout, wrapped_stderr
27+
sys.stdout = wrapped_stdout = \
28+
wrap_stream(orig_stdout, convert, strip, autoreset, wrap)
29+
sys.stderr = wrapped_stderr = \
30+
wrap_stream(orig_stderr, convert, strip, autoreset, wrap)
31+
32+
global atexit_done
33+
if not atexit_done:
34+
atexit.register(reset_all)
35+
atexit_done = True
36+
37+
38+
def deinit():
39+
sys.stdout = orig_stdout
40+
sys.stderr = orig_stderr
41+
42+
43+
def reinit():
44+
sys.stdout = wrapped_stdout
45+
sys.stderr = wrapped_stdout
46+
47+
48+
def wrap_stream(stream, convert, strip, autoreset, wrap):
49+
if wrap:
50+
wrapper = AnsiToWin32(stream,
51+
convert=convert, strip=strip, autoreset=autoreset)
52+
if wrapper.should_wrap():
53+
stream = wrapper.stream
54+
return stream
55+
56+

0 commit comments

Comments
 (0)