Improved terminal functions.

This commit is contained in:
Bastian Kleineidam 2012-06-20 22:33:26 +02:00
parent 4dec964cb7
commit c9082aee42
4 changed files with 67 additions and 30 deletions

View file

@ -10,6 +10,7 @@ Changes:
- comics: Removed the twisted and zope dependencies by adding - comics: Removed the twisted and zope dependencies by adding
an internal plugin search mechanism. an internal plugin search mechanism.
- testing: Refactored the test comic routine in proper unit tests. - testing: Refactored the test comic routine in proper unit tests.
- cmdline: Improved terminal feature detection.
Fixes: Fixes:
- comics: Adjusted Xkcd href values. - comics: Adjusted Xkcd href values.

16
dosage
View file

@ -22,7 +22,7 @@ import traceback
from dosagelib import events, scraper from dosagelib import events, scraper
from dosagelib.output import out from dosagelib.output import out
from dosagelib.util import getWindowSize, internal_error from dosagelib.util import is_tty, get_columns, internal_error
from dosagelib.configuration import App, Freeware, Copyright from dosagelib.configuration import App, Freeware, Copyright
def setupOptions(): def setupOptions():
@ -38,14 +38,7 @@ def setupOptions():
parser.add_option('-m', '--module-help', action='store_true', dest='modhelp', help='display help for comic modules') parser.add_option('-m', '--module-help', action='store_true', dest='modhelp', help='display help for comic modules')
parser.add_option('-t', '--timestamps', action='store_true', dest='timestamps', default=False, help='print timestamps for all output at any info level') parser.add_option('-t', '--timestamps', action='store_true', dest='timestamps', default=False, help='print timestamps for all output at any info level')
parser.add_option('-o', '--output', action='store', dest='output', choices=events.getHandlers(), help='output formatting for downloaded comics') parser.add_option('-o', '--output', action='store', dest='output', choices=events.getHandlers(), help='output formatting for downloaded comics')
try: if is_tty(sys.stdout):
getWindowSize()
except NotImplementedError:
progress = False
else:
progress = True
if progress:
parser.add_option('-p', '--progress', action='store_true', dest='progress', default=False, help='display progress bar while downloading comics') parser.add_option('-p', '--progress', action='store_true', dest='progress', default=False, help='display progress bar while downloading comics')
return parser return parser
@ -131,10 +124,7 @@ class Dosage(object):
print '\n'.join(scraper.get_name() for scraper in scrapers) print '\n'.join(scraper.get_name() for scraper in scrapers)
def doColumnList(self, scrapers): def doColumnList(self, scrapers):
try: screenWidth = get_columns()
screenWidth = getWindowSize()
except NotImplementedError:
screenWidth = 80
names = [scraper.get_name() for scraper in scrapers] names = [scraper.get_name() for scraper in scrapers]
maxlen = max([len(name) for name in names]) maxlen = max([len(name) for name in names])
namesPerLine = int(screenWidth / (maxlen + 1)) namesPerLine = int(screenWidth / (maxlen + 1))

22
dosagelib/fileutil.py Normal file
View file

@ -0,0 +1,22 @@
# -*- coding: iso-8859-1 -*-
# Copyright (C) 2012 Bastian Kleineidam
"""
File and path utilities.
"""
def has_module (name):
"""Test if given module can be imported.
@return: flag if import is successful
@rtype: bool
"""
try:
exec "import %s as _bla" % name
return True
except (OSError, ImportError):
# some modules (for example HTMLtidy) raise OSError
return False
def is_tty (fp):
"""Check if a file object is a TTY."""
return (hasattr(fp, "isatty") and fp.isatty())

View file

@ -2,8 +2,6 @@ from __future__ import division
import urllib2, urlparse import urllib2, urlparse
import sys import sys
import struct
import array
import os import os
import cgi import cgi
import re import re
@ -14,6 +12,12 @@ from math import log, floor
from .output import out from .output import out
from .configuration import UserAgent, AppName, App, SupportUrl from .configuration import UserAgent, AppName, App, SupportUrl
from .fileutil import has_module, is_tty
has_wconio = has_module("WConio")
has_curses = has_module("curses")
has_fcntl = has_module('fcntl')
has_termios = has_module('termios')
class NoMatchError(Exception): pass class NoMatchError(Exception): pass
@ -148,21 +152,41 @@ def urlopen(url, referrer=None, retries=5):
return urlobj return urlobj
def getWindowSize():
try: def get_columns (fp):
from fcntl import ioctl """Return number of columns for given file."""
from termios import TIOCGWINSZ if not is_tty(fp):
except ImportError: return 80
raise NotImplementedError if has_wconio:
st = 'HHHH' import WConio
names = 'ws_row', 'ws_col', 'ws_xpixel', 'ws_ypixel' # gettextinfo() returns a tuple
buf = array.array('b', ' ' * struct.calcsize(st)) # - left, top, right, bottom: window coordinates
try: # - textattr, normattr: current attributes
ioctl(sys.stderr, TIOCGWINSZ, buf, True) # - videomode: current video mode
except IOError: # - height, width: screen size
raise NotImplementedError # - curx, cury: current cursor position
winsize = dict(zip(names, struct.unpack(st, buf.tostring()))) # return the width:
return winsize['ws_col'] return WConio.gettextinfo()[8]
if has_curses:
import curses
try:
curses.setupterm()
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
suffixes = ('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB') suffixes = ('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB')