move documentation to be below the declaration and not above, this makes it parsable by python's help command, althought it is not as pretty, but hay, help() is awesome

Signed-off-by: Mattias Andrée <maandree@operamail.com>
This commit is contained in:
Mattias Andrée 2013-08-12 07:54:31 +02:00
parent a18804002b
commit ecdac1b6a1
12 changed files with 583 additions and 579 deletions

View file

@ -33,25 +33,29 @@ from common import *
ARGUMENTLESS = 0
''' '''
Option takes no arguments Option takes no arguments
''' '''
ARGUMENTLESS = 0
ARGUMENTED = 1
''' '''
Option takes one argument per instance Option takes one argument per instance
''' '''
ARGUMENTED = 1
VARIADIC = 2
''' '''
Option consumes all following arguments Option consumes all following arguments
''' '''
VARIADIC = 2
class ArgParser():
''' '''
Simple argument parser Simple argument parser
''' '''
class ArgParser():
def __init__(self, program, description, usage, longdescription = None):
''' '''
Constructor. Constructor.
The short description is printed on same line as the program name The short description is printed on same line as the program name
@ -61,7 +65,6 @@ class ArgParser():
@param usage:str Formated, multi-line, usage text @param usage:str Formated, multi-line, usage text
@param longdescription:str Long, multi-line, description of the program, may be `None` @param longdescription:str Long, multi-line, description of the program, may be `None`
''' '''
def __init__(self, program, description, usage, longdescription = None):
self.linuxvt = ('TERM' in os.environ) and (os.environ['TERM'] == 'linux') self.linuxvt = ('TERM' in os.environ) and (os.environ['TERM'] == 'linux')
self.__program = program self.__program = program
self.__description = description self.__description = description
@ -72,19 +75,20 @@ class ArgParser():
self.optmap = {} self.optmap = {}
def add_argumentless(self, alternatives, help = None):
''' '''
Add option that takes no arguments Add option that takes no arguments
@param alternatives:list<str> Option names @param alternatives:list<str> Option names
@param help:str Short description, use `None` to hide the option @param help:str Short description, use `None` to hide the option
''' '''
def add_argumentless(self, alternatives, help = None):
self.__arguments.append((ARGUMENTLESS, alternatives, None, help)) self.__arguments.append((ARGUMENTLESS, alternatives, None, help))
stdalt = alternatives[0] stdalt = alternatives[0]
self.opts[stdalt] = None self.opts[stdalt] = None
for alt in alternatives: for alt in alternatives:
self.optmap[alt] = (stdalt, ARGUMENTLESS) self.optmap[alt] = (stdalt, ARGUMENTLESS)
def add_argumented(self, alternatives, arg, help = None):
''' '''
Add option that takes one argument Add option that takes one argument
@ -92,13 +96,13 @@ class ArgParser():
@param arg:str The name of the takes argument, one word @param arg:str The name of the takes argument, one word
@param help:str Short description, use `None` to hide the option @param help:str Short description, use `None` to hide the option
''' '''
def add_argumented(self, alternatives, arg, help = None):
self.__arguments.append((ARGUMENTED, alternatives, arg, help)) self.__arguments.append((ARGUMENTED, alternatives, arg, help))
stdalt = alternatives[0] stdalt = alternatives[0]
self.opts[stdalt] = None self.opts[stdalt] = None
for alt in alternatives: for alt in alternatives:
self.optmap[alt] = (stdalt, ARGUMENTED) self.optmap[alt] = (stdalt, ARGUMENTED)
def add_variadic(self, alternatives, arg, help = None):
''' '''
Add option that takes all following argument Add option that takes all following argument
@ -106,7 +110,6 @@ class ArgParser():
@param arg:str The name of the takes arguments, one word @param arg:str The name of the takes arguments, one word
@param help:str Short description, use `None` to hide the option @param help:str Short description, use `None` to hide the option
''' '''
def add_variadic(self, alternatives, arg, help = None):
self.__arguments.append((VARIADIC, alternatives, arg, help)) self.__arguments.append((VARIADIC, alternatives, arg, help))
stdalt = alternatives[0] stdalt = alternatives[0]
self.opts[stdalt] = None self.opts[stdalt] = None
@ -114,13 +117,13 @@ class ArgParser():
self.optmap[alt] = (stdalt, VARIADIC) self.optmap[alt] = (stdalt, VARIADIC)
def parse(self, argv = sys.argv):
''' '''
Parse arguments Parse arguments
@param args:list<str> The command line arguments, should include the execute file at index 0, `sys.argv` is default @param args:list<str> The command line arguments, should include the execute file at index 0, `sys.argv` is default
@return :bool Whether no unrecognised option is used @return :bool Whether no unrecognised option is used
''' '''
def parse(self, argv = sys.argv):
self.argcount = len(argv) - 1 self.argcount = len(argv) - 1
self.files = [] self.files = []
@ -242,10 +245,10 @@ class ArgParser():
return self.rc return self.rc
def help(self):
''' '''
Prints a colourful help message Prints a colourful help message
''' '''
def help(self):
print('\033[1m%s\033[21m %s %s' % (self.__program, '-' if self.linuxvt else '', self.__description)) print('\033[1m%s\033[21m %s %s' % (self.__program, '-' if self.linuxvt else '', self.__description))
print() print()
if self.__longdescription is not None: if self.__longdescription is not None:

View file

@ -36,10 +36,12 @@ from ucs import *
class Backend():
''' '''
Super-ultra-extreme-awesomazing replacement for cowsay Super-ultra-extreme-awesomazing replacement for cowsay
''' '''
class Backend():
def __init__(self, message, ponyfile, wrapcolumn, width, balloon, hyphen, linkcolour, ballooncolour, mode, infolevel):
''' '''
Constructor Constructor
@ -54,7 +56,6 @@ class Backend():
@param mode:str Mode string for the pony @param mode:str Mode string for the pony
@parma infolevel:int 2 if ++info is used, 1 if --info is used and 0 otherwise @parma infolevel:int 2 if ++info is used, 1 if --info is used and 0 otherwise
''' '''
def __init__(self, message, ponyfile, wrapcolumn, width, balloon, hyphen, linkcolour, ballooncolour, mode, infolevel):
self.message = message self.message = message
self.ponyfile = ponyfile self.ponyfile = ponyfile
self.wrapcolumn = None if wrapcolumn is None else wrapcolumn - (0 if balloon is None else balloon.minwidth) self.wrapcolumn = None if wrapcolumn is None else wrapcolumn - (0 if balloon is None else balloon.minwidth)
@ -78,10 +79,10 @@ class Backend():
self.pony = None self.pony = None
def parse(self):
''' '''
Process all data Process all data
''' '''
def parse(self):
self.__loadFile() self.__loadFile()
if self.pony.startswith('$$$\n'): if self.pony.startswith('$$$\n'):
@ -126,14 +127,14 @@ class Backend():
self.__truncate() self.__truncate()
@staticmethod
def formatInfo(info):
''' '''
Format metadata to be nicely printed, this include bold keys Format metadata to be nicely printed, this include bold keys
@param info:str The metadata @param info:str The metadata
@return :str The metadata nicely formated @return :str The metadata nicely formated
''' '''
@staticmethod
def formatInfo(info):
info = info.split('\n') info = info.split('\n')
tags = '' tags = ''
comment = '' comment = ''
@ -156,10 +157,10 @@ class Backend():
return tags + comment return tags + comment
def __unpadMessage(self):
''' '''
Remove padding spaces fortune cookies are padded with whitespace (damn featherbrains) Remove padding spaces fortune cookies are padded with whitespace (damn featherbrains)
''' '''
def __unpadMessage(self):
lines = self.message.split('\n') lines = self.message.split('\n')
for spaces in (128, 64, 32, 16, 8, 4, 2, 1): for spaces in (128, 64, 32, 16, 8, 4, 2, 1):
padded = True padded = True
@ -176,10 +177,10 @@ class Backend():
self.message = '\n'.join(lines) self.message = '\n'.join(lines)
def __expandMessage(self):
''' '''
Converts all tabs in the message to spaces by expanding Converts all tabs in the message to spaces by expanding
''' '''
def __expandMessage(self):
lines = self.message.split('\n') lines = self.message.split('\n')
buf = '' buf = ''
for line in lines: for line in lines:
@ -203,18 +204,18 @@ class Backend():
self.message = buf[:-1] self.message = buf[:-1]
def __loadFile(self):
''' '''
Loads the pony file Loads the pony file
''' '''
def __loadFile(self):
with open(self.ponyfile, 'rb') as ponystream: with open(self.ponyfile, 'rb') as ponystream:
self.pony = ponystream.read().decode('utf8', 'replace') self.pony = ponystream.read().decode('utf8', 'replace')
def __truncate(self):
''' '''
Truncate output to the width of the screen Truncate output to the width of the screen
''' '''
def __truncate(self):
if self.width is None: if self.width is None:
return return
lines = self.output.split('\n') lines = self.output.split('\n')
@ -237,10 +238,10 @@ class Backend():
self.output = self.output[:-1] self.output = self.output[:-1]
def __processPony(self):
''' '''
Process the pony file and generate output to self.output Process the pony file and generate output to self.output
''' '''
def __processPony(self):
self.output = '' self.output = ''
AUTO_PUSH = '\033[01010~' AUTO_PUSH = '\033[01010~'
@ -307,7 +308,7 @@ class Backend():
w -= x; w -= x;
else: else:
w = int(w) w = int(w)
balloon = self.__getballoon(w, h, x, justify, indent) balloon = self.__getBalloon(w, h, x, justify, indent)
balloon = balloon.split('\n') balloon = balloon.split('\n')
balloon = [AUTO_PUSH + self.ballooncolour + item + AUTO_POP for item in balloon] balloon = [AUTO_PUSH + self.ballooncolour + item + AUTO_POP for item in balloon]
for b in balloon[0]: for b in balloon[0]:
@ -383,6 +384,8 @@ class Backend():
self.output = '\n'.join(self.output) self.output = '\n'.join(self.output)
@staticmethod
def getColour(input, offset):
''' '''
Gets colour code att the currect offset in a buffer Gets colour code att the currect offset in a buffer
@ -390,8 +393,6 @@ class Backend():
@param offset:int The offset at where to start reading, a escape must begin here @param offset:int The offset at where to start reading, a escape must begin here
@return :str The escape sequence @return :str The escape sequence
''' '''
@staticmethod
def getColour(input, offset):
(i, n) = (offset, len(input)) (i, n) = (offset, len(input))
rc = input[i] rc = input[i]
i += 1 i += 1
@ -439,14 +440,14 @@ class Backend():
return rc return rc
@staticmethod
def len(input):
''' '''
Calculates the number of visible characters in a text Calculates the number of visible characters in a text
@param input:str The input buffer @param input:str The input buffer
@return :int The number of visible characters @return :int The number of visible characters
''' '''
@staticmethod
def len(input):
(rc, i, n) = (0, 0, len(input)) (rc, i, n) = (0, 0, len(input))
while i < n: while i < n:
c = input[i] c = input[i]
@ -459,6 +460,7 @@ class Backend():
return rc return rc
def __getBalloon(self, width, height, innerleft, justify, left):
''' '''
Generates a balloon with the message Generates a balloon with the message
@ -470,7 +472,6 @@ class Backend():
@param left:int The column where the balloon starts @param left:int The column where the balloon starts
@return :str The balloon the the message as a string @return :str The balloon the the message as a string
''' '''
def __getballoon(self, width, height, innerleft, justify, left):
wrap = None wrap = None
if self.wrapcolumn is not None: if self.wrapcolumn is not None:
wrap = self.wrapcolumn - left wrap = self.wrapcolumn - left
@ -508,6 +509,7 @@ class Backend():
return rc return rc
def __wrapMessage(self, message, wrap):
''' '''
Wraps the message Wraps the message
@ -515,7 +517,6 @@ class Backend():
@param wrap:int The width at where to force wrapping @param wrap:int The width at where to force wrapping
@return :str The message wrapped @return :str The message wrapped
''' '''
def __wrapMessage(self, message, wrap):
wraplimit = os.environ['PONYSAY_WRAP_LIMIT'] if 'PONYSAY_WRAP_LIMIT' in os.environ else '' wraplimit = os.environ['PONYSAY_WRAP_LIMIT'] if 'PONYSAY_WRAP_LIMIT' in os.environ else ''
wraplimit = 8 if len(wraplimit) == 0 else int(wraplimit) wraplimit = 8 if len(wraplimit) == 0 else int(wraplimit)
@ -579,11 +580,11 @@ class Backend():
nbsp = b[map[mm + x]] == ' ' # nbsp nbsp = b[map[mm + x]] == ' ' # nbsp
m = map[mm + x] m = map[mm + x]
if ('­' in b[bisub : m]) and not nbsp: # sort hyphen if ('­' in b[bisub : m]) and not nbsp: # soft hyphen
hyphen = m - 1 hyphen = m - 1
while b[hyphen] != '­': # sort hyphen while b[hyphen] != '­': # soft hyphen
hyphen -= 1 hyphen -= 1
while map[mm + x] > hyphen: ## Only looking backward, if foreward is required the word is probabily not hyphenated correctly while map[mm + x] > hyphen: ## Only looking backward, if forward is required the word is probabily not hyphenated correctly
x -= 1 x -= 1
x += 1 x += 1
m = map[mm + x] m = map[mm + x]

View file

@ -34,10 +34,12 @@ from ucs import *
class Balloon():
''' '''
Balloon format class Balloon format class
''' '''
class Balloon():
def __init__(self, link, linkmirror, linkcross, ww, ee, nw, nnw, n, nne, ne, nee, e, see, se, sse, s, ssw, sw, sww, w, nww):
''' '''
Constructor Constructor
@ -63,7 +65,6 @@ class Balloon():
@param w:str See the info manual @param w:str See the info manual
@param nww:str See the info manual @param nww:str See the info manual
''' '''
def __init__(self, link, linkmirror, linkcross, ww, ee, nw, nnw, n, nne, ne, nee, e, see, se, sse, s, ssw, sw, sww, w, nww):
(self.link, self.linkmirror, self.linkcross) = (link, linkmirror, linkcross) (self.link, self.linkmirror, self.linkcross) = (link, linkmirror, linkcross)
(self.ww, self.ee) = (ww, ee) (self.ww, self.ee) = (ww, ee)
(self.nw, self.ne, self.se, self.sw) = (nw, ne, se, sw) (self.nw, self.ne, self.se, self.sw) = (nw, ne, se, sw)
@ -86,6 +87,7 @@ class Balloon():
self.minheight = minN + minS self.minheight = minN + minS
def get(self, minw, minh, lines, lencalc):
''' '''
Generates a balloon with a message Generates a balloon with a message
@ -95,7 +97,6 @@ class Balloon():
@param lencalc:int(str) Function used to compute the length of a text line @param lencalc:int(str) Function used to compute the length of a text line
@return :str The balloon as a formated string @return :str The balloon as a formated string
''' '''
def get(self, minw, minh, lines, lencalc):
## Get dimension ## Get dimension
h = self.minheight + len(lines) h = self.minheight + len(lines)
w = self.minwidth + lencalc(max(lines, key = lencalc)) w = self.minwidth + lencalc(max(lines, key = lencalc))
@ -138,6 +139,8 @@ class Balloon():
return '\n'.join(rc) return '\n'.join(rc)
@staticmethod
def fromFile(balloonfile, isthink):
''' '''
Creates the balloon style object Creates the balloon style object
@ -145,8 +148,6 @@ class Balloon():
@param isthink:bool Whether the ponythink command is used @param isthink:bool Whether the ponythink command is used
@return :Balloon Instance describing the balloon's style @return :Balloon Instance describing the balloon's style
''' '''
@staticmethod
def fromFile(balloonfile, isthink):
## Use default balloon if none is specified ## Use default balloon if none is specified
if balloonfile is None: if balloonfile is None:
if isthink: if isthink:

View file

@ -33,19 +33,20 @@ from common import *
class ColourStack():
''' '''
ANSI colour stack ANSI colour stack
This is used to make layers with independent coloursations This is used to make layers with independent coloursations
''' '''
class ColourStack():
def __init__(self, autopush, autopop):
''' '''
Constructor Constructor
@param autopush:str String that, when used, will create a new independently colourised layer @param autopush:str String that, when used, will create a new independently colourised layer
@param autopop:str String that, when used, will end the current layer and continue of the previous layer @param autopop:str String that, when used, will end the current layer and continue of the previous layer
''' '''
def __init__(self, autopush, autopop):
self.autopush = autopush self.autopush = autopush
self.autopop = autopop self.autopop = autopop
self.lenpush = len(autopush) self.lenpush = len(autopush)
@ -56,24 +57,24 @@ class ColourStack():
self.seq = None self.seq = None
def push(self):
''' '''
Create a new independently colourised layer Create a new independently colourised layer
@return :str String that should be inserted into your buffer @return :str String that should be inserted into your buffer
''' '''
def push(self):
self.stack.insert(0, [self.bufproto, None, None, [False] * 9]) self.stack.insert(0, [self.bufproto, None, None, [False] * 9])
if len(self.stack) == 1: if len(self.stack) == 1:
return None return None
return '\033[0m' return '\033[0m'
def pop(self):
''' '''
End the current layer and continue of the previous layer End the current layer and continue of the previous layer
@return :str String that should be inserted into your buffer @return :str String that should be inserted into your buffer
''' '''
def pop(self):
old = self.stack.pop(0) old = self.stack.pop(0)
rc = '\033[0;' rc = '\033[0;'
if len(self.stack) == 0: # last resort in case something made it pop too mush if len(self.stack) == 0: # last resort in case something made it pop too mush
@ -87,6 +88,7 @@ class ColourStack():
return rc[:-1] + 'm' return rc[:-1] + 'm'
def feed(self, char):
''' '''
Use this, in sequence, for which character in your buffer that contains yor autopush and autopop Use this, in sequence, for which character in your buffer that contains yor autopush and autopop
string, the automatically get push and pop string to insert after each character string, the automatically get push and pop string to insert after each character
@ -94,7 +96,6 @@ class ColourStack():
@param :chr One character in your buffer @param :chr One character in your buffer
@return :str The text to insert after the input character @return :str The text to insert after the input character
''' '''
def feed(self, char):
if self.seq is not None: if self.seq is not None:
self.seq += char self.seq += char
if (char == '~') or (('a' <= char) and (char <= 'z')) or (('A' <= char) and (char <= 'Z')): if (char == '~') or (('a' <= char) and (char <= 'z')) or (('A' <= char) and (char <= 'Z')):

View file

@ -38,13 +38,14 @@ from subprocess import Popen, PIPE
VERSION = 'dev' # this line should not be edited, it is fixed by the build system
''' '''
The version of ponysay The version of ponysay
''' '''
VERSION = 'dev' # this line should not be edited, it is fixed by the build system
def print(text = '', end = '\n'):
''' '''
Hack to enforce UTF-8 in output (in the future, if you see anypony not using utf-8 in Hack to enforce UTF-8 in output (in the future, if you see anypony not using utf-8 in
programs by default, report them to Princess Celestia so she can banish them to the moon) programs by default, report them to Princess Celestia so she can banish them to the moon)
@ -52,26 +53,25 @@ programs by default, report them to Princess Celestia so she can banish them to
@param text:str The text to print (empty string is default) @param text:str The text to print (empty string is default)
@param end:str The appendix to the text to print (line breaking is default) @param end:str The appendix to the text to print (line breaking is default)
''' '''
def print(text = '', end = '\n'):
sys.stdout.buffer.write((str(text) + end).encode('utf-8')) sys.stdout.buffer.write((str(text) + end).encode('utf-8'))
def printerr(text = '', end = '\n'):
''' '''
stderr equivalent to print() stderr equivalent to print()
@param text:str The text to print (empty string is default) @param text:str The text to print (empty string is default)
@param end:str The appendix to the text to print (line breaking is default) @param end:str The appendix to the text to print (line breaking is default)
''' '''
def printerr(text = '', end = '\n'):
sys.stderr.buffer.write((str(text) + end).encode('utf-8')) sys.stderr.buffer.write((str(text) + end).encode('utf-8'))
fd3 = None fd3 = None
def printinfo(text = '', end = '\n'):
''' '''
/proc/self/fd/3 equivalent to print() /proc/self/fd/3 equivalent to print()
@param text:str The text to print (empty string is default) @param text:str The text to print (empty string is default)
@param end:str The appendix to the text to print (line breaking is default) @param end:str The appendix to the text to print (line breaking is default)
''' '''
def printinfo(text = '', end = '\n'):
global fd3 global fd3
if os.path.exists('/proc/self/fd/3') and not os.path.isdir(os.path.realpath('/proc/self/fd/3')): if os.path.exists('/proc/self/fd/3') and not os.path.isdir(os.path.realpath('/proc/self/fd/3')):
if fd3 is None: if fd3 is None:
@ -80,6 +80,7 @@ def printinfo(text = '', end = '\n'):
fd3.write(str(text) + end) fd3.write(str(text) + end)
def endswith(text, ending):
''' '''
Checks whether a text ends with a specific text, but has more Checks whether a text ends with a specific text, but has more
@ -87,16 +88,15 @@ Checks whether a text ends with a specific text, but has more
@param ending:str The desired end of the text @param ending:str The desired end of the text
@return :bool The result of the test @return :bool The result of the test
''' '''
def endswith(text, ending):
return text.endswith(ending) and not (text == ending) return text.endswith(ending) and not (text == ending)
def gettermsize():
''' '''
Gets the size of the terminal in (rows, columns) Gets the size of the terminal in (rows, columns)
@return (rows, columns):(int, int) The number or lines and the number of columns in the terminal's display area @return (rows, columns):(int, int) The number or lines and the number of columns in the terminal's display area
''' '''
def gettermsize():
## Call `stty` to determine the size of the terminal, this way is better than using python's ncurses ## Call `stty` to determine the size of the terminal, this way is better than using python's ncurses
for channel in (sys.stderr, sys.stdout, sys.stdin): for channel in (sys.stderr, sys.stdout, sys.stdin):
termsize = Popen(['stty', 'size'], stdout=PIPE, stdin=channel, stderr=PIPE).communicate()[0] termsize = Popen(['stty', 'size'], stdout=PIPE, stdin=channel, stderr=PIPE).communicate()[0]

View file

@ -33,18 +33,19 @@ from common import *
class KMS():
''' '''
KMS support utilisation KMS support utilisation
''' '''
class KMS():
@staticmethod
def usingkms(linuxvt):
''' '''
Identifies whether KMS support is utilised Identifies whether KMS support is utilised
@param linuxvt:bool Whether Linux VT is used @param linuxvt:bool Whether Linux VT is used
@return :bool Whether KMS support is utilised @return :bool Whether KMS support is utilised
''' '''
@staticmethod
def usingkms(linuxvt):
## KMS is not utilised if Linux VT is not used ## KMS is not utilised if Linux VT is not used
if not linuxvt: if not linuxvt:
return False return False
@ -64,6 +65,8 @@ class KMS():
return env_kms != '' return env_kms != ''
@staticmethod
def kms(pony, home, linuxvt):
''' '''
Returns the file name of the input pony converted to a KMS pony, or if KMS is not used, the input pony itself Returns the file name of the input pony converted to a KMS pony, or if KMS is not used, the input pony itself
@ -72,8 +75,6 @@ class KMS():
@param linuxvt:bool Whether Linux VT is used @param linuxvt:bool Whether Linux VT is used
@return :str Pony file to display @return :str Pony file to display
''' '''
@staticmethod
def kms(pony, home, linuxvt):
## If not in Linux VT, return the pony as is ## If not in Linux VT, return the pony as is
if not linuxvt: if not linuxvt:
return pony return pony

View file

@ -34,17 +34,18 @@ from ucs import *
class List():
''' '''
File listing functions File listing functions
''' '''
class List():
@staticmethod
def __columnise(ponies):
''' '''
Columnise a list and prints it Columnise a list and prints it
@param ponies:list<(str, str)> All items to list, each item should have to elements: unformated name, formated name @param ponies:list<(str, str)> All items to list, each item should have to elements: unformated name, formated name
''' '''
@staticmethod
def __columnise(ponies):
## Get terminal width, and a 2 which is the space between columns ## Get terminal width, and a 2 which is the space between columns
termwidth = gettermsize()[1] + 2 termwidth = gettermsize()[1] + 2
## Sort the ponies, and get the cells' widths, and the largest width + 2 ## Sort the ponies, and get the cells' widths, and the largest width + 2
@ -92,6 +93,8 @@ class List():
print() print()
@staticmethod
def simplelist(ponydirs, quoters = [], ucsiser = None):
''' '''
Lists the available ponies Lists the available ponies
@ -99,8 +102,6 @@ class List():
@param quoters:__in__(str)bool Set of ponies that of quotes @param quoters:__in__(str)bool Set of ponies that of quotes
@param ucsiser:(list<str>)?void Function used to UCS:ise names @param ucsiser:(list<str>)?void Function used to UCS:ise names
''' '''
@staticmethod
def simplelist(ponydirs, quoters = [], ucsiser = None):
for ponydir in ponydirs: # Loop ponydirs for ponydir in ponydirs: # Loop ponydirs
## Get all ponies in the directory ## Get all ponies in the directory
_ponies = os.listdir(ponydir) _ponies = os.listdir(ponydir)
@ -122,6 +123,8 @@ class List():
List.__columnise([(pony, '\033[1m' + pony + '\033[21m' if pony in quoters else pony) for pony in ponies]) List.__columnise([(pony, '\033[1m' + pony + '\033[21m' if pony in quoters else pony) for pony in ponies])
@staticmethod
def linklist(ponydirs = None, quoters = [], ucsiser = None):
''' '''
Lists the available ponies with alternatives inside brackets Lists the available ponies with alternatives inside brackets
@ -129,8 +132,6 @@ class List():
@param quoters:__in__(str)bool Set of ponies that of quotes @param quoters:__in__(str)bool Set of ponies that of quotes
@param ucsiser:(list<str>, map<str, str>)?void Function used to UCS:ise names @param ucsiser:(list<str>, map<str, str>)?void Function used to UCS:ise names
''' '''
@staticmethod
def linklist(ponydirs = None, quoters = [], ucsiser = None):
## Get the size of the terminal ## Get the size of the terminal
termsize = gettermsize() termsize = gettermsize()
@ -200,6 +201,8 @@ class List():
List.__columnise(list(ponies)) List.__columnise(list(ponies))
@staticmethod
def onelist(standarddirs, extradirs = None, ucsiser = None):
''' '''
Lists the available ponies on one column without anything bold or otherwise formated Lists the available ponies on one column without anything bold or otherwise formated
@ -207,8 +210,6 @@ class List():
@param extra:itr<str>? Include extra ponies @param extra:itr<str>? Include extra ponies
@param ucsiser:(list<str>)?void Function used to UCS:ise names @param ucsiser:(list<str>)?void Function used to UCS:ise names
''' '''
@staticmethod
def onelist(standarddirs, extradirs = None, ucsiser = None):
## Get all pony files ## Get all pony files
_ponies = [] _ponies = []
if standarddirs is not None: if standarddirs is not None:
@ -237,14 +238,14 @@ class List():
print(pony) print(pony)
@staticmethod
def balloonlist(balloondirs, isthink):
''' '''
Prints a list of all balloons Prints a list of all balloons
@param balloondirs:itr<str> The balloon directories to use @param balloondirs:itr<str> The balloon directories to use
@param isthink:bool Whether the ponythink command is used @param isthink:bool Whether the ponythink command is used
''' '''
@staticmethod
def balloonlist(balloondirs, isthink):
## Get the size of the terminal ## Get the size of the terminal
termsize = gettermsize() termsize = gettermsize()

View file

@ -33,18 +33,19 @@ from common import *
class Metadata():
''' '''
Metadata functions Metadata functions
''' '''
class Metadata():
@staticmethod
def makeRestrictionLogic(restriction):
''' '''
Make restriction test logic function Make restriction test logic function
@param restriction:list<string> Metadata based restrictions @param restriction:list<string> Metadata based restrictions
@return :dict<str, str>bool Test function @return :dict<str, str>bool Test function
''' '''
@staticmethod
def makeRestrictionLogic(restriction):
def get_test(cell): def get_test(cell):
strict = cell[0][-1] != '?' strict = cell[0][-1] != '?'
key = cell[0] key = cell[0]
@ -109,6 +110,8 @@ class Metadata():
return Logic(table) return Logic(table)
@staticmethod
def restrictedPonies(ponydir, logic):
''' '''
Get ponies that pass restriction Get ponies that pass restriction
@ -116,8 +119,6 @@ class Metadata():
@param logic:(str)bool Restriction test functor @param logic:(str)bool Restriction test functor
@return :list<str> Passed ponies @return :list<str> Passed ponies
''' '''
@staticmethod
def restrictedPonies(ponydir, logic):
import pickle import pickle
passed = [] passed = []
if os.path.exists(ponydir + 'metadata'): if os.path.exists(ponydir + 'metadata'):
@ -131,6 +132,8 @@ class Metadata():
return passed return passed
@staticmethod
def getfitting(fitting, requirement, file):
''' '''
Get ponies that fit the terminal Get ponies that fit the terminal
@ -138,8 +141,6 @@ class Metadata():
@param requirement:int The maximum allowed value @param requirement:int The maximum allowed value
@param file:istream The file with all data @param file:istream The file with all data
''' '''
@staticmethod
def getfitting(fitting, requirement, file):
data = file.read() # not too much data, can load everything at once data = file.read() # not too much data, can load everything at once
ptr = 0 ptr = 0
while data[ptr] != 47: # 47 == ord('/') while data[ptr] != 47: # 47 == ord('/')

View file

@ -3,13 +3,31 @@
''' '''
ponysay - Ponysay, cowsay reimplementation for ponies ponysay - Ponysay, cowsay reimplementation for ponies
Copyright (C) 2012, 2013 Erkin Batu Altunbaş et al. Copyright (C) 2012, 2013 Erkin Batu Altunbaş et al.
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it This program is free software: you can redistribute it and/or modify
and/or modify it under the terms of the Do What The Fuck You Want it under the terms of the GNU General Public License as published by
To Public License, Version 2, as published by Sam Hocevar. See the Free Software Foundation, either version 3 of the License, or
http://sam.zoy.org/wtfpl/COPYING for more details. (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
If you intend to redistribute ponysay or a fork of it commercially,
it contains aggregated images, some of which may not be commercially
redistribute, you would be required to remove those. To determine
whether or not you may commercially redistribute an image make use
that line FREE: yes, is included inside the image between two $$$
lines and the FREE is and upper case and directly followed by
the colon.
''' '''
from common import * from common import *
from backend import * from backend import *
@ -22,29 +40,29 @@ from metadata import *
class Ponysay():
''' '''
This is the mane class of ponysay This is the mane class of ponysay
''' '''
class Ponysay():
def __init__(self):
''' '''
Constructor Constructor
''' '''
def __init__(self):
''' # The user's home directory
The user's home directory
'''
self.HOME = os.environ['HOME'] if 'HOME' in os.environ else '' self.HOME = os.environ['HOME'] if 'HOME' in os.environ else ''
if len(self.HOME) == 0: if len(self.HOME) == 0:
os.environ['HOME'] = self.HOME = os.path.expanduser('~') os.environ['HOME'] = self.HOME = os.path.expanduser('~')
def parsefile(file):
''' '''
Parse a file name encoded with environment variables Parse a file name encoded with environment variables
@param file The encoded file name @param file The encoded file name
@return The target file name, None if the environment variables are not declared @return The target file name, None if the environment variables are not declared
''' '''
def parsefile(file):
if '$' in file: if '$' in file:
buf = '' buf = ''
esc = False esc = False
@ -88,21 +106,15 @@ class Ponysay():
os.environ['HOME'] = self.HOME = os.path.expanduser('~') os.environ['HOME'] = self.HOME = os.path.expanduser('~')
''' # Whether any unrecognised options was parsed, this should be set by the invoker before run()
Whether any unrecognised options was parsed, this should be set by the invoker before run()
'''
self.unrecognised = False self.unrecognised = False
''' # Whether the program is execute in Linux VT (TTY)
Whether the program is execute in Linux VT (TTY)
'''
self.linuxvt = ('TERM' in os.environ) and (os.environ['TERM'] == 'linux') self.linuxvt = ('TERM' in os.environ) and (os.environ['TERM'] == 'linux')
''' # Whether the script is executed as ponythink
Whether the script is executed as ponythink
'''
self.isthink = sys.argv[0] self.isthink = sys.argv[0]
if os.sep in self.isthink: if os.sep in self.isthink:
self.isthink = self.isthink[self.isthink.rfind(os.sep) + 1:] self.isthink = self.isthink[self.isthink.rfind(os.sep) + 1:]
@ -111,31 +123,21 @@ class Ponysay():
self.isthink = self.isthink.endswith('think') self.isthink = self.isthink.endswith('think')
''' # Whether stdin is piped
Whether stdin is piped
'''
self.pipelinein = not sys.stdin.isatty() self.pipelinein = not sys.stdin.isatty()
''' # Whether stdout is piped
Whether stdout is piped
'''
self.pipelineout = not sys.stdout.isatty() self.pipelineout = not sys.stdout.isatty()
''' # Whether stderr is piped
Whether stderr is piped
'''
self.pipelineerr = not sys.stderr.isatty() self.pipelineerr = not sys.stderr.isatty()
''' # Whether KMS is used
Whether KMS is used
'''
self.usekms = KMS.usingkms(self.linuxvt) self.usekms = KMS.usingkms(self.linuxvt)
''' # Mode string that modifies or adds $ variables in the pony image
Mode string that modifies or adds $ variables in the pony image
'''
self.mode = '' self.mode = ''
@ -152,9 +154,7 @@ class Ponysay():
]] ]]
''' # The directories where pony files are stored, ttyponies/ are used if the terminal is Linux VT (also known as TTY) and not with KMS
The directories where pony files are stored, ttyponies/ are used if the terminal is Linux VT (also known as TTY) and not with KMS
'''
appendset = set() appendset = set()
self.xponydirs = [] self.xponydirs = []
_ponydirs = share('ponies/') _ponydirs = share('ponies/')
@ -171,9 +171,7 @@ class Ponysay():
appendset.add(ponydir) appendset.add(ponydir)
''' # The directories where pony files are stored, extrattyponies/ are used if the terminal is Linux VT (also known as TTY) and not with KMS
The directories where pony files are stored, extrattyponies/ are used if the terminal is Linux VT (also known as TTY) and not with KMS
'''
appendset = set() appendset = set()
self.extraxponydirs = [] self.extraxponydirs = []
_extraponydirs = share('extraponies/') _extraponydirs = share('extraponies/')
@ -190,9 +188,7 @@ class Ponysay():
appendset.add(extraponydir) appendset.add(extraponydir)
''' # The directories where quotes files are stored
The directories where quotes files are stored
'''
appendset = set() appendset = set()
self.quotedirs = [] self.quotedirs = []
_quotedirs = share('quotes/') _quotedirs = share('quotes/')
@ -202,9 +198,7 @@ class Ponysay():
appendset.add(quotedir) appendset.add(quotedir)
''' # The directories where balloon style files are stored
The directories where balloon style files are stored
'''
appendset = set() appendset = set()
self.balloondirs = [] self.balloondirs = []
_balloondirs = share('balloons/') _balloondirs = share('balloons/')
@ -214,9 +208,7 @@ class Ponysay():
appendset.add(balloondir) appendset.add(balloondir)
''' # ucsmap files
ucsmap files
'''
appendset = set() appendset = set()
self.ucsmaps = [] self.ucsmaps = []
_ucsmaps = share('ucsmap/') _ucsmaps = share('ucsmap/')
@ -227,24 +219,24 @@ class Ponysay():
def run(self, args):
''' '''
Starts the part of the program the arguments indicate Starts the part of the program the arguments indicate
@param args:ArgParser Parsed command line arguments @param args:ArgParser Parsed command line arguments
''' '''
def run(self, args):
if (args.argcount == 0) and not self.pipelinein: if (args.argcount == 0) and not self.pipelinein:
args.help() args.help()
exit(254) exit(254)
return return
def test(*keys):
''' '''
Test arguments written in negation-free disjunctive normal form Test arguments written in negation-free disjunctive normal form
@param keys:*str|itr<str> A list of keys and set of keys, any of which must exists, a set of keys only passes if all of those exists @param keys:*str|itr<str> A list of keys and set of keys, any of which must exists, a set of keys only passes if all of those exists
@return :bool Whether the check passed @return :bool Whether the check passed
''' '''
def test(*keys):
for key in keys: for key in keys:
if isinstance(key, str): if isinstance(key, str):
if args.opts[key] is not None: if args.opts[key] is not None:
@ -328,21 +320,21 @@ class Ponysay():
## Methods that run before the mane methods ## ## Methods that run before the mane methods ##
############################################## ##############################################
def __extraponies(self):
''' '''
Use extra ponies Use extra ponies
''' '''
def __extraponies(self):
## Change ponydir to extraponydir ## Change ponydir to extraponydir
self.ponydirs[:] = self.extraponydirs self.ponydirs[:] = self.extraponydirs
self.quotedirs[:] = [] ## TODO +q self.quotedirs[:] = [] ## TODO +q
def __bestpony(self, args):
''' '''
Use best.pony if nothing else is set Use best.pony if nothing else is set
@param args:ArgParser Parsed command line arguments @param args:ArgParser Parsed command line arguments
''' '''
def __bestpony(self, args):
## Set best.pony as the pony to display if none is selected ## Set best.pony as the pony to display if none is selected
def test(keys, strict): def test(keys, strict):
if strict: if strict:
@ -368,12 +360,12 @@ class Ponysay():
break break
def __ucsremap(self, args):
''' '''
Apply pony name remapping to args according to UCS settings Apply pony name remapping to args according to UCS settings
@param args:ArgParser Parsed command line arguments @param args:ArgParser Parsed command line arguments
''' '''
def __ucsremap(self, args):
## Read UCS configurations ## Read UCS configurations
env_ucs = os.environ['PONYSAY_UCS_ME'] if 'PONYSAY_UCS_ME' in os.environ else '' env_ucs = os.environ['PONYSAY_UCS_ME'] if 'PONYSAY_UCS_ME' in os.environ else ''
ucs_conf = 0 ucs_conf = 0
@ -413,13 +405,13 @@ class Ponysay():
## Auxiliary methods ## ## Auxiliary methods ##
####################### #######################
def __ucsise(self, ponies, links = None):
''' '''
Apply UCS:ise pony names according to UCS settings Apply UCS:ise pony names according to UCS settings
@param ponies:list<str> List of all ponies (of interrest) @param ponies:list<str> List of all ponies (of interrest)
@param links:map<str, str>? Map to fill with simulated symlink ponies, may be `None` @param links:map<str, str>? Map to fill with simulated symlink ponies, may be `None`
''' '''
def __ucsise(self, ponies, links = None):
## Read UCS configurations ## Read UCS configurations
env_ucs = os.environ['PONYSAY_UCS_ME'] if 'PONYSAY_UCS_ME' in os.environ else '' env_ucs = os.environ['PONYSAY_UCS_ME'] if 'PONYSAY_UCS_ME' in os.environ else ''
ucs_conf = 0 ucs_conf = 0
@ -460,6 +452,7 @@ class Ponysay():
ponies[j] = map[ponies[j]] ponies[j] = map[ponies[j]]
def __getpony(self, selection, args, alt = False):
''' '''
Returns one file with full path and ponyquote that should be used, names is filter for names, also accepts filepaths Returns one file with full path and ponyquote that should be used, names is filter for names, also accepts filepaths
@ -471,7 +464,6 @@ class Ponysay():
@param alt:bool For method internal use... @param alt:bool For method internal use...
@return (path, quote):(str, str?) The file name of a pony, and the ponyquote that should be used if any @return (path, quote):(str, str?) The file name of a pony, and the ponyquote that should be used if any
''' '''
def __getpony(self, selection, args, alt = False):
## If there is no selected ponies, choose all of them ## If there is no selected ponies, choose all of them
if (selection is None) or (len(selection) == 0): if (selection is None) or (len(selection) == 0):
quote = args.opts['-q'] is not None ## TODO +q -Q quote = args.opts['-q'] is not None ## TODO +q -Q
@ -570,6 +562,7 @@ class Ponysay():
return (file, self.__getquote(pony[0], file) if pony[2] else None) return (file, self.__getquote(pony[0], file) if pony[2] else None)
def __getquote(self, pony, file):
''' '''
Select a quote for a pony Select a quote for a pony
@ -577,7 +570,6 @@ class Ponysay():
@param file:str The pony's file name @param file:str The pony's file name
@return :str A quote from the pony, with a failure fall back message @return :str A quote from the pony, with a failure fall back message
''' '''
def __getquote(self, pony, file):
quote = [] quote = []
if (os.path.dirname(file) + os.sep).replace(os.sep + os.sep, os.sep) in self.ponydirs: if (os.path.dirname(file) + os.sep).replace(os.sep + os.sep, os.sep) in self.ponydirs:
realpony = pony realpony = pony
@ -596,6 +588,7 @@ class Ponysay():
return quote return quote
def __quoters(self, ponydirs = None, quotedirs = None):
''' '''
Returns a set with all ponies that have quotes and are displayable Returns a set with all ponies that have quotes and are displayable
@ -603,7 +596,6 @@ class Ponysay():
@param quotedirs:itr<str>? The quote directories to use @param quotedirs:itr<str>? The quote directories to use
@return :set<str> All ponies that have quotes and are displayable @return :set<str> All ponies that have quotes and are displayable
''' '''
def __quoters(self, ponydirs = None, quotedirs = None):
if ponydirs is None: ponydirs = self.ponydirs if ponydirs is None: ponydirs = self.ponydirs
if quotedirs is None: quotedirs = self.quotedirs if quotedirs is None: quotedirs = self.quotedirs
@ -633,6 +625,7 @@ class Ponysay():
return ponies return ponies
def __quotes(self, ponydirs = None, quotedirs = None, ponies = None):
''' '''
Returns a list with all (pony, quote file) pairs Returns a list with all (pony, quote file) pairs
@ -641,7 +634,6 @@ class Ponysay():
@param ponies:itr<str>? The ponies to use @param ponies:itr<str>? The ponies to use
@return (pony, quote):(str, str) All poniesquote file-pairs @return (pony, quote):(str, str) All poniesquote file-pairs
''' '''
def __quotes(self, ponydirs = None, quotedirs = None, ponies = None):
if ponydirs is None: ponydirs = self.ponydirs if ponydirs is None: ponydirs = self.ponydirs
if quotedirs is None: quotedirs = self.quotedirs if quotedirs is None: quotedirs = self.quotedirs
@ -678,45 +670,45 @@ class Ponysay():
## Listing methods ## ## Listing methods ##
##################### #####################
def list(self, ponydirs = None):
''' '''
Lists the available ponies Lists the available ponies
@param ponydirs:itr<str>? The pony directories to use @param ponydirs:itr<str>? The pony directories to use
''' '''
def list(self, ponydirs = None):
List.simplelist(self.ponydirs if ponydirs is None else ponydirs, List.simplelist(self.ponydirs if ponydirs is None else ponydirs,
self.__quoters(), lambda x : self.__ucsise(x)) self.__quoters(), lambda x : self.__ucsise(x))
def linklist(self, ponydirs = None):
''' '''
Lists the available ponies with alternatives inside brackets Lists the available ponies with alternatives inside brackets
@param ponydirs:itr<str> The pony directories to use @param ponydirs:itr<str> The pony directories to use
''' '''
def linklist(self, ponydirs = None):
List.linklist(self.ponydirs if ponydirs is None else ponydirs, List.linklist(self.ponydirs if ponydirs is None else ponydirs,
self.__quoters(), lambda x, y : self.__ucsise(x, y)) self.__quoters(), lambda x, y : self.__ucsise(x, y))
def onelist(self, standard = True, extra = False):
''' '''
Lists the available ponies on one column without anything bold or otherwise formated Lists the available ponies on one column without anything bold or otherwise formated
@param standard:bool Include standard ponies @param standard:bool Include standard ponies
@param extra:bool Include extra ponies @param extra:bool Include extra ponies
''' '''
def onelist(self, standard = True, extra = False):
List.onelist(self.ponydirs if standard else None, List.onelist(self.ponydirs if standard else None,
self.extraponydirs if extra else None, self.extraponydirs if extra else None,
lambda x : self.__ucsise(x)) lambda x : self.__ucsise(x))
def quoters(self, standard = True, extra = False):
''' '''
Lists with all ponies that have quotes and are displayable, on one column without anything bold or otherwise formated Lists with all ponies that have quotes and are displayable, on one column without anything bold or otherwise formated
@param standard:bool Include standard ponies @param standard:bool Include standard ponies
@param extra:bool Include extra ponies @param extra:bool Include extra ponies
''' '''
def quoters(self, standard = True, extra = False):
## Get all quoters ## Get all quoters
ponies = list(self.__quoters()) if standard else [] ponies = list(self.__quoters()) if standard else []
@ -742,13 +734,14 @@ class Ponysay():
## Balloon methods ## ## Balloon methods ##
##################### #####################
def balloonlist(self):
''' '''
Prints a list of all balloons Prints a list of all balloons
''' '''
def balloonlist(self):
List.balloonlist(self.balloondirs, self.isthink) List.balloonlist(self.balloondirs, self.isthink)
def __getballoonpath(self, names, alt = False):
''' '''
Returns one file with full path, names is filter for style names, also accepts filepaths Returns one file with full path, names is filter for style names, also accepts filepaths
@ -756,7 +749,6 @@ class Ponysay():
@param alt:bool For method internal use @param alt:bool For method internal use
@param :str The file name of the balloon, will be `None` iff `names` is `None` @param :str The file name of the balloon, will be `None` iff `names` is `None`
''' '''
def __getballoonpath(self, names, alt = False):
## Stop if their is no choosen balloon ## Stop if their is no choosen balloon
if names is None: if names is None:
return None return None
@ -799,13 +791,13 @@ class Ponysay():
return balloons[balloon] return balloons[balloon]
def __getballoon(self, balloonfile):
''' '''
Creates the balloon style object Creates the balloon style object
@param balloonfile:str The file with the balloon style, may be `None` @param balloonfile:str The file with the balloon style, may be `None`
@return :Balloon Instance describing the balloon's style @return :Balloon Instance describing the balloon's style
''' '''
def __getballoon(self, balloonfile):
return Balloon.fromFile(balloonfile, self.isthink) return Balloon.fromFile(balloonfile, self.isthink)
@ -814,20 +806,20 @@ class Ponysay():
## Displaying methods ## ## Displaying methods ##
######################## ########################
def version(self):
''' '''
Prints the name of the program and the version of the program Prints the name of the program and the version of the program
''' '''
def version(self):
## Prints the "ponysay $VERSION", if this is modified, ./dev/dist.sh must be modified accordingly ## Prints the "ponysay $VERSION", if this is modified, ./dev/dist.sh must be modified accordingly
print('%s %s' % ('ponysay', VERSION)) print('%s %s' % ('ponysay', VERSION))
def print_pony(self, args):
''' '''
Print the pony with a speech or though bubble. message, pony and wrap from args are used. Print the pony with a speech or though bubble. message, pony and wrap from args are used.
@param args:ArgParser Parsed command line arguments @param args:ArgParser Parsed command line arguments
''' '''
def print_pony(self, args):
## Get the pony ## Get the pony
(selection, standard, extra) = ([], [], []) (selection, standard, extra) = ([], [], [])
for ponydir in self.ponydirs: for ponydir in self.ponydirs:

View file

@ -39,13 +39,14 @@ from ponysay import *
from metadata import * from metadata import *
VERSION = 'dev' # this line should not be edited, it is fixed by the build system
''' '''
The version of ponysay The version of ponysay
''' '''
VERSION = 'dev' # this line should not be edited, it is fixed by the build system
def print(text = '', end = '\n'):
''' '''
Hack to enforce UTF-8 in output (in the future, if you see anypony not using utf-8 in Hack to enforce UTF-8 in output (in the future, if you see anypony not using utf-8 in
programs by default, report them to Princess Celestia so she can banish them to the moon) programs by default, report them to Princess Celestia so she can banish them to the moon)
@ -53,30 +54,30 @@ programs by default, report them to Princess Celestia so she can banish them to
@param text:str The text to print (empty string is default) @param text:str The text to print (empty string is default)
@param end:str The appendix to the text to print (line breaking is default) @param end:str The appendix to the text to print (line breaking is default)
''' '''
def print(text = '', end = '\n'):
sys.stdout.buffer.write((str(text) + end).encode('utf-8')) sys.stdout.buffer.write((str(text) + end).encode('utf-8'))
def printerr(text = '', end = '\n'):
''' '''
stderr equivalent to print() stderr equivalent to print()
@param text:str The text to print (empty string is default) @param text:str The text to print (empty string is default)
@param end:str The appendix to the text to print (line breaking is default) @param end:str The appendix to the text to print (line breaking is default)
''' '''
def printerr(text = '', end = '\n'):
sys.stderr.buffer.write((str(text) + end).encode('utf-8')) sys.stderr.buffer.write((str(text) + end).encode('utf-8'))
class PonysayTool():
''' '''
This is the mane class of ponysay-tool This is the mane class of ponysay-tool
''' '''
class PonysayTool():
def __init__(self, args):
''' '''
Starts the part of the program the arguments indicate Starts the part of the program the arguments indicate
@param args:ArgParser Parsed command line arguments @param args:ArgParser Parsed command line arguments
''' '''
def __init__(self, args):
if args.argcount == 0: if args.argcount == 0:
args.help() args.help()
exit(255) exit(255)
@ -194,13 +195,13 @@ class PonysayTool():
exit(253) exit(253)
def execPonysay(self, args, message = ''):
''' '''
Execute ponysay! Execute ponysay!
@param args Arguments @param args Arguments
@param message Message @param message Message
''' '''
def execPonysay(self, args, message = ''):
class PhonyArgParser(): class PhonyArgParser():
def __init__(self, args, message): def __init__(self, args, message):
self.argcount = len(args) + (0 if message is None else 1) self.argcount = len(args) + (0 if message is None else 1)
@ -239,13 +240,13 @@ class PonysayTool():
return out return out
def browse(self, ponydir, restriction):
''' '''
Browse ponies Browse ponies
@param ponydir:str The pony directory to browse @param ponydir:str The pony directory to browse
@param restriction:list<str> Restrictions on listed ponies, may be None @param restriction:list<str> Restrictions on listed ponies, may be None
''' '''
def browse(self, ponydir, restriction):
## Call `stty` to determine the size of the terminal, this way is better than using python's ncurses ## Call `stty` to determine the size of the terminal, this way is better than using python's ncurses
termsize = None termsize = None
for channel in (sys.stdout, sys.stdin, sys.stderr): for channel in (sys.stdout, sys.stdin, sys.stderr):
@ -431,10 +432,10 @@ class PonysayTool():
(x, y) = (0, 0) (x, y) = (0, 0)
def generateKMS(self):
''' '''
Generate all kmsponies for the current TTY palette Generate all kmsponies for the current TTY palette
''' '''
def generateKMS(self):
class PhonyArgParser(): class PhonyArgParser():
def __init__(self, key, value): def __init__(self, key, value):
self.argcount = 3 self.argcount = 3
@ -495,13 +496,13 @@ class PonysayTool():
sys.stdout = stdout sys.stdout = stdout
def generateDimensions(self, ponydir, ponies = None):
''' '''
Generate pony dimension file for a directory Generate pony dimension file for a directory
@param ponydir:str The directory @param ponydir:str The directory
@param ponies:itr<str>? Ponies to which to limit @param ponies:itr<str>? Ponies to which to limit
''' '''
def generateDimensions(self, ponydir, ponies = None):
dimensions = [] dimensions = []
ponyset = None if (ponies is None) or (len(ponies) == 0) else set(ponies) ponyset = None if (ponies is None) or (len(ponies) == 0) else set(ponies)
for ponyfile in os.listdir(ponydir): for ponyfile in os.listdir(ponydir):
@ -581,13 +582,13 @@ class PonysayTool():
file.flush() file.flush()
def generateMetadata(self, ponydir, ponies = None):
''' '''
Generate pony metadata collection file for a directory Generate pony metadata collection file for a directory
@param ponydir:str The directory @param ponydir:str The directory
@param ponies:itr<str>? Ponies to which to limit @param ponies:itr<str>? Ponies to which to limit
''' '''
def generateMetadata(self, ponydir, ponies = None):
if not ponydir.endswith('/'): if not ponydir.endswith('/'):
ponydir += '/' ponydir += '/'
def makeset(value): def makeset(value):
@ -663,12 +664,12 @@ class PonysayTool():
file.flush() file.flush()
def editmeta(self, ponyfile):
''' '''
Edit a pony file's metadata Edit a pony file's metadata
@param ponyfile:str A pony file to edit @param ponyfile:str A pony file to edit
''' '''
def editmeta(self, ponyfile):
(data, meta, image) = 3 * [None] (data, meta, image) = 3 * [None]
with open(ponyfile, 'rb') as file: with open(ponyfile, 'rb') as file:
@ -838,10 +839,11 @@ class PonysayTool():
class TextArea(): # TODO support small screens (This is being work on in GNU-Pony/featherweight)
''' '''
GNU Emacs alike text area GNU Emacs alike text area
''' '''
class TextArea(): # TODO support small screens def __init__(self, fields, datamap, left, top, width, height, termsize):
''' '''
Constructor Constructor
@ -853,17 +855,16 @@ class TextArea(): # TODO support small screens
@param height:int Height of the component @param height:int Height of the component
@param termsize:(int,int) The height and width of the terminal @param termsize:(int,int) The height and width of the terminal
''' '''
def __init__(self, fields, datamap, left, top, width, height, termsize):
(self.fields, self.datamap, self.left, self.top, self.width, self.height, self.termsize) \ (self.fields, self.datamap, self.left, self.top, self.width, self.height, self.termsize) \
= (fields, datamap, left, top, width - 1, height, termsize) = (fields, datamap, left, top, width - 1, height, termsize)
def run(self, saver):
''' '''
Execute text reading Execute text reading
@param saver Save method @param saver Save method
''' '''
def run(self, saver):
innerleft = UCS.dispLen(max(self.fields, key = UCS.dispLen)) + self.left + 3 innerleft = UCS.dispLen(max(self.fields, key = UCS.dispLen)) + self.left + 3
leftlines = [] leftlines = []
@ -1183,25 +1184,25 @@ class TextArea(): # TODO support small screens
HOME = os.environ['HOME'] if 'HOME' in os.environ else os.path.expanduser('~')
''' '''
The user's home directory The user's home directory
''' '''
HOME = os.environ['HOME'] if 'HOME' in os.environ else os.path.expanduser('~')
pipelinein = not sys.stdin.isatty()
''' '''
Whether stdin is piped Whether stdin is piped
''' '''
pipelinein = not sys.stdin.isatty()
pipelineout = not sys.stdout.isatty()
''' '''
Whether stdout is piped Whether stdout is piped
''' '''
pipelineout = not sys.stdout.isatty()
pipelineerr = not sys.stderr.isatty()
''' '''
Whether stderr is piped Whether stderr is piped
''' '''
pipelineerr = not sys.stderr.isatty()
usage_program = '\033[34;1mponysay-tool\033[21;39m' usage_program = '\033[34;1mponysay-tool\033[21;39m'
@ -1241,10 +1242,10 @@ opts.add_argumented( ['--edit-rm'], arg = 'PONY-FILE', help = 'Remove
opts.add_argumented( ['--edit-apply'], arg = 'PONY-FILE', help = 'Apply metadata from stdin to a pony file') opts.add_argumented( ['--edit-apply'], arg = 'PONY-FILE', help = 'Apply metadata from stdin to a pony file')
opts.add_argumented( ['--edit-stash'], arg = 'PONY-FILE', help = 'Print applyable metadata from a pony file') opts.add_argumented( ['--edit-stash'], arg = 'PONY-FILE', help = 'Print applyable metadata from a pony file')
unrecognised = not opts.parse()
''' '''
Whether at least one unrecognised option was used Whether at least one unrecognised option was used
''' '''
unrecognised = not opts.parse()
PonysayTool(args = opts) PonysayTool(args = opts)

View file

@ -33,13 +33,15 @@ from common import *
class SpelloCorrecter(): # Naïvely and quickly ported and adapted from optimised Java, may not be the nicest, or even fast, Python code
''' '''
Class used for correcting spellos and typos, Class used for correcting spellos and typos,
Note that this implementation will not find that correctly spelled word are correct faster than it corrects words. Note that this implementation will not find that correctly spelled word are correct faster than it corrects words.
It is also limited to words of size 0 to 127 (inclusive) It is also limited to words of size 0 to 127 (inclusive)
''' '''
class SpelloCorrecter(): # Naïvely and quickly ported and adapted from optimised Java, may not be the nicest, or even fast, Python code
def __init__(self, directories, ending = None):
''' '''
Constructor Constructor
@ -50,7 +52,6 @@ class SpelloCorrecter(): # Naïvely and quickly ported and adapted from optimise
@param directories:list<str> The file names with the correct spelling @param directories:list<str> The file names with the correct spelling
''' '''
def __init__(self, directories, ending = None):
self.weights = {'k' : {'c' : 0.25, 'g' : 0.75, 'q' : 0.125}, self.weights = {'k' : {'c' : 0.25, 'g' : 0.75, 'q' : 0.125},
'c' : {'k' : 0.25, 'g' : 0.75, 's' : 0.5, 'z' : 0.5, 'q' : 0.125}, 'c' : {'k' : 0.25, 'g' : 0.75, 's' : 0.5, 'z' : 0.5, 'q' : 0.125},
's' : {'z' : 0.25, 'c' : 0.5}, 's' : {'z' : 0.25, 'c' : 0.5},
@ -145,13 +146,13 @@ class SpelloCorrecter(): # Naïvely and quickly ported and adapted from optimise
# index -= 1; # index -= 1;
def correct(self, used):
''' '''
Finds the closests correct spelled word Finds the closests correct spelled word
@param used:str The word to correct @param used:str The word to correct
@return (words, distance):(list<string>, int) A list the closest spellings and the weighted distance @return (words, distance):(list<string>, int) A list the closest spellings and the weighted distance
''' '''
def correct(self, used):
if len(used) > 127: if len(used) > 127:
return ([used], 0) return ([used], 0)
@ -159,12 +160,12 @@ class SpelloCorrecter(): # Naïvely and quickly ported and adapted from optimise
return (self.corrections, self.closestDistance) return (self.corrections, self.closestDistance)
def __correct(self, used):
''' '''
Finds the closests correct spelled word Finds the closests correct spelled word
@param used:str The word to correct, it must satisfy all restrictions @param used:str The word to correct, it must satisfy all restrictions
''' '''
def __correct(self, used):
self.closestDistance = 0x7FFFFFFF self.closestDistance = 0x7FFFFFFF
previous = self.dictionary[-1] previous = self.dictionary[-1]
prevLen = 0 prevLen = 0
@ -217,6 +218,7 @@ class SpelloCorrecter(): # Naïvely and quickly ported and adapted from optimise
prevLen = len(proper) prevLen = len(proper)
def __distance(self, proper, y0, yn, used, x0, xn):
''' '''
Calculate the distance between a correct word and a incorrect word Calculate the distance between a correct word and a incorrect word
@ -228,7 +230,6 @@ class SpelloCorrecter(): # Naïvely and quickly ported and adapted from optimise
@param xn:int The length, before applying `x0`, of `used` @param xn:int The length, before applying `x0`, of `used`
@return :float The distance between the words @return :float The distance between the words
''' '''
def __distance(self, proper, y0, yn, used, x0, xn):
my = self.M[y0] my = self.M[y0]
for y in range(y0, yn): for y in range(y0, yn):
best = 0x7FFFFFFF best = 0x7FFFFFFF

View file

@ -33,18 +33,19 @@ from common import *
class UCS():
''' '''
UCS utility class UCS utility class
''' '''
class UCS():
@staticmethod
def isCombining(char):
''' '''
Checks whether a character is a combining character Checks whether a character is a combining character
@param char:chr The character to test @param char:chr The character to test
@return :bool Whether the character is a combining character @return :bool Whether the character is a combining character
''' '''
@staticmethod
def isCombining(char):
o = ord(char) o = ord(char)
if (0x0300 <= o) and (o <= 0x036F): return True if (0x0300 <= o) and (o <= 0x036F): return True
if (0x20D0 <= o) and (o <= 0x20FF): return True if (0x20D0 <= o) and (o <= 0x20FF): return True
@ -53,14 +54,14 @@ class UCS():
return False return False
@staticmethod
def countCombining(string):
''' '''
Gets the number of combining characters in a string Gets the number of combining characters in a string
@param string:str A text to count combining characters in @param string:str A text to count combining characters in
@return :int The number of combining characters in the string @return :int The number of combining characters in the string
''' '''
@staticmethod
def countCombining(string):
rc = 0 rc = 0
for char in string: for char in string:
if UCS.isCombining(char): if UCS.isCombining(char):
@ -68,13 +69,13 @@ class UCS():
return rc return rc
@staticmethod
def dispLen(string):
''' '''
Gets length of a string not counting combining characters Gets length of a string not counting combining characters
@param string:str The text of which to determine the monospaced width @param string:str The text of which to determine the monospaced width
@return The determine the monospaced width of the text, provided it does not have escape sequnces @return The determine the monospaced width of the text, provided it does not have escape sequnces
''' '''
@staticmethod
def dispLen(string):
return len(string) - UCS.countCombining(string) return len(string) - UCS.countCombining(string)