From a53e1f63bcf29cb67c75dd213155fb1197337e07 Mon Sep 17 00:00:00 2001 From: Bastian Kleineidam Date: Thu, 27 Sep 2012 21:59:11 +0200 Subject: [PATCH] Improve console size guessing. --- dosagelib/colorama.py | 141 ++++++++++++++++++++++++++++++++++++++++++ dosagelib/util.py | 29 ++------- 2 files changed, 145 insertions(+), 25 deletions(-) create mode 100644 dosagelib/colorama.py diff --git a/dosagelib/colorama.py b/dosagelib/colorama.py new file mode 100644 index 000000000..fd57a3752 --- /dev/null +++ b/dosagelib/colorama.py @@ -0,0 +1,141 @@ +# These functions are part of the python-colorama module +# They have been adjusted slightly for Dosage +# +# Copyright: (C) 2010 Jonathan Hartley +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name(s) of the copyright holders nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# from winbase.h +STDOUT = -11 +STDERR = -12 + +from ctypes import (windll, byref, Structure, c_char, c_short, c_uint32, + c_ushort) + +handles = { + STDOUT: windll.kernel32.GetStdHandle(STDOUT), + STDERR: windll.kernel32.GetStdHandle(STDERR), +} + +SHORT = c_short +WORD = c_ushort +DWORD = c_uint32 +TCHAR = c_char + +class COORD(Structure): + """struct in wincon.h""" + _fields_ = [ + ('X', SHORT), + ('Y', SHORT), + ] + +class SMALL_RECT(Structure): + """struct in wincon.h.""" + _fields_ = [ + ("Left", SHORT), + ("Top", SHORT), + ("Right", SHORT), + ("Bottom", SHORT), + ] + +class CONSOLE_SCREEN_BUFFER_INFO(Structure): + """struct in wincon.h.""" + _fields_ = [ + ("dwSize", COORD), + ("dwCursorPosition", COORD), + ("wAttributes", WORD), + ("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): + handle = handles[stream_id] + csbi = CONSOLE_SCREEN_BUFFER_INFO() + success = windll.kernel32.GetConsoleScreenBufferInfo( + handle, byref(csbi)) + return csbi + + +def SetConsoleTextAttribute(stream_id, attrs): + handle = handles[stream_id] + return windll.kernel32.SetConsoleTextAttribute(handle, attrs) + + +# from wincon.h +BLACK = 0 +BLUE = 1 +GREEN = 2 +CYAN = 3 +RED = 4 +MAGENTA = 5 +YELLOW = 6 +GREY = 7 + +# from wincon.h +NORMAL = 0x00 # dim text, dim background +BRIGHT = 0x08 # bright text, dim background + +_default_foreground = None +_default_background = None +_default_style = None + + +def init(): + global _default_foreground, _default_background, _default_style + attrs = GetConsoleScreenBufferInfo(STDOUT).wAttributes + _default_foreground = attrs & 7 + _default_background = (attrs >> 4) & 7 + _default_style = attrs & BRIGHT + + +def get_attrs(foreground, background, style): + return foreground + (background << 4) + style + + +def set_console(stream=STDOUT, foreground=None, background=None, style=None): + if foreground is None: + foreground = _default_foreground + if background is None: + background = _default_background + if style is None: + style = _default_style + attrs = get_attrs(foreground, background, style) + SetConsoleTextAttribute(stream, attrs) + + +def reset_console(stream=STDOUT): + set_console(stream=stream) + + +def get_console_size(): + return GetConsoleScreenBufferInfo(STDOUT).dwSize diff --git a/dosagelib/util.py b/dosagelib/util.py index 2feb3d277..b572fb246 100644 --- a/dosagelib/util.py +++ b/dosagelib/util.py @@ -16,11 +16,9 @@ from math import log, floor from .output import out from .configuration import UserAgent, AppName, App, SupportUrl from .fileutil import has_module, is_tty +from . import colorama -has_wconio = has_module("WConio") has_curses = has_module("curses") -has_fcntl = has_module('fcntl') -has_termios = has_module('termios') class NoMatchError(Exception): pass @@ -157,34 +155,15 @@ def get_columns (fp): """Return number of columns for given file.""" if not is_tty(fp): return 80 - if has_wconio: - import WConio - # gettextinfo() returns a tuple - # - left, top, right, bottom: window coordinates - # - textattr, normattr: current attributes - # - videomode: current video mode - # - height, width: screen size - # - curx, cury: current cursor position - # return the width: - return WConio.gettextinfo()[8] + if os.name == 'nt': + return colorama.get_console_size().X if has_curses: import curses try: - curses.setupterm() + curses.setupterm(os.environ.get("TERM"), fp.fileno()) return curses.tigetnum("cols") except curses.error: pass - if has_fcntl and has_termios: - import fcntl, termios, array, struct - st = 'HHHH' - names = 'ws_row', 'ws_col', 'ws_xpixel', 'ws_ypixel' - buf = array.array('b', ' ' * struct.calcsize(st)) - try: - fcntl.ioctl(fp, termios.TIOCGWINSZ, buf, True) - winsize = dict(zip(names, struct.unpack(st, buf.tostring()))) - return winsize['ws_col'] - except IOError: - pass return 80