From 2a32fed2236e667ded7d8b8bafe2c9c148bf5b83 Mon Sep 17 00:00:00 2001 From: "K. Lange" Date: Tue, 22 Mar 2022 22:41:22 +0900 Subject: [PATCH] kuroko port --- .gitignore | 1 - src/__main__.py => ponysay/__init__.krk | 47 ++-- src/argparser.py => ponysay/argparser.krk | 131 +++++---- src/backend.py => ponysay/backend.krk | 200 +++++++------ src/balloon.py => ponysay/balloon.krk | 58 ++-- src/colourstack.py => ponysay/colourstack.krk | 27 +- src/common.py => ponysay/common.krk | 51 +--- src/kms.py => ponysay/kms.krk | 2 +- src/lists.py => ponysay/lists.krk | 73 +++-- src/metadata.py => ponysay/metadata.krk | 2 +- src/ponysay.py => ponysay/ponysay.krk | 263 +++++++++++------- src/ponysaytool.py => ponysay/ponysaytool.krk | 223 +++++++-------- .../spellocorrecter.krk | 39 ++- src/ucs.py => ponysay/ucs.krk | 6 +- 14 files changed, 592 insertions(+), 531 deletions(-) rename src/__main__.py => ponysay/__init__.krk (84%) rename src/argparser.py => ponysay/argparser.krk (75%) rename src/backend.py => ponysay/backend.krk (81%) rename src/balloon.py => ponysay/balloon.krk (80%) rename src/colourstack.py => ponysay/colourstack.krk (85%) rename src/common.py => ponysay/common.krk (60%) rename src/kms.py => ponysay/kms.krk (99%) rename src/lists.py => ponysay/lists.krk (79%) rename src/metadata.py => ponysay/metadata.krk (98%) rename src/ponysay.py => ponysay/ponysay.krk (85%) rename src/ponysaytool.py => ponysay/ponysaytool.krk (86%) rename src/spellocorrecter.py => ponysay/spellocorrecter.krk (92%) rename src/ucs.py => ponysay/ucs.krk (95%) diff --git a/.gitignore b/.gitignore index db54bf3b..6b5edfd5 100644 --- a/.gitignore +++ b/.gitignore @@ -39,7 +39,6 @@ _/ /*ponies/onlyheights /*ponies/widths /*ponies/metadata -/ponysay /bin/ /obj/ diff --git a/src/__main__.py b/ponysay/__init__.krk similarity index 84% rename from src/__main__.py rename to ponysay/__init__.krk index 3b084e93..95bc3a61 100644 --- a/src/__main__.py +++ b/ponysay/__init__.krk @@ -39,56 +39,57 @@ Authors: Jan Alexander "heftig" Steffens: Major contributor of the first implementation Kyah "L-four" Rindlisbacher: Patched the first implementation ''' -from common import * -from argparser import * -from ponysay import * - +from ponysay.common import printerr, printinfo, gettermsize, endswith +from ponysay.argparser import ArgParser +from ponysay.ponysay import Ponysay +import os +import kuroko ''' Start the program ''' if __name__ == '__main__': - istool = sys.argv[0] + let istool = kuroko.argv[0] if os.sep in istool: istool = istool[istool.rfind(os.sep) + 1:] if os.extsep in istool: istool = istool[:istool.find(os.extsep)] istool = istool.endswith('-tool') if istool: - from ponysaytool import * ## will start ponysay-tool - exit(0) + import ponysaytool + os.exit(0) - isthink = sys.argv[0] + let isthink = kuroko.argv[0] if os.sep in isthink: isthink = isthink[isthink.rfind(os.sep) + 1:] if os.extsep in isthink: isthink = isthink[:isthink.find(os.extsep)] isthink = isthink.endswith('think') - usage_saythink = '\033[34;1m(ponysay | ponythink)\033[21;39m' - usage_common = '[-c] [-W\033[33mCOLUMN\033[39m] [-b\033[33mSTYLE\033[39m]' - usage_listhelp = '(-l | -L | -B | +l | +L | -A | + A | -v | -h)' - usage_file = '[-f\033[33mPONY\033[39m]* [[--] \033[33mmessage\033[39m]' - usage_xfile = '(+f\033[33mPONY\033[39m)* [[--] \033[33mmessage\033[39m]' - usage_afile = '(-F\033[33mPONY\033[39m)* [[--] \033[33mmessage\033[39m]' - usage_quote = '(-q\033[33mPONY\033[39m)*' + let usage_saythink = '\033[34;1m(ponysay | ponythink)\033[22;39m' + let usage_common = '[-c] [-W\033[33mCOLUMN\033[39m] [-b\033[33mSTYLE\033[39m]' + let usage_listhelp = '(-l | -L | -B | +l | +L | -A | + A | -v | -h)' + let usage_file = '[-f\033[33mPONY\033[39m]* [[--] \033[33mmessage\033[39m]' + let usage_xfile = '(+f\033[33mPONY\033[39m)* [[--] \033[33mmessage\033[39m]' + let usage_afile = '(-F\033[33mPONY\033[39m)* [[--] \033[33mmessage\033[39m]' + let usage_quote = '(-q\033[33mPONY\033[39m)*' - usage = ('%s %s' + 4 * '\n%s %s %s') % (usage_saythink, usage_listhelp, + let usage = ('{} {}' + 4 * '\n{} {} {}') .format (usage_saythink, usage_listhelp, usage_saythink, usage_common, usage_file, usage_saythink, usage_common, usage_xfile, usage_saythink, usage_common, usage_afile, usage_saythink, usage_common, usage_quote) - usage = usage.replace('\033[', '\0') + usage = usage.replace('\033[', 'あ') for sym in ('[', ']', '(', ')', '|', '...', '*'): usage = usage.replace(sym, '\033[2m' + sym + '\033[22m') - usage = usage.replace('\0', '\033[') + usage = usage.replace('あ', '\033[') ''' Argument parsing ''' - opts = ArgParser(program = 'ponythink' if isthink else 'ponysay', + let opts = ArgParser(program = 'ponythink' if isthink else 'ponysay', description = 'cowsay reimplemention for ponies', usage = usage, longdescription = @@ -117,8 +118,8 @@ run `man ponysay`. Ponysay has so much more to offer than described here.''') opts.add_argumented( ['--colour-pony'], arg = 'COLOUR') opts.add_argumented( ['--colour-wrap', '--colour-hyphen'], arg = 'COLOUR') - _F = ['--any-file', '--anyfile', '--any-pony', '--anypony'] - __F = [_.replace("pony", "ponie") + 's' for _ in _F] + let _F = ['--any-file', '--anyfile', '--any-pony', '--anypony'] + let __F = [_.replace("pony", "ponie") + 's' for _ in _F] opts.add_argumentless(['-h', '--help'], help = 'Print this help message.') opts.add_argumentless(['+h', '++help', '--help-colour'], help = 'Print this help message with colours even if piped.') opts.add_argumentless(['-v', '--version'], help = 'Print the version of the program.') @@ -145,10 +146,10 @@ run `man ponysay`. Ponysay has so much more to offer than described here.''') ''' Whether at least one unrecognised option was used ''' - unrecognised = not opts.parse() + let unrecognised = not opts.parse() ## Start - ponysay = Ponysay() + let ponysay = Ponysay() ponysay.unrecognised = unrecognised ponysay.run(opts) diff --git a/src/argparser.py b/ponysay/argparser.krk similarity index 75% rename from src/argparser.py rename to ponysay/argparser.krk index 7b13b3cc..c6d91291 100644 --- a/src/argparser.py +++ b/ponysay/argparser.krk @@ -29,21 +29,23 @@ 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 ponysay.common import printerr, printinfo, gettermsize, endswith +import os +import kuroko +import fileio - -ARGUMENTLESS = 0 +let ARGUMENTLESS = 0 ''' Option takes no arguments ''' -ARGUMENTED = 1 +let ARGUMENTED = 1 ''' Option takes one argument per instance ''' -VARIADIC = 2 +let VARIADIC = 2 ''' Option consumes all following arguments ''' @@ -83,7 +85,7 @@ class ArgParser(): @param help:str Short description, use `None` to hide the option ''' self.__arguments.append((ARGUMENTLESS, alternatives, None, help)) - stdalt = alternatives[0] + let stdalt = alternatives[0] self.opts[stdalt] = None for alt in alternatives: self.optmap[alt] = (stdalt, ARGUMENTLESS) @@ -97,7 +99,7 @@ class ArgParser(): @param help:str Short description, use `None` to hide the option ''' self.__arguments.append((ARGUMENTED, alternatives, arg, help)) - stdalt = alternatives[0] + let stdalt = alternatives[0] self.opts[stdalt] = None for alt in alternatives: self.optmap[alt] = (stdalt, ARGUMENTED) @@ -111,13 +113,13 @@ class ArgParser(): @param help:str Short description, use `None` to hide the option ''' self.__arguments.append((VARIADIC, alternatives, arg, help)) - stdalt = alternatives[0] + let stdalt = alternatives[0] self.opts[stdalt] = None for alt in alternatives: self.optmap[alt] = (stdalt, VARIADIC) - def parse(self, argv = sys.argv): + def parse(self, argv = kuroko.argv): ''' Parse arguments @@ -127,23 +129,24 @@ class ArgParser(): self.argcount = len(argv) - 1 self.files = [] - argqueue = [] - optqueue = [] - deque = [] + let arg, i, n, opt, varopt + let argqueue = [] + let optqueue = [] + let deque = [] for arg in argv[1:]: deque.append(arg) - dashed = False - tmpdashed = False - get = 0 - dontget = 0 + let dashed = False + let tmpdashed = False + let get = 0 + let dontget = 0 self.rc = True self.unrecognisedCount = 0 def unrecognised(arg): self.unrecognisedCount += 1 if self.unrecognisedCount <= 5: - sys.stderr.write('%s: warning: unrecognised option %s\n' % (self.__program, arg)) + fileio.stderr.write('{}: warning: unrecognised option {}\n' .format (self.__program, arg)) self.rc = False while len(deque) != 0: @@ -184,11 +187,11 @@ class ArgParser(): else: unrecognised(arg) else: - sign = arg[0] - i = 1 - n = len(arg) + let sign = arg[0] + let i = 1 + let n = len(arg) while i < n: - narg = sign + arg[i] + let narg = sign + arg[i] i += 1 if (narg in self.optmap): if self.optmap[narg][1] == ARGUMENTLESS: @@ -196,7 +199,7 @@ class ArgParser(): argqueue.append(None) elif self.optmap[narg][1] == ARGUMENTED: optqueue.append(narg) - nargarg = arg[i:] + let nargarg = arg[i:] if len(nargarg) == 0: get += 1 else: @@ -204,7 +207,7 @@ class ArgParser(): break elif self.optmap[narg][1] == VARIADIC: optqueue.append(narg) - nargarg = arg[i:] + let nargarg = arg[i:] argqueue.append(nargarg if len(nargarg) > 0 else None) dashed = True break @@ -240,7 +243,7 @@ class ArgParser(): self.message = ' '.join(self.files) if len(self.files) > 0 else None if self.unrecognisedCount > 5: - sys.stderr.write('%s: warning: %i more unrecognised %s\n' % (self.unrecognisedCount - 5, 'options' if self.unrecognisedCount == 6 else 'options')) + fileio.stderr.write('{}: warning: {} more unrecognised {}\n' .format (self.unrecognisedCount - 5, 'options' if self.unrecognisedCount == 6 else 'options')) return self.rc @@ -252,94 +255,102 @@ class ArgParser(): @param use_colours:bool? Whether to use colours, `None` if stdout is not piped ''' if use_colours is None: - use_colours = sys.stdout.isatty() + use_colours = True # os.isatty(1) - print(('\033[1m%s\033[21m %s %s' if use_colours else '%s %s %s') % (self.__program, '-' if self.linuxvt else '—', self.__description)) + print(('\[[1m{}\[[22m {} {}' if use_colours else '{} {} {}').format(self.__program, '-' if self.linuxvt else '—', self.__description)) print() if self.__longdescription is not None: - desc = self.__longdescription + let desc = self.__longdescription if not use_colours: - while '\033' in desc: - esc = desc.find('\033') + while '\[' in desc: + esc = desc.find('\[') desc = desc[:esc] + desc[desc.find('m', esc) + 1:] print(desc) print() - print('\033[1mUSAGE:\033[21m' if use_colours else 'USAGE:', end='') - first = True + print('\[[1mUSAGE:\[[22m' if use_colours else 'USAGE:', end='') + let first = True for line in self.__usage.split('\n'): if first: first = False else: print(' or', end='') if not use_colours: - while '\033' in line: - esc = line.find('\033') + while '\[' in line: + esc = line.find('\[') line = line[:esc] + line[line.find('m', esc) + 1:] - print('\t%s' % line) + print('\t{}'.format(line)) print() - maxfirstlen = [] + let maxfirstlen = [] for opt in self.__arguments: - opt_alts = opt[1] - opt_help = opt[3] + let opt_alts = opt[1] + let opt_help = opt[3] if opt_help is None: continue first = opt_alts[0] - last = opt_alts[-1] + let last = opt_alts[-1] if first is not last: maxfirstlen.append(first) maxfirstlen = len(max(maxfirstlen, key = len)) - print('\033[1mSYNOPSIS:\033[21m' if use_colours else 'SYNOPSIS') - (lines, lens) = ([], []) + print('\[[1mSYNOPSIS:\[[22m' if use_colours else 'SYNOPSIS') + let lines, lens = [], [] for opt in self.__arguments: - opt_type = opt[0] - opt_alts = opt[1] - opt_arg = opt[2] - opt_help = opt[3] + let opt_type = opt[0] + let opt_alts = opt[1] + let opt_arg = opt[2] + let opt_help = opt[3] if opt_help is None: continue - (line, l) = ('', 0) + let line, l = '', 0 first = opt_alts[0] - last = opt_alts[-1] - alts = ['', last] if first is last else [first, last] + let last = opt_alts[-1] + let alts = ['', last] if first is last else [first, last] alts[0] += ' ' * (maxfirstlen - len(alts[0])) for opt_alt in alts: if opt_alt is alts[-1]: line += '%colour%' + opt_alt l += len(opt_alt) if use_colours: - if opt_type == ARGUMENTED: line += ' \033[4m%s\033[24m' % (opt_arg); l += len(opt_arg) + 1 - elif opt_type == VARIADIC: line += ' [\033[4m%s\033[24m...]' % (opt_arg); l += len(opt_arg) + 6 + if opt_type == ARGUMENTED: + line += ' \[[4m{}\[[24m' .format (opt_arg) + l += len(opt_arg) + 1 + elif opt_type == VARIADIC: + line += ' [\[[4m{}\[[24m...]' .format (opt_arg) + l += len(opt_arg) + 6 else: - if opt_type == ARGUMENTED: line += ' %s' % (opt_arg); l += len(opt_arg) + 1 - elif opt_type == VARIADIC: line += ' [%s...]' % (opt_arg); l += len(opt_arg) + 6 + if opt_type == ARGUMENTED: + line += ' {}' .format (opt_arg) + l += len(opt_arg) + 1 + elif opt_type == VARIADIC: + line += ' [{}...]' .format (opt_arg) + l += len(opt_arg) + 6 else: if use_colours: - line += ' \033[2m%s\033[22m ' % (opt_alt) + line += ' \[[2m{}\[[22m ' .format (opt_alt) else: - line += ' %s ' % (opt_alt) + line += ' {} ' .format (opt_alt) l += len(opt_alt) + 6 lines.append(line) lens.append(l) - col = max(lens) + let col = max(lens) col += 8 - ((col - 4) & 7) - index = 0 + let index = 0 for opt in self.__arguments: - opt_help = opt[3] + let opt_help = opt[3] if opt_help is None: continue first = True - colour = ('36' if (index & 1) == 0 else '34') if use_colours else '' - print(lines[index].replace('%colour%', ('\033[%s;1m' % colour) if use_colours else ''), end=' ' * (col - lens[index])) + let colour = ('36' if (index & 1) == 0 else '34') if use_colours else '' + print(lines[index].replace('%colour%', ('\[[{};1m' .format (colour)) if use_colours else ''), end=' ' * (col - lens[index])) for line in opt_help.split('\n'): if first: first = False - print('%s' % (line), end='\033[21;39m\n' if use_colours else '\n') + print(line, end='\[[22;39m\n' if use_colours else '\n') else: - print(('%s\033[%sm%s\033[39m' if use_colours else '%s%s%s') % (' ' * col, colour, line)) + print(('{}\[[{}m{}\[[39m' if use_colours else '{}{}{}').format (' ' * col, colour, line)) index += 1 print() diff --git a/src/backend.py b/ponysay/backend.krk similarity index 81% rename from src/backend.py rename to ponysay/backend.krk index 82ff1496..a7b7364f 100644 --- a/src/backend.py +++ b/ponysay/backend.krk @@ -29,14 +29,14 @@ 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 balloon import * -from colourstack import * -from ucs import * - -import unicodedata - +from ponysay.common import printerr, printinfo, gettermsize, endswith +from ponysay.balloon import Balloon +from ponysay.colourstack import ColourStack +from ponysay.ucs import UCS +from wcwidth import wcwidth +import fileio +import os class Backend(): ''' @@ -89,6 +89,7 @@ class Backend(): if self.pony.startswith('$$$\n'): self.pony = self.pony[4:] + let infoend, info if self.pony.startswith('$$$\n'): infoend = 4 info = '' @@ -104,21 +105,21 @@ class Backend(): else: info = info.split('\n') for line in info: - sep = line.find(':') + let sep = line.find(':') if sep > 0: - key = line[:sep].strip() + let key = line[:sep].strip() if key == 'BALLOON TOP': - value = line[sep + 1:].strip() + let value = line[sep + 1:].strip() if len(value) > 0: self.balloontop = int(value) if key == 'BALLOON BOTTOM': - value = line[sep + 1:].strip() + let value = line[sep + 1:].strip() if len(value) > 0: self.balloonbottom = int(value) printinfo(info) self.pony = self.pony[infoend:] elif self.infolevel == 2: - self.message = '\033[01;31mI am the mysterious mare...\033[21;39m' + self.message = '\033[01;31mI am the mysterious mare...\033[22;39m' elif self.infolevel == 1: self.pony = 'There is not metadata for this pony file' self.pony = self.mode + self.pony @@ -149,7 +150,7 @@ class Backend(): test = test.replace(c, '') if (len(test) == 0) and (len(key.replace(' ', '')) > 0): value = line[sep + 1:].strip() - line = '\033[1m%s\033[21m: %s\n' % (key.strip(), value) + line = '\033[1m{}\033[22m: {}\n' .format (key.strip(), value) tags += line continue comment += '\n' + line @@ -163,16 +164,16 @@ class Backend(): ''' Remove padding spaces fortune cookies are padded with whitespace (damn featherbrains) ''' - lines = self.message.split('\n') + let lines = self.message.split('\n') for spaces in (128, 64, 32, 16, 8, 4, 2, 1): - padded = True + let padded = True for line in lines: if not line.startswith(' ' * spaces): padded = False break if padded: for i in range(0, len(lines)): - line = lines[i] + let line = lines[i] line = line[spaces:] lines[i] = line lines = [line.rstrip(' ') for line in lines] @@ -183,19 +184,19 @@ class Backend(): ''' Converts all tabs in the message to spaces by expanding ''' - lines = self.message.split('\n') - buf = '' + let lines = self.message.split('\n') + let buf = '' for line in lines: - (i, n, x) = (0, len(line), 0) + let i, n, x = (0, len(line), 0) while i < n: - c = line[i] + let c = line[i] i += 1 if c == '\033': - colour = Backend.getColour(line, i - 1) + let colour = Backend.getColour(line, i - 1) i += len(colour) - 1 buf += colour elif c == '\t': - nx = 8 - (x & 7) + let nx = 8 - (x & 7) buf += ' ' * nx x += nx else: @@ -210,8 +211,8 @@ class Backend(): ''' Loads the pony file ''' - with open(self.ponyfile, 'rb') as ponystream: - self.pony = ponystream.read().decode('utf8', 'replace') + with fileio.open(self.ponyfile, 'rb') as ponystream: + self.pony = ponystream.read().decode() def __truncate(self): @@ -220,15 +221,15 @@ class Backend(): ''' if self.width is None: return - lines = self.output.split('\n') + let lines = self.output.split('\n') self.output = '' for line in lines: - (i, n, x) = (0, len(line), 0) + let i, n, x = (0, len(line), 0) while i < n: - c = line[i] + let c = line[i] i += 1 if c == '\033': - colour = Backend.getColour(line, i - 1) + let colour = Backend.getColour(line, i - 1) i += len(colour) - 1 self.output += colour else: @@ -246,35 +247,36 @@ class Backend(): ''' self.output = '' - AUTO_PUSH = '\033[01010~' - AUTO_POP = '\033[10101~' + let AUTO_PUSH = '\033[01010~' + let AUTO_POP = '\033[10101~' - variables = {'' : '$'} + let variables = {'' : '$'} for key in self.link: variables[key] = AUTO_PUSH + self.link[key] + AUTO_POP - indent = 0 - dollar = None - balloonLines = None - colourstack = ColourStack(AUTO_PUSH, AUTO_POP) + let indent = 0 + let dollar = None + let balloonLines = None + let balloonLine, balloonIndent + let colourstack = ColourStack(AUTO_PUSH, AUTO_POP) - (i, n, lineindex, skip, nonskip) = (0, len(self.pony), 0, 0, 0) + let i, n, lineindex, skip, nonskip = (0, len(self.pony), 0, 0, 0) while i < n: - c = self.pony[i] + let c = self.pony[i] if c == '\t': n += 7 - (indent & 7) - ed = ' ' * (8 - (indent & 7)) + let ed = ' ' * (8 - (indent & 7)) c = ' ' self.pony = self.pony[:i] + ed + self.pony[i + 1:] i += 1 if c == '$': if dollar is not None: if '=' in dollar: - name = dollar[:dollar.find('=')] - value = dollar[dollar.find('=') + 1:] + let name = dollar[:dollar.find('=')] + let value = dollar[dollar.find('=') + 1:] variables[name] = value elif not dollar.startswith('balloon'): - data = variables[dollar].replace('$', '$$') + let data = variables[dollar].replace('$', '$$') if data == '$$': # if not handled specially we will get an infinity loop if (skip == 0) or (nonskip > 0): if nonskip > 0: @@ -287,8 +289,8 @@ class Backend(): n += len(data) self.pony = self.pony[:i] + data + self.pony[i:] elif self.balloon is not None: - (w, h, x, justify) = ('0', 0, 0, None) - props = dollar[7:] + let w, h, x, justify = ('0', 0, 0, None) + let props = dollar[7:] if len(props) > 0: if ',' in props: if props[0] != ',': @@ -299,28 +301,28 @@ class Backend(): if 'l' in w: (x, w) = (int(w[:w.find('l')]), int(w[w.find('l') + 1:])) justify = 'l' - w -= x; + w -= x elif 'c' in w: (x, w) = (int(w[:w.find('c')]), int(w[w.find('c') + 1:])) justify = 'c' - w -= x; + w -= x elif 'r' in w: (x, w) = (int(w[:w.find('r')]), int(w[w.find('r') + 1:])) justify = 'r' - w -= x; + w -= x else: w = int(w) - balloon = self.__getBalloon(w, h, x, justify, indent) + let balloon = self.__getBalloon(w, h, x, justify, indent) balloon = balloon.split('\n') balloon = [AUTO_PUSH + self.ballooncolour + item + AUTO_POP for item in balloon] for b in balloon[0]: self.output += b + colourstack.feed(b) if lineindex == 0: - balloonpre = '\n' + (' ' * indent) + let balloonpre = '\n' + (' ' * indent) for line in balloon[1:]: - self.output += balloonpre; + self.output += balloonpre for b in line: - self.output += b + colourstack.feed(b); + self.output += b + colourstack.feed(b) indent = 0 elif len(balloon) > 1: balloonLines = balloon @@ -337,9 +339,9 @@ class Backend(): i += 1 dollar += c elif c == '\033': - colour = Backend.getColour(self.pony, i - 1) + let colour = Backend.getColour(self.pony, i - 1) for b in colour: - self.output += b + colourstack.feed(b); + self.output += b + colourstack.feed(b) i += len(colour) - 1 elif c == '\n': self.output += c @@ -364,7 +366,7 @@ class Backend(): if (skip == 0) or (nonskip > 0): if nonskip > 0: nonskip -= 1 - self.output += c + colourstack.feed(c); + self.output += c + colourstack.feed(c) if not UCS.isCombining(c): indent += 1 else: @@ -374,7 +376,7 @@ class Backend(): for line in balloonLines[balloonLine:]: data = ' ' * (balloonIndent - indent) + line + '\n' for b in data: - self.output += b + colourstack.feed(b); + self.output += b + colourstack.feed(b) indent = 0 self.output = self.output.replace(AUTO_PUSH, '').replace(AUTO_POP, '') @@ -395,11 +397,11 @@ class Backend(): @param offset:int The offset at where to start reading, a escape must begin here @return :str The escape sequence ''' - (i, n) = (offset, len(input)) - rc = input[i] + let i, n = (offset, len(input)) + let rc = input[i] i += 1 if i == n: return rc - c = input[i] + let c = input[i] i += 1 rc += c @@ -450,16 +452,16 @@ class Backend(): @param input:str The input buffer @return :int The number of visible characters ''' - (rc, i, n) = (0, 0, len(input)) + let rc, i, n = 0, 0, len(input) while i < n: - c = input[i] + let c = input[i] if c == '\033': i += len(Backend.getColour(input, i)) else: i += 1 if not UCS.isCombining(c): rc += 1 - if unicodedata.east_asian_width(c) in ('F', 'W'): + if wcwidth(ord(c)) in ('F', 'W'): rc += 1 return rc @@ -476,22 +478,22 @@ class Backend(): @param left:int The column where the balloon starts @return :str The balloon the the message as a string ''' - wrap = None + let wrap = None if self.wrapcolumn is not None: wrap = self.wrapcolumn - left if wrap < 8: wrap = 8 - msg = self.message + let msg = self.message if wrap is not None: msg = self.__wrapMessage(msg, wrap) - msg = msg.replace('\n', '\033[0m%s\n' % (self.ballooncolour)) + '\033[0m' + self.ballooncolour + msg = msg.replace('\n', '\033[0m{}\n' .format (self.ballooncolour)) + '\033[0m' + self.ballooncolour msg = msg.split('\n') - extraleft = 0 + let extraleft = 0 if justify is not None: - msgwidth = self.len(max(msg, key = self.len)) + self.balloon.minwidth + let msgwidth = self.len(max(msg, key = self.len)) + self.balloon.minwidth extraleft = innerleft if msgwidth > width: if (justify == 'l') and (wrap is not None): @@ -507,7 +509,7 @@ class Backend(): if extraleft + msgwidth > wrap: extraleft -= msgwidth - wrap - rc = self.balloon.get(width, height, msg, Backend.len); + let rc = self.balloon.get(width, height, msg, Backend.len) if extraleft > 0: rc = ' ' * extraleft + rc.replace('\n', '\n' + ' ' * extraleft) return rc @@ -521,39 +523,39 @@ class Backend(): @param wrap:int The width at where to force wrapping @return :str The message wrapped ''' - wraplimit = os.environ['PONYSAY_WRAP_LIMIT'] if 'PONYSAY_WRAP_LIMIT' in os.environ else '' + let wraplimit = os.environ['PONYSAY_WRAP_LIMIT'] if 'PONYSAY_WRAP_LIMIT' in os.environ else '' wraplimit = 8 if len(wraplimit) == 0 else int(wraplimit) - wrapexceed = os.environ['PONYSAY_WRAP_EXCEED'] if 'PONYSAY_WRAP_EXCEED' in os.environ else '' + let wrapexceed = os.environ['PONYSAY_WRAP_EXCEED'] if 'PONYSAY_WRAP_EXCEED' in os.environ else '' wrapexceed = 5 if len(wrapexceed) == 0 else int(wrapexceed) - buf = '' + let buf = '' + let AUTO_PUSH = '\033[01010~' + let AUTO_POP = '\033[10101~' try: - AUTO_PUSH = '\033[01010~' - AUTO_POP = '\033[10101~' - msg = message.replace('\n', AUTO_PUSH + '\n' + AUTO_POP) - cstack = ColourStack(AUTO_PUSH, AUTO_POP) + let msg = message.replace('\n', AUTO_PUSH + '\n' + AUTO_POP) + let cstack = ColourStack(AUTO_PUSH, AUTO_POP) for c in msg: buf += c + cstack.feed(c) - lines = buf.replace(AUTO_PUSH, '').replace(AUTO_POP, '').split('\n') + let lines = buf.replace(AUTO_PUSH, '').replace(AUTO_POP, '').split('\n') buf = '' for line in lines: - b = [None] * len(line) - map = {0 : 0} - (bi, cols, w) = (0, 0, wrap) - (indent, indentc) = (-1, 0) + let b = [None] * len(line) + let map = {0 : 0} + let bi, cols, w = (0, 0, wrap) + let indent, indentc = (-1, 0) - (i, n) = (0, len(line)) + let i, n = (0, len(line)) while i <= n: - d = None + let d = None if i < n: d = line[i] i += 1 if d == '\033': ## Invisible stuff i -= 1 - colourseq = Backend.getColour(line, i) + let colourseq = Backend.getColour(line, i) b[bi : bi + len(colourseq)] = colourseq i += len(colourseq) bi += len(colourseq) @@ -571,18 +573,18 @@ class Backend(): map[cols] = bi else: ## Wrap? - mm = 0 - bisub = 0 - iwrap = wrap - (0 if indent == 1 else indentc) + let mm = 0 + let bisub = 0 + let iwrap = wrap - (0 if indent == 1 else indentc) while ((w > wraplimit) and (cols > w + wrapexceed)) or (cols > iwrap): ## wrap - x = w; + let x = w if mm + x not in map: # Too much whitespace? cols = 0 break - nbsp = b[map[mm + x]] == ' ' # nbsp - m = map[mm + x] + let nbsp = b[map[mm + x]] == ' ' # nbsp + let m = map[mm + x] if ('­' in b[bisub : m]) and not nbsp: # soft hyphen hyphen = m - 1 @@ -597,7 +599,7 @@ class Backend(): for bb in b[bisub : m]: buf += bb - buf += '\n' if nbsp else '\0\n' + buf += '\n' if nbsp else 'あ\n' cols -= x - (0 if nbsp else 1) bisub = m @@ -635,21 +637,15 @@ class Backend(): w -= indentc buf += '\n' - rc = '\n'.join(line.rstrip(' ') for line in buf[:-1].split('\n')); - rc = rc.replace('­', ''); # remove soft hyphens - rc = rc.replace('\0', '%s%s%s' % (AUTO_PUSH, self.hyphen, AUTO_POP)) + let rc = '\n'.join(line.rstrip(' ') for line in buf[:-1].split('\n')) + rc = rc.replace('­', '') # remove soft hyphens + rc = rc.replace('あ', '{}{}{}' .format (AUTO_PUSH, self.hyphen, AUTO_POP)) return rc except Exception as err: - import traceback - errormessage = ''.join(traceback.format_exception(type(err), err, None)) - rc = '\n'.join(line.rstrip(' ') for line in buf.split('\n')); - rc = rc.replace('\0', '%s%s%s' % (AUTO_PUSH, self.hyphen, AUTO_POP)) + let errormessage = str(err) + let rc = '\n'.join(line.rstrip(' ') for line in buf.split('\n')) + rc = rc.replace('あ', '{}{}{}' .format (AUTO_PUSH, self.hyphen, AUTO_POP)) errormessage += '\n---- WRAPPING BUFFER ----\n\n' + rc - try: - if os.readlink('/proc/self/fd/2') != os.readlink('/proc/self/fd/1'): - printerr(errormessage, end='') - return message - except: - pass - return message + '\n\n\033[0;1;31m---- EXCEPTION IN PONYSAY WHILE WRAPPING ----\033[0m\n\n' + errormessage + printerr(errormessage, end='') + return message diff --git a/src/balloon.py b/ponysay/balloon.krk similarity index 80% rename from src/balloon.py rename to ponysay/balloon.krk index 0f1909e4..16e7d34f 100644 --- a/src/balloon.py +++ b/ponysay/balloon.krk @@ -29,10 +29,18 @@ 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 ucs import * +from ponysay.common import printerr, printinfo, gettermsize, endswith +from ponysay.ucs import UCS +import fileio +def fmax(lst,key): + if not lst: return None + let best = lst[0] + for i in lst[1:]: + if key(best) < key(i): + best = i + return best class Balloon(): ''' @@ -73,15 +81,15 @@ class Balloon(): (self.sse, self.s, self.ssw) = (sse, s, ssw) (self.sww, self.w, self.nww) = (sww, w, nww) - _ne = max(ne, key = UCS.dispLen) - _nw = max(nw, key = UCS.dispLen) - _se = max(se, key = UCS.dispLen) - _sw = max(sw, key = UCS.dispLen) + let _ne = fmax(ne, key = UCS.dispLen) + let _nw = fmax(nw, key = UCS.dispLen) + let _se = fmax(se, key = UCS.dispLen) + let _sw = fmax(sw, key = UCS.dispLen) - minE = UCS.dispLen(max([_ne, nee, e, see, _se, ee], key = UCS.dispLen)) - minW = UCS.dispLen(max([_nw, nww, e, sww, _sw, ww], key = UCS.dispLen)) - minN = len(max([ne, nne, n, nnw, nw], key = len)) - minS = len(max([se, sse, s, ssw, sw], key = len)) + let minE = UCS.dispLen(fmax([_ne, nee, e, see, _se, ee], key = UCS.dispLen)) + let minW = UCS.dispLen(fmax([_nw, nww, e, sww, _sw, ww], key = UCS.dispLen)) + let minN = len(fmax([ne, nne, n, nnw, nw], key = len)) + let minS = len(fmax([se, sse, s, ssw, sw], key = len)) self.minwidth = minE + minE self.minheight = minN + minS @@ -98,26 +106,27 @@ class Balloon(): @return :str The balloon as a formated string ''' ## Get dimension - h = self.minheight + len(lines) - w = self.minwidth + lencalc(max(lines, key = lencalc)) + let h = self.minheight + len(lines) + let w = self.minwidth + lencalc(fmax(lines, key = lencalc)) if w < minw: w = minw if h < minh: h = minh ## Create edges + let ws, es if len(lines) > 1: - (ws, es) = ({0 : self.nww, len(lines) - 1 : self.sww}, {0 : self.nee, len(lines) - 1 : self.see}) + ws, es = ({0 : self.nww, len(lines) - 1 : self.sww}, {0 : self.nee, len(lines) - 1 : self.see}) for j in range(1, len(lines) - 1): ws[j] = self.w es[j] = self.e else: - (ws, es) = ({0 : self.ww}, {0 : self.ee}) + ws, es = ({0 : self.ww}, {0 : self.ee}) - rc = [] + let rc = [] ## Create the upper part of the balloon for j in range(0, len(self.n)): - outer = UCS.dispLen(self.nw[j]) + UCS.dispLen(self.ne[j]) - inner = UCS.dispLen(self.nnw[j]) + UCS.dispLen(self.nne[j]) + let outer = UCS.dispLen(self.nw[j]) + UCS.dispLen(self.ne[j]) + let inner = UCS.dispLen(self.nnw[j]) + UCS.dispLen(self.nne[j]) if outer + inner <= w: rc.append(self.nw[j] + self.nnw[j] + self.n[j] * (w - outer - inner) + self.nne[j] + self.ne[j]) else: @@ -129,8 +138,8 @@ class Balloon(): ## Create the lower part of the balloon for j in range(0, len(self.s)): - outer = UCS.dispLen(self.sw[j]) + UCS.dispLen(self.se[j]) - inner = UCS.dispLen(self.ssw[j]) + UCS.dispLen(self.sse[j]) + let outer = UCS.dispLen(self.sw[j]) + UCS.dispLen(self.se[j]) + let inner = UCS.dispLen(self.ssw[j]) + UCS.dispLen(self.sse[j]) if outer + inner <= w: rc.append(self.sw[j] + self.ssw[j] + self.s[j] * (w - outer - inner) + self.sse[j] + self.se[j]) else: @@ -155,24 +164,25 @@ class Balloon(): return Balloon('\\', '/', 'X', '< ', ' >', [' _'], ['_'], ['_'], ['_'], ['_ '], ' \\', ' |', ' /', ['- '], ['-'], ['-'], ['-'], [' -'], '\\ ', '| ', '/ ') ## Initialise map for balloon parts - map = {} + let map = {} for elem in ('\\', '/', 'X', 'ww', 'ee', 'nw', 'nnw', 'n', 'nne', 'ne', 'nee', 'e', 'see', 'se', 'sse', 's', 'ssw', 'sw', 'sww', 'w', 'nww'): map[elem] = [] ## Read all lines in the balloon file - with open(balloonfile, 'rb') as balloonstream: - data = balloonstream.read().decode('utf8', 'replace') + let data + with fileio.open(balloonfile, 'rb') as balloonstream: + data = balloonstream.read().decode() data = [line.replace('\n', '') for line in data.split('\n')] ## Parse the balloon file, and fill the map - last = None + let last = None for line in data: if len(line) > 0: if line[0] == ':': map[last].append(line[1:]) else: last = line[:line.index(':')] - value = line[len(last) + 1:] + let value = line[len(last) + 1:] map[last].append(value) ## Return the balloon diff --git a/src/colourstack.py b/ponysay/colourstack.krk similarity index 85% rename from src/colourstack.py rename to ponysay/colourstack.krk index c6b4a88f..4bf73edb 100644 --- a/src/colourstack.py +++ b/ponysay/colourstack.krk @@ -29,7 +29,7 @@ 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 ponysay.common import printerr, printinfo, gettermsize, endswith @@ -63,7 +63,10 @@ class ColourStack(): @return :str String that should be inserted into your buffer ''' - self.stack.insert(0, [self.bufproto, None, None, [False] * 9]) + if self.stack: + self.stack.insert(0, [self.bufproto, None, None, [False] * 9]) + else: + self.stack.append([self.bufproto, None, None, [False] * 9]) if len(self.stack) == 1: return None return '\033[0m' @@ -75,11 +78,11 @@ class ColourStack(): @return :str String that should be inserted into your buffer ''' - old = self.stack.pop(0) - rc = '\033[0;' + let old = self.stack.pop(0) + let rc = '\033[0;' if len(self.stack) == 0: # last resort in case something made it pop too mush push() - new = self.stack[0] + let new = self.stack[0] if new[1] is not None: rc += new[1] + ';' if new[2] is not None: rc += new[2] + ';' for i in range(0, 9): @@ -101,10 +104,10 @@ class ColourStack(): if (char == '~') or (('a' <= char) and (char <= 'z')) or (('A' <= char) and (char <= 'Z')): if (self.seq[0] == '[') and (self.seq[-1] == 'm'): self.seq = self.seq[1:-1].split(';') - (i, n) = (0, len(self.seq)) + let i, n = (0, len(self.seq)) while i < n: - part = self.seq[i] - p = 0 if part == '' else int(part) + let part = self.seq[i] + let p = 0 if part == '' else int(part) i += 1 if p == 0: self.stack[0][1:] = [None, None, [False] * 9] elif 1 <= p <= 9: self.stack[0][3][p - 1] = True @@ -116,17 +119,17 @@ class ColourStack(): elif 40 <= p <= 47: self.stack[0][2] = part elif 100 <= p <= 107: self.stack[0][2] = part elif p == 38: - self.stack[0][1] = '%s;%s;%s' % (part, self.seq[i], self.seq[i + 1]) + self.stack[0][1] = '{};{};{}' .format (part, self.seq[i], self.seq[i + 1]) i += 2 elif p == 48: - self.stack[0][2] = '%s;%s;%s' % (part, self.seq[i], self.seq[i + 1]) + self.stack[0][2] = '{};{};{}' .format (part, self.seq[i], self.seq[i + 1]) i += 2 self.seq = None elif char == '\033': self.seq = '' - buf = self.stack[0][0] + let buf = self.stack[0][0] buf = buf[1:] + char - rc = '' + let rc = '' if buf[-self.lenpush:] == self.autopush: rc = self.push() elif buf[-self.lenpop:] == self.autopop: rc = self.pop() self.stack[0][0] = buf diff --git a/src/common.py b/ponysay/common.krk similarity index 60% rename from src/common.py rename to ponysay/common.krk index b4e6f40b..1bbae95e 100644 --- a/src/common.py +++ b/ponysay/common.krk @@ -30,30 +30,8 @@ lines and the ‘FREE’ is and upper case and directly followed by the colon. ''' +import fileio import os -import shutil -import sys -import random -from subprocess import Popen, PIPE - - - -VERSION = 'dev' # this line should not be edited, it is fixed by the build system -''' -The version of ponysay -''' - - - -def print(text = '', end = '\n'): - ''' - 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) - - @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) - ''' - sys.stdout.buffer.write((str(text) + end).encode('utf-8')) def printerr(text = '', end = '\n'): ''' @@ -62,9 +40,8 @@ def printerr(text = '', end = '\n'): @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) ''' - sys.stderr.buffer.write((str(text) + end).encode('utf-8')) + fileio.stderr.write((str(text) + end)) -fd3 = None def printinfo(text = '', end = '\n'): ''' /proc/self/fd/3 equivalent to print() @@ -72,12 +49,8 @@ def printinfo(text = '', end = '\n'): @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) ''' - global fd3 - if os.path.exists('/proc/self/fd/3') and not os.path.isdir(os.path.realpath('/proc/self/fd/3')): - if fd3 is None: - fd3 = os.fdopen(3, 'w') - if fd3 is not None: - fd3.write(str(text) + end) + pass + #os.write(2, (str(text) + end).encode()) def endswith(text, ending): @@ -97,12 +70,12 @@ def gettermsize(): @return (rows, columns):(int, int) The number or lines and the number of columns in the terminal's display area ''' - ## 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): - termsize = Popen(['stty', 'size'], stdout=PIPE, stdin=channel, stderr=PIPE).communicate()[0] - if len(termsize) > 0: - termsize = termsize.decode('utf8', 'replace')[:-1].split(' ') # [:-1] removes a \n - termsize = [int(item) for item in termsize] - return termsize - return (24, 80) # fall back to minimal sane size + # TODO we don't have a thing for this?? + try: + os.system("stty size > /tmp/.ponysaysize") + with fileio.open("/tmp/.ponysaysize") as f: + let tmp = f.read().strip() + return tuple(int(x) for x in tmp.split(' ')) + except: + return (24, 80) # fall back to minimal sane size diff --git a/src/kms.py b/ponysay/kms.krk similarity index 99% rename from src/kms.py rename to ponysay/kms.krk index 745bfa90..2d4d8a06 100644 --- a/src/kms.py +++ b/ponysay/kms.krk @@ -29,7 +29,7 @@ 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 ponysay.common import * diff --git a/src/lists.py b/ponysay/lists.krk similarity index 79% rename from src/lists.py rename to ponysay/lists.krk index 6a8c4a71..5ffd429b 100644 --- a/src/lists.py +++ b/ponysay/lists.krk @@ -34,11 +34,17 @@ File listing functions. ''' -from ucs import * -import itertools +from ponysay.common import endswith, gettermsize +from ponysay.ucs import UCS +import os +def _range(min,max,step): + let i = min + while i < max: + yield i + i += step -def _columnise_list(items: list, available_width: int, length_fn: callable, separation : int = 2): +def _columnise_list(items: list, available_width: int, length_fn: function, separation : int = 2): """ From a list of items, produce a list of columns. Each columns is a list of tuples. Each tuple contains the element and a an int, specifying how much shorter the element is compared to the column width. @@ -48,18 +54,27 @@ def _columnise_list(items: list, available_width: int, length_fn: callable, sepa :param separation: Amount of space to insert between columns. """ - num_items = len(items) - items_with_length = [(i, length_fn(i)) for i in items] - max_item_length = max(i for _, i in items_with_length) + let num_items = len(items) + let items_with_length = [(i, length_fn(i)) for i in items] + let max_item_length = max(i for _, i in items_with_length) # Make at least one column to handle very narrow terminals. - num_columns = max((available_width + separation) // (max_item_length + separation), 1) - column_length = (num_items - 1) // num_columns + 1 + let num_columns = max((available_width + separation) // (max_item_length + separation), 1) + let column_length = (num_items - 1) // num_columns + 1 - items_with_spacing = [(i, max_item_length - l + separation) for i, l in items_with_length] + let items_with_spacing = [(i, max_item_length - l + separation) for i, l in items_with_length] - return [items_with_spacing[i:i + column_length] for i in range(0, num_items, column_length)] + return [items_with_spacing[i:(i + column_length)] for i in _range(0, num_items, column_length)] +def _sorted(lst, key): + class Sortable(): + def __init__(self, thing): + self.thing = thing + def __lt__(self, other): + return key(self.thing) < key(other.thing) + let out = [Sortable(l) for l in lst] + out.sort() + return [l.thing for l in out] def _print_columnised(items): ''' @@ -68,26 +83,24 @@ def _print_columnised(items): @param ponies:list<(str, str)> All items to list, each item should have to elements: unformatted name, formatted name. ''' ## Get terminal width - _, term_width = gettermsize() + let _, term_width = gettermsize() - columns = _columnise_list( - sorted(items, key = lambda x: x[0]), + let columns = _columnise_list( + _sorted(items, key = lambda x: x[0]), term_width, lambda x: UCS.dispLen(x[0])) - for row in itertools.zip_longest(*columns): + for row in zip(*columns): def iter_parts(): - spacing = 0 - + let spacing = 0 for cell in row: if cell: # Yield this here to prevent whitespace to be printed after the last column. yield ' ' * spacing - - (_, item), spacing = cell - + let item, _, inner + inner, spacing = cell + _, item = inner yield item - print(''.join(iter_parts())) print() @@ -114,7 +127,7 @@ def simplelist(ponydirs, quoters = [], ucsiser = None): ''' for ponydir in ponydirs: # Loop ponydirs ## Get all ponies in the directory - ponies = _get_file_list(ponydir, '.pony') + let ponies = _get_file_list(ponydir, '.pony') print() @@ -125,8 +138,8 @@ def simplelist(ponydirs, quoters = [], ucsiser = None): ## If ther directory is not empty print its name and all ponies, columnised if len(ponies) == 0: continue - print('\033[1mponies located in ' + ponydir + '\033[21m') - _print_columnised([(pony, '\033[1m' + pony + '\033[21m' if pony in quoters else pony) for pony in ponies]) + print('\033[1mponies located in ' + ponydir + '\033[22m') + _print_columnised([(pony, '\033[1m' + pony + '\033[22m' if pony in quoters else pony) for pony in ponies]) def linklist(ponydirs = None, quoters = [], ucsiser = None): @@ -145,7 +158,7 @@ def linklist(ponydirs = None, quoters = [], ucsiser = None): ## If there are no ponies in the directory skip to next directory, otherwise, print the directories name if len(ponies) == 0: continue - print('\033[1mponies located in ' + ponydir + '\033[21m') + print('\033[1mponies located in ' + ponydir + '\033[22m') ## UCS:ise pony names pseudolinkmap = {} @@ -156,7 +169,7 @@ def linklist(ponydirs = None, quoters = [], ucsiser = None): pairs = [] for pony in ponies: if pony in pseudolinkmap: - pairs.append((pony, pseudolinkmap[pony] + '.pony')); + pairs.append((pony, pseudolinkmap[pony] + '.pony')) else: pairs.append((pony, os.path.realpath(ponydir + pony + '.pony') if os.path.islink(ponydir + pony + '.pony') else None)) @@ -179,7 +192,7 @@ def linklist(ponydirs = None, quoters = [], ucsiser = None): ponies = {} for pony in ponymap: w = UCS.dispLen(pony) - item = '\033[1m' + pony + '\033[21m' if (pony in quoters) else pony + item = '\033[1m' + pony + '\033[22m' if (pony in quoters) else pony syms = ponymap[pony] syms.sort() if len(syms) > 0: @@ -190,9 +203,9 @@ def linklist(ponydirs = None, quoters = [], ucsiser = None): w += UCS.dispLen(sym) if first: first = False else: item += ' ' - item += '\033[1m' + sym + '\033[21m' if (sym in quoters) else sym + item += '\033[1m' + sym + '\033[22m' if (sym in quoters) else sym item += ')' - ponies[(item.replace('\033[1m', '').replace('\033[21m', ''), item)] = w + ponies[(item.replace('\033[1m', '').replace('\033[22m', ''), item)] = w ## Print the ponies, columnised _print_columnised(list(ponies)) @@ -206,14 +219,14 @@ def onelist(pony_dirs, ucsiser): @param ucsiser:(list)→void Function used to UCS:ise names ''' ## Get all pony files - ponies = [name for dir in pony_dirs for name in _get_file_list(dir, '.pony')] + let ponies = [name for dir in pony_dirs for name in _get_file_list(dir, '.pony')] ## UCS:ise and sort ucsiser(ponies) ponies.sort() ## Print each one on a seperate line, but skip duplicates - last = '' + let last = '' for pony in ponies: if not pony == last: last = pony diff --git a/src/metadata.py b/ponysay/metadata.krk similarity index 98% rename from src/metadata.py rename to ponysay/metadata.krk index 6038c26b..6b923bca 100644 --- a/src/metadata.py +++ b/ponysay/metadata.krk @@ -29,7 +29,7 @@ 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 ponysay.common import printerr, printinfo, gettermsize, endswith diff --git a/src/ponysay.py b/ponysay/ponysay.krk similarity index 85% rename from src/ponysay.py rename to ponysay/ponysay.krk index 17e02f5a..98417e72 100755 --- a/src/ponysay.py +++ b/ponysay/ponysay.krk @@ -29,16 +29,72 @@ 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 backend import * -from balloon import * -from spellocorrecter import * -from ucs import * -from kms import * -import lists -from metadata import * +from ponysay.common import printerr, printinfo, gettermsize, endswith +from ponysay.backend import Backend +from ponysay.balloon import Balloon +from ponysay.spellocorrecter import SpelloCorrecter +from ponysay.ucs import UCS +import ponysay.lists as lists +from ponysay.metadata import Metadata +import os +import kuroko +import fileio +import stat +import random + +def randrange(low,high): + with fileio.open('/dev/urandom','rb') as f: + let b = f.read(4) + let val = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3] + let flt = val / 0xFFFFFFFF + return int(flt*(high-low)+low) + +def rfind(self, sub): + let last = self.find(sub) + while True: + let next = self.find(sub,last+1) + if next == -1: break + last = next + return last + +str.rfind = rfind + +random.randrange = randrange + +class OSExtensions(): + def exists(self, p): + try: + os.stat(p) + return True + except: + return False + def isdir(self, p): + try: + let res = os.stat(p) + return stat.S_ISDIR(res.st_mode) + except: + return False + def isfile(self, p): + try: + let res = os.stat(p) + return stat.S_ISREG(res.st_mode) + except: + return False + def islink(self, p): + try: + let res = os.stat(p) + return stat.S_ISLNK(res.st_mode) + except: + return False + +os.path = OSExtensions() +let exit = os.exit + +def listdir(p): + return [c['name'] for c in fileio.opendir(p)] +os.listdir = listdir class Ponysay(): ''' @@ -55,7 +111,6 @@ class Ponysay(): if len(self.HOME) == 0: os.environ['HOME'] = self.HOME = os.path.expanduser('~') - ## Load extension and configurations via ponysayrc for file in ('$XDG_CONFIG_HOME/ponysay/ponysayrc', '$HOME/.config/ponysay/ponysayrc', '$HOME/.ponysayrc', '/etc/ponysayrc'): file = self.__parseFile(file) @@ -84,17 +139,17 @@ class Ponysay(): # Whether stdin is piped - self.pipelinein = not sys.stdin.isatty() + self.pipelinein = not os.isatty(0) #sys.stdin.isatty() # Whether stdout is piped - self.pipelineout = not sys.stdout.isatty() + self.pipelineout = not os.isatty(1) #sys.stdout.isatty() # Whether stderr is piped - self.pipelineerr = not sys.stderr.isatty() + self.pipelineerr = not os.isatty(2) #sys.stderr.isatty() # Whether KMS is used - self.usekms = KMS.usingKMS(self.linuxvt) + self.usekms = False #KMS.usingKMS(self.linuxvt) # Mode string that modifies or adds $ variables in the pony image @@ -128,9 +183,9 @@ class Ponysay(): @return The target file name, None if the environment variables are not declared ''' if '$' in file: - buf = '' - esc = False - var = None + let buf = '' + let esc = False + let var = None for c in file: if esc: buf += c @@ -162,9 +217,9 @@ class Ponysay(): @param directory:str The directory base name @return :list Absolute directory names ''' - appendset = set() - rc = [] - _ponydirs = cls.__share(directory) + let appendset = set() + let rc = [] + let _ponydirs = cls.__share(directory) for ponydir in _ponydirs: if (ponydir is not None) and os.path.isdir(ponydir) and (ponydir not in appendset): rc.append(ponydir) @@ -188,7 +243,8 @@ class Ponysay(): return [cat(cls.__parseFile(item), file) for item in [ '$XDG_DATA_HOME/ponysay/', '$HOME/.local/share/ponysay/', - '/usr/share/ponysay/' + '/usr/share/ponysay/', + './' ]] @@ -197,7 +253,7 @@ class Ponysay(): ''' Check if ponythink is executed ''' - isthink = sys.argv[0] + let isthink = kuroko.argv[0] if os.sep in isthink: isthink = isthink[isthink.rfind(os.sep) + 1:] if os.extsep in isthink: @@ -217,7 +273,7 @@ class Ponysay(): args.help() exit(254) return - self.args = args; + self.args = args ## Emulate termial capabilities if self.__test_nfdnf('-X'): (self.linuxvt, self.usekms) = (False, False) @@ -229,8 +285,8 @@ class Ponysay(): ## Variadic variants of -f, -q &c for sign in ('-', '+'): for letter in ('f', 'F', 'q', 'Q'): - ssl = sign + sign + letter - sl = sign + letter + let ssl = sign + sign + letter + let sl = sign + letter if (ssl in args.opts) and (args.opts[ssl] is not None): if args.opts[sl] is not None: args.opts[sl] += args.opts[ssl] else: args.opts[sl] = args.opts[ssl] @@ -343,11 +399,11 @@ class Ponysay(): if args.opts[key] is not None: return False return True - keys = ['-f', '+f', '-F', '-q'] ## TODO +q -Q + let keys = ['-f', '+f', '-F', '-q'] ## TODO +q -Q if test(keys, False): for ponydir in self.ponydirs: if os.path.isfile(ponydir + 'best.pony') or os.path.islink(ponydir + 'best.pony'): - pony = os.path.realpath(ponydir + 'best.pony') # Canonical path + let pony = os.path.realpath(ponydir + 'best.pony') # Canonical path if test(keys, True): args.opts['-f'] = [pony] else: @@ -364,8 +420,8 @@ class Ponysay(): @param args:ArgParser Parsed command line arguments ''' ## Read UCS configurations - env_ucs = os.environ['PONYSAY_UCS_ME'] if 'PONYSAY_UCS_ME' in os.environ else '' - ucs_conf = 0 + let env_ucs = os.environ['PONYSAY_UCS_ME'] if 'PONYSAY_UCS_ME' in os.environ else '' + let ucs_conf = 0 if env_ucs in ('yes', 'y', '1'): ucs_conf = 1 elif env_ucs in ('harder', 'h', '2'): ucs_conf = 2 @@ -410,8 +466,8 @@ class Ponysay(): @param links:map? Map to fill with simulated symlink ponies, may be `None` ''' ## Read UCS configurations - env_ucs = os.environ['PONYSAY_UCS_ME'] if 'PONYSAY_UCS_ME' in os.environ else '' - ucs_conf = 0 + let env_ucs = os.environ['PONYSAY_UCS_ME'] if 'PONYSAY_UCS_ME' in os.environ else '' + let ucs_conf = 0 if env_ucs in ('yes', 'y', '1'): ucs_conf = 1 elif env_ucs in ('harder', 'h', '2'): ucs_conf = 2 @@ -420,20 +476,20 @@ class Ponysay(): return ## Read all lines in all UCS → ASCII map files - maplines = [] + let maplines = [] for ucsmap in self.ucsmaps: if os.path.isfile(ucsmap): with open(ucsmap, 'rb') as mapfile: maplines += [line.replace('\n', '') for line in mapfile.read().decode('utf8', 'replace').split('\n')] ## Create UCS → ASCII mapping from read lines - map = {} - stripset = ' \t' # must be string, wtf! and way doesn't python's doc say so + let map = {} + let stripset = ' \t' # must be string, wtf! and way doesn't python's doc say so for line in maplines: if not line.startswith('#'): - s = line.index('→') - ucs = line[:s] .strip(stripset) - ascii = line[s + 1:].strip(stripset) + let s = line.index('→') + let ucs = line[:s] .strip(stripset) + let ascii = line[s + 1:].strip(stripset) map[ascii] = ucs ## Apply UCS → ASCII mapping to ponies, by alias if weak settings @@ -466,31 +522,31 @@ class Ponysay(): selection = [self.__selectAnypony(args)] ## Select a random pony of the choosen ones - pony = selection[random.randrange(0, len(selection))] + let pony = selection[random.randrange(0, len(selection))] if os.path.exists(pony[0]): - ponyname = pony[0].split(os.sep)[-1] + let ponyname = pony[0].split(os.sep)[-1] if os.extsep in ponyname: ponyname = ponyname[:ponyname.rfind(os.extsep)] return (pony[0], self.__getQuote(ponyname, pony[0]) if pony[2] else None) else: - possibilities = [f.split(os.sep)[-1][:-5] for f in pony[1]] + let possibilities = [f.split(os.sep)[-1][:-5] for f in pony[1]] if pony[0] not in possibilities: if not alt: - autocorrect = SpelloCorrecter(possibilities) - (alternatives, dist) = autocorrect.correct(pony[0]) - limit = os.environ['PONYSAY_TYPO_LIMIT'] if 'PONYSAY_TYPO_LIMIT' in os.environ else '' + let autocorrect = SpelloCorrecter(possibilities) + let alternatives, dist = autocorrect.correct(pony[0]) + let limit = os.environ['PONYSAY_TYPO_LIMIT'] if 'PONYSAY_TYPO_LIMIT' in os.environ else '' limit = 5 if len(limit) == 0 else int(limit) if (len(alternatives) > 0) and (dist <= limit): - (_, files, quote) = pony + let _, files, quote = pony return self.__getPony([(a, files, quote) for a in alternatives], True) - printerr('I have never heard of anypony named %s' % pony[0]); + printerr('I have never heard of anypony named %s' % pony[0]) if not self.usingstandard: - printerr('Use -f/-q or -F if it a MLP:FiM pony'); + printerr('Use -f/-q or -F if it a MLP:FiM pony') if not self.usingextra: - printerr('Have you tested +f or -F?'); + printerr('Have you tested +f or -F?') exit(252) else: - file = pony[1][possibilities.index(pony[0])] + let file = pony[1][possibilities.index(pony[0])] return (file, self.__getQuote(pony[0], file) if pony[2] else None) @@ -501,30 +557,30 @@ class Ponysay(): @param args:ArgParser Parsed command line arguments @return (name, dirfile, quote):(str, list, bool) The pony name, pony file with the directory, and whether to use ponyquotes ''' - quote = args.opts['-q'] is not None ## TODO +q -Q - standard = (args.opts['-f'] is not None) or (args.opts['-F'] is not None) or (args.opts['-q'] is not None) ## TODO -Q - extra = (args.opts['+f'] is not None) or (args.opts['-F'] is not None) ## TODO +q -Q + let quote = args.opts['-q'] is not None ## TODO +q -Q + let standard = (args.opts['-f'] is not None) or (args.opts['-F'] is not None) or (args.opts['-q'] is not None) ## TODO -Q + let extra = (args.opts['+f'] is not None) or (args.opts['-F'] is not None) ## TODO +q -Q if not (standard or extra): standard = True - ponydirs = (self.ponydirs if standard else []) + (self.extraponydirs if extra else []); - quoters = self.__quoters() if standard and quote else None ## TODO +q -Q + let ponydirs = (self.ponydirs if standard else []) + (self.extraponydirs if extra else []) + let quoters = self.__quoters() if standard and quote else None ## TODO +q -Q if (quoters is not None) and (len(quoters) == 0): printerr('Princess Celestia! All the ponies are mute!') exit(250) ## Get all ponies, with quotes - oldponies = {} + let oldponies = {} self.__getAllPonies(standard, extra, oldponies, quoters) ## Apply restriction - ponies = self.__applyRestriction(oldponies, ponydirs) + let ponies = self.__applyRestriction(oldponies, ponydirs) ## Select one pony and set all information - names = list(ponies.keys()) + let names = list(ponies.keys()) if len(names) == 0: printerr('All the ponies are missing, call the Princess!') exit(249) - pony = names[random.randrange(0, len(names))] + let pony = names[random.randrange(0, len(names))] return (pony, [ponies[pony]], quote) @@ -554,7 +610,7 @@ class Ponysay(): for ponydir in directories: for ponyfile in os.listdir(ponydir): if endswith(ponyfile, '.pony'): - pony = ponyfile[:-5] + let pony = ponyfile[:-5] if (pony not in collection) and ((quoters is None) or (pony in quoters)): collection[pony] = ponydir + ponyfile @@ -575,7 +631,7 @@ class Ponysay(): oldponies = ponies ## Apply dimension restriction - ponies = {} + let ponies = {} self.__applyDimensionRestriction(ponies, oldponies, ponydirs) if len(ponies) > 0: oldponies = ponies @@ -606,9 +662,9 @@ class Ponysay(): @param oldponies:dict Collection of original ponies, maps to pony file @param ponydirs:list List of pony directories ''' - (termh, termw) = gettermsize() + let termh, termw = gettermsize() for ponydir in ponydirs: - (fitw, fith) = (None, None) + let fitw, fith = (None, None) if os.path.exists(ponydir + 'widths'): fitw = set() with open(ponydir + 'widths', 'rb') as file: @@ -619,7 +675,7 @@ class Ponysay(): Metadata.getFitting(fith, termh, file) for ponyfile in oldponies.values(): if ponyfile.startswith(ponydir): - pony = ponyfile[len(ponydir) : -5] + let pony = ponyfile[len(ponydir) : -5] if (fitw is None) or (pony in fitw): if (fith is None) or (pony in fith): ponies[pony] = ponyfile @@ -663,9 +719,9 @@ class Ponysay(): if quotedirs is None: quotedirs = self.quotedirs ## List all unique quote files - quotes = [] - quoteshash = set() - _quotes = [] + let quotes = [] + let quoteshash = set() + let _quotes = [] for quotedir in quotedirs: _quotes += [item[:item.index('.')] for item in os.listdir(quotedir)] for quote in _quotes: @@ -675,11 +731,11 @@ class Ponysay(): quotes.append(quote) ## Create a set of all ponies that have quotes - ponies = set() + let ponies = set() for ponydir in ponydirs: for pony in os.listdir(ponydir): if not pony[0] == '.': - p = pony[:-5] # remove .pony + let p = pony[:-5] # remove .pony for quote in quotes: if ('+' + p + '+') in ('+' + quote + '+'): if not p in ponies: @@ -760,8 +816,7 @@ class Ponysay(): @param standard:bool Include standard ponies @param extra:bool Include extra ponies ''' - - pony_dirs = (self.ponydirs if standard else []) + (self.extraponydirs if extra else []) + let pony_dirs = (self.ponydirs if standard else []) + (self.extraponydirs if extra else []) lists.onelist(pony_dirs, self.__ucsise) @@ -774,7 +829,7 @@ class Ponysay(): @param extra:bool Include extra ponies ''' ## Get all quoters - ponies = list(self.__quoters()) if standard else [] + let ponies = list(self.__quoters()) if standard else [] ## And now the extra ponies if extra: @@ -818,10 +873,10 @@ class Ponysay(): return None ## Get all balloons - balloons = {} + let balloons = {} for balloondir in self.balloondirs: for balloon in os.listdir(balloondir): - balloonfile = balloon + let balloonfile = balloon ## Use .think if running ponythink, otherwise .say if self.isthink and endswith(balloon, '.think'): balloon = balloon[:-6] @@ -840,12 +895,12 @@ class Ponysay(): balloons[name] = name ## Select a random balloon of the choosen ones - balloon = names[random.randrange(0, len(names))] + let balloon = names[random.randrange(0, len(names))] if balloon not in balloons: if not alt: - autocorrect = SpelloCorrecter(self.balloondirs, '.think' if self.isthink else '.say') - (alternatives, dist) = autocorrect.correct(balloon) - limit = os.environ['PONYSAY_TYPO_LIMIT'] if 'PONYSAY_TYPO_LIMIT' in os.environ else '' + let autocorrect = SpelloCorrecter(self.balloondirs, '.think' if self.isthink else '.say') + let alternatives, dist = autocorrect.correct(balloon) + let limit = os.environ['PONYSAY_TYPO_LIMIT'] if 'PONYSAY_TYPO_LIMIT' in os.environ else '' limit = 5 if len(limit) == 0 else int(limit) if (len(alternatives) > 0) and (dist <= limit): return self.__getBalloonPath(alternatives, True) @@ -885,12 +940,12 @@ class Ponysay(): @param args:ArgParser Parsed command line arguments ''' ## Get the pony - selection = [] + let selection = [] self.__getSelectedPonies(args, selection) - (pony, quote) = self.__getPony(selection, args) + let pony, quote = self.__getPony(selection, args) ## Get message and manipulate it - msg = self.__getMessage(args, quote) + let msg = self.__getMessage(args, quote) msg = self.__colouriseMessage(args, msg) msg = self.__compressMessage(args, msg) @@ -901,38 +956,38 @@ class Ponysay(): pony = self.__useImage(pony) ## If KMS is utilies, select a KMS pony file and create it if necessary - pony = KMS.kms(pony, self.HOME, self.linuxvt) + #pony = KMS.kms(pony, self.HOME, self.linuxvt) ## If in Linux VT clean the terminal (See info/pdf-manual [Printing in TTY with KMS]) if self.linuxvt: print('\033[H\033[2J', end='') ## Get width truncation and wrapping - widthtruncation = self.__getWidthTruncation() - messagewrap = self.__getMessageWrap(args) + let widthtruncation = self.__getWidthTruncation() + let messagewrap = self.__getMessageWrap(args) ## Get balloon object - balloonfile = self.__getBalloonPath(args.opts['-b'] if args.opts['-b'] is not None else None) + let balloonfile = self.__getBalloonPath(args.opts['-b'] if args.opts['-b'] is not None else None) printinfo('balloon style file: ' + str(balloonfile)) - balloon = self.__getBalloon(balloonfile) if args.opts['-o'] is None else None + let balloon = self.__getBalloon(balloonfile) if args.opts['-o'] is None else None ## Get hyphen style - hyphen = self.__getHyphen(args) + let hyphen = self.__getHyphen(args) ## Link and balloon colouring - linkcolour = self.__getLinkColour(args) - ballooncolour = self.__getBalloonColour(args) + let linkcolour = self.__getLinkColour(args) + let ballooncolour = self.__getBalloonColour(args) ## Determine --info/++info settings - minusinfo = args.opts['-i'] is not None - plusinfo = args.opts['+i'] is not None + let minusinfo = args.opts['-i'] is not None + let plusinfo = args.opts['+i'] is not None ## Run cowsay replacement - backend = Backend(message = msg, ponyfile = pony, wrapcolumn = messagewrap, width = widthtruncation, balloon = balloon, + let backend = Backend(message = msg, ponyfile = pony, wrapcolumn = messagewrap, width = widthtruncation, balloon = balloon, hyphen = hyphen, linkcolour = linkcolour, ballooncolour = ballooncolour, mode = self.mode, infolevel = 2 if plusinfo else (1 if minusinfo else 0)) backend.parse() - output = backend.output + let output = backend.output if output.endswith('\n'): output = output[:-1] @@ -947,7 +1002,7 @@ class Ponysay(): @param args:ArgParser Command line options @param selection:list<(name:str, file:str, quotes:bool)> List to fill with tuples of selected pony names, pony files and whether quotes are used ''' - (standard, extra) = ([], []) + let standard, extra = [], [] for ponydir in self.ponydirs: for pony in os.listdir(ponydir): if endswith(pony, '.pony'): @@ -956,8 +1011,8 @@ class Ponysay(): for pony in os.listdir(ponydir): if endswith(pony, '.pony'): extra.append(ponydir + pony) - both = standard + extra - for (opt, ponies, quotes) in [('-f', standard, False), ('+f', extra, False), ('-F', both, False), ('-q', standard, True)]: ## TODO +q -Q + let both = standard + extra + for opt, ponies, quotes in [('-f', standard, False), ('+f', extra, False), ('-F', both, False), ('-q', standard, True)]: ## TODO +q -Q if args.opts[opt] is not None: for pony in args.opts[opt]: selection.append((pony, ponies, quotes)) @@ -974,7 +1029,7 @@ class Ponysay(): if quote is not None: return quote if args.message is None: - return ''.join(sys.stdin.readlines()).rstrip() + return ''.join(fileio.stdin.readlines()).rstrip() return args.message @@ -1044,7 +1099,7 @@ class Ponysay(): @return :int? The column the truncate the output at, or `None` to not truncate it ''' - env_width = os.environ['PONYSAY_FULL_WIDTH'] if 'PONYSAY_FULL_WIDTH' in os.environ else None + let env_width = os.environ['PONYSAY_FULL_WIDTH'] if 'PONYSAY_FULL_WIDTH' in os.environ else None if env_width is None: env_width = 'auto' return gettermsize()[1] if env_width not in ('yes', 'y', '1') else None @@ -1056,7 +1111,7 @@ class Ponysay(): @param args:ArgParser Command line options @return :int? The message balloon wrapping column, or `None` if disabled ''' - messagewrap = 65 + let messagewrap = 65 if (args.opts['-W'] is not None) and (len(args.opts['-W'][0]) > 0): messagewrap = args.opts['-W'][0] if messagewrap[0] in 'nmsNMS': # m is left to n on QWERTY and s is left to n on Dvorak @@ -1075,10 +1130,10 @@ class Ponysay(): @param args:ArgParser Command line options @return :str The hyphen string to use at hyphenation ''' - hyphen = os.environ['PONYSAY_WRAP_HYPHEN'] if 'PONYSAY_WRAP_HYPHEN' in os.environ else None + let hyphen = os.environ['PONYSAY_WRAP_HYPHEN'] if 'PONYSAY_WRAP_HYPHEN' in os.environ else None if (hyphen is None) or (len(hyphen) == 0): hyphen = '-' - hyphencolour = '' + let hyphencolour = '' if args.opts['--colour-wrap'] is not None: hyphencolour = '\033[' + ';'.join(args.opts['--colour-wrap']) + 'm' return '\033[31m' + hyphencolour + hyphen @@ -1091,7 +1146,7 @@ class Ponysay(): @param args:ArgParser Command line options @return :str The colour of balloon links ''' - linkcolour = '' + let linkcolour = '' if args.opts['--colour-link'] is not None: linkcolour = '\033[' + ';'.join(args.opts['--colour-link']) + 'm' return linkcolour @@ -1104,7 +1159,7 @@ class Ponysay(): @param args:ArgParser Command line options @return :str The colour of balloons ''' - ballooncolour = '' + let ballooncolour = '' if args.opts['--colour-bubble'] is not None: ballooncolour = '\033[' + ';'.join(args.opts['--colour-bubble']) + 'm' return ballooncolour @@ -1117,17 +1172,17 @@ class Ponysay(): @param output:str The output truncated on the width but not on the height ''' ## Load height trunction settings - env_bottom = os.environ['PONYSAY_BOTTOM'] if 'PONYSAY_BOTTOM' in os.environ else None + let env_bottom = os.environ['PONYSAY_BOTTOM'] if 'PONYSAY_BOTTOM' in os.environ else None if env_bottom is None: env_bottom = '' - env_height = os.environ['PONYSAY_TRUNCATE_HEIGHT'] if 'PONYSAY_TRUNCATE_HEIGHT' in os.environ else None + let env_height = os.environ['PONYSAY_TRUNCATE_HEIGHT'] if 'PONYSAY_TRUNCATE_HEIGHT' in os.environ else None if env_height is None: env_height = '' - env_lines = os.environ['PONYSAY_SHELL_LINES'] if 'PONYSAY_SHELL_LINES' in os.environ else None + let env_lines = os.environ['PONYSAY_SHELL_LINES'] if 'PONYSAY_SHELL_LINES' in os.environ else None if (env_lines is None) or (env_lines == ''): env_lines = '2' ## Print the output, truncated on height if so set - lines = gettermsize()[0] - int(env_lines) + let lines = gettermsize()[0] - int(env_lines) if self.linuxvt or (env_height in ('yes', 'y', '1')): if env_bottom in ('yes', 'y', '1'): for line in output.split('\n')[: -lines]: diff --git a/src/ponysaytool.py b/ponysay/ponysaytool.krk similarity index 86% rename from src/ponysaytool.py rename to ponysay/ponysaytool.krk index 574a2baa..79496466 100755 --- a/src/ponysaytool.py +++ b/ponysay/ponysaytool.krk @@ -31,15 +31,16 @@ the colon. ''' import os -import sys -from subprocess import Popen, PIPE +import kuroko +import fileio -from argparser import * -from ponysay import * -from metadata import * +from ponysay.argparser import ArgParser +from ponysay.ponysay import Ponysay +from ponysay.metadata import Metadata -VERSION = 'dev' # this line should not be edited, it is fixed by the build system + +let VERSION = 'dev' # this line should not be edited, it is fixed by the build system ''' The version of ponysay ''' @@ -54,7 +55,7 @@ def print(text = '', end = '\n'): @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) ''' - sys.stdout.buffer.write((str(text) + end).encode('utf-8')) + fileio.stdout.buffer.write((str(text) + end).encode('utf-8')) def printerr(text = '', end = '\n'): ''' @@ -63,7 +64,7 @@ def printerr(text = '', end = '\n'): @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) ''' - sys.stderr.buffer.write((str(text) + end).encode('utf-8')) + fileio.stderr.buffer.write((str(text) + end).encode('utf-8')) @@ -80,7 +81,7 @@ class PonysayTool(): ''' if args.argcount == 0: args.help() - exit(255) + os.exit(255) return opts = args.opts @@ -88,7 +89,7 @@ class PonysayTool(): if unrecognised or (opts['-h'] is not None) or (opts['+h'] is not None): args.help(True if opts['+h'] is not None else None) if unrecognised: - exit(254) + os.exit(254) elif opts['-v'] is not None: print('%s %s' % ('ponysay-tool', VERSION)) @@ -105,33 +106,33 @@ class PonysayTool(): elif (opts['-b'] is not None) and (len(opts['-b']) == 1): try: if opts['--no-term-init'] is None: - print('\033[?1049h', end='') # initialise terminal + print('\[[?1049h', end='') # initialise terminal cmd = 'stty %s < %s > /dev/null 2> /dev/null' cmd %= ('-echo -icanon -echo -isig -ixoff -ixon', os.path.realpath('/dev/stdout')) Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE).wait() - print('\033[?25l', end='') # hide cursor + print('\[[?25l', end='') # hide cursor dir = opts['-b'][0] if not dir.endswith(os.sep): dir += os.sep self.browse(dir, opts['-r']) finally: - print('\033[?25h', end='') # show cursor + print('\[[?25h', end='') # show cursor cmd = 'stty %s < %s > /dev/null 2> /dev/null' cmd %= ('echo icanon echo isig ixoff ixon', os.path.realpath('/dev/stdout')) Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE).wait() if opts['--no-term-init'] is None: - print('\033[?1049l', end='') # terminate terminal + print('\[[?1049l', end='') # terminate terminal elif (opts['--edit'] is not None) and (len(opts['--edit']) == 1): pony = opts['--edit'][0] if not os.path.isfile(pony): printerr('%s is not an existing regular file' % pony) - exit(252) + os.exit(252) linuxvt = ('TERM' in os.environ) and (os.environ['TERM'] == 'linux') try: if opts['--no-term-init'] is None: - print('\033[?1049h', end='') # initialise terminal - if linuxvt: print('\033[?8c', end='') # use full block for cursor (_ is used by default in linux vt) + print('\[[?1049h', end='') # initialise terminal + if linuxvt: print('\[[?8c', end='') # use full block for cursor (_ is used by default in linux vt) cmd = 'stty %s < %s > /dev/null 2> /dev/null' cmd %= ('-echo -icanon -echo -isig -ixoff -ixon', os.path.realpath('/dev/stdout')) Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE).wait() @@ -140,9 +141,9 @@ class PonysayTool(): cmd = 'stty %s < %s > /dev/null 2> /dev/null' cmd %= ('echo icanon echo isig ixoff ixon', os.path.realpath('/dev/stdout')) Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE).wait() - if linuxvt: print('\033[?0c', end='') # restore cursor + if linuxvt: print('\[[?0c', end='') # restore cursor if opts['--no-term-init'] is None: - print('\033[?1049l', end='') # terminate terminal + print('\[[?1049l', end='') # terminate terminal elif (opts['--edit-rm'] is not None) and (len(opts['--edit-rm']) == 1): ponyfile = opts['--edit-rm'][0] @@ -174,7 +175,7 @@ class PonysayTool(): if data == '': if line != '$$$': printerr('Bad stash') - exit(251) + os.exit(251) data += '$$$\n' else: data += line + '\n' @@ -192,7 +193,7 @@ class PonysayTool(): else: args.help() - exit(253) + os.exit(253) def execPonysay(self, args, message = ''): @@ -214,9 +215,9 @@ class PonysayTool(): return args[key] if (args[key] is not None) and isinstance(args[key], list) else [args[key]] return None def __contains__(self, key): - return key in args; + return key in args - stdout = sys.stdout + stdout = fileio.stdout class StringInputStream(): def __init__(self): self.buf = '' @@ -232,11 +233,11 @@ class PonysayTool(): pass def isatty(self): return True - sys.stdout = StringInputStream() + fileio.stdout = StringInputStream() ponysay = Ponysay() ponysay.run(PhonyArgParser(args, message)) - out = sys.stdout.buf[:-1] - sys.stdout = stdout + out = fileio.stdout.buf[:-1] + fileio.stdout = stdout return out @@ -249,7 +250,7 @@ class PonysayTool(): ''' ## Call `stty` to determine the size of the terminal, this way is better than using python's ncurses termsize = None - for channel in (sys.stdout, sys.stdin, sys.stderr): + for channel in (fileio.stdout, fileio.stdin, fileio.stderr): termsize = Popen(['stty', 'size'], stdout=PIPE, stdin=channel, stderr=PIPE).communicate()[0] if len(termsize) > 0: termsize = termsize.decode('utf8', 'replace')[:-1].split(' ') # [:-1] removes a \n @@ -275,7 +276,7 @@ class PonysayTool(): ponies.sort() if len(ponies) == 0: - print('\033[1;31m%s\033[21m;39m' % 'No ponies... press Enter to exit.') + print('\[[1;31m%s\[[22m;39m' % 'No ponies... press Enter to exit.') input() panelw = Backend.len(max(ponies, key = Backend.len)) @@ -300,14 +301,14 @@ class PonysayTool(): ponyfile = (ponydir + '/' + ponies[ponyindex] + '.pony').replace('//', '/') pony = self.execPonysay({'-f' : ponyfile, '-W' : 'none', '-o' : None}).split('\n') - preprint = '\033[H\033[2J' + preprint = '\[[H\[[2J' if pony[0].startswith(preprint): pony[0] = pony[0][len(preprint):] ponyheight = len(pony) ponywidth = Backend.len(max(pony, key = Backend.len)) - AUTO_PUSH = '\033[01010~' - AUTO_POP = '\033[10101~' + AUTO_PUSH = '\[[01010~' + AUTO_POP = '\[[10101~' pony = '\n'.join(pony).replace('\n', AUTO_PUSH + '\n' + AUTO_POP) colourstack = ColourStack(AUTO_PUSH, AUTO_POP) buf = '' @@ -317,7 +318,7 @@ class PonysayTool(): if (oldx != x) or (oldy != y): (oldx, oldy) = (x, y) - print('\033[H\033[2J', end='') + print('\[[H\[[2J', end='') def getprint(pony, ponywidth, ponyheight, termw, termh, px, py): ponyprint = pony @@ -338,7 +339,7 @@ class PonysayTool(): elif px > 0: ponyprint = [px * ' ' + line for line in ponyprint] ponyprint = [(line if Backend.len(line) <= termw else line[:findcolumn(line, termw)]) for line in ponyprint] - ponyprint = ['\033[21;39;49;0m%s\033[21;39;49;0m' % line for line in ponyprint] + ponyprint = ['\[[22;39;49;0m%s\[[22;39;49;0m' % line for line in ponyprint] return '\n'.join(ponyprint) if quotes: @@ -361,24 +362,24 @@ class PonysayTool(): for line in ponies[panely:]: cury += 1 if os.path.islink((ponydir + '/' + line + '.pony').replace('//', '/')): - line = '\033[34m%s\033[39m' % ((line + ' ' * panelw)[:panelw]) + line = '\[[34m%s\[[39m' % ((line + ' ' * panelw)[:panelw]) else: line = (line + ' ' * panelw)[:panelw] - print('\033[%i;%iH\033[%im%s\033[0m' % (cury, panelx + 1, 1 if panely + cury - 1 == ponyindex else 0, line), end='') + print('\[[%i;%iH\[[%im%s\[[0m' % (cury, panelx + 1, 1 if panely + cury - 1 == ponyindex else 0, line), end='') elif printpanel >= 0: for index in (printpanel, ponyindex): cury = index - panely if (0 <= cury) and (cury < termh): line = ponies[cury + panely] if os.path.islink((ponydir + '/' + line + '.pony').replace('//', '/')): - line = '\033[34m%s\033[39m' % ((line + ' ' * panelw)[:panelw]) + line = '\[[34m%s\[[39m' % ((line + ' ' * panelw)[:panelw]) else: line = (line + ' ' * panelw)[:panelw] - print('\033[%i;%iH\033[%im%s\033[0m' % (cury, panelx + 1, 1 if panely + cury - 1 == ponyindex else 0, line), end='') + print('\[[%i;%iH\[[%im%s\[[0m' % (cury, panelx + 1, 1 if panely + cury - 1 == ponyindex else 0, line), end='') - sys.stdout.buffer.flush() + fileios.stdout.buffer.flush() if stored is None: - d = sys.stdin.read(1) + d = fileio.stdin.read(1) else: d = stored stored = None @@ -409,20 +410,20 @@ class PonysayTool(): elif ord(d) == ord('Q') - ord('@'): break elif ord(d) == ord('X') - ord('@'): - if ord(sys.stdin.read(1)) == ord('C') - ord('@'): + if ord(fileio.stdin.read(1)) == ord('C') - ord('@'): break - elif d == '\033': - d = sys.stdin.read(1) + elif d == '\[': + d = fileio.stdin.read(1) if d == '[': - d = sys.stdin.read(1) + d = fileio.stdin.read(1) if d == 'A': stored = chr(ord('P') - ord('@')) if (not quotes) and (not info) else 'W' elif d == 'B': stored = chr(ord('N') - ord('@')) if (not quotes) and (not info) else 'S' elif d == 'C': stored = chr(ord('N') - ord('@')) if (not quotes) and (not info) else 'D' elif d == 'D': stored = chr(ord('P') - ord('@')) if (not quotes) and (not info) else 'A' elif d == '1': - if sys.stdin.read(1) == ';': - if sys.stdin.read(1) == '5': - d = sys.stdin.read(1) + if fileio.stdin.read(1) == ';': + if fileio.stdin.read(1) == '5': + d = fileio.stdin.read(1) if d == 'A': stored = 'W' elif d == 'B': stored = 'S' elif d == 'C': stored = 'D' @@ -446,7 +447,7 @@ class PonysayTool(): def __getitem__(self, key): return [self.value] if key == self.key else None def __contains__(self, key): - return key == self.key; + return key == self.key class StringInputStream(): def __init__(self): @@ -464,36 +465,36 @@ class PonysayTool(): def isatty(self): return True - stdout = sys.stdout + stdout = fileio.stdout term = os.environ['TERM'] os.environ['TERM'] = 'linux' - sys.stdout = StringInputStream() + fileio.stdout = StringInputStream() ponysay = Ponysay() ponysay.run(PhonyArgParser('--onelist', None)) - stdponies = sys.stdout.buf[:-1].split('\n') + stdponies = fileio.stdout.buf[:-1].split('\n') - sys.stdout = StringInputStream() + fileio.stdout = StringInputStream() ponysay = Ponysay() ponysay.run(PhonyArgParser('++onelist', None)) - extraponies = sys.stdout.buf[:-1].split('\n') + extraponies = fileio.stdout.buf[:-1].split('\n') for pony in stdponies: printerr('Genering standard kmspony: %s' % pony) - sys.stderr.buffer.flush(); - sys.stdout = StringInputStream() + fileio.stderr.buffer.flush() + fileio.stdout = StringInputStream() ponysay = Ponysay() ponysay.run(PhonyArgParser('--pony', pony)) for pony in extraponies: printerr('Genering extra kmspony: %s' % pony) - sys.stderr.buffer.flush(); - sys.stdout = StringInputStream() + fileio.stderr.buffer.flush() + fileio.stdout = StringInputStream() ponysay = Ponysay() ponysay.run(PhonyArgParser('++pony', pony)) os.environ['TERM'] = term - sys.stdout = stdout + fileio.stdout = stdout def generateDimensions(self, ponydir, ponies = None): @@ -523,8 +524,8 @@ class PonysayTool(): return [('none' if self.balloon else None)] return None def __contains__(self, key): - return key in ('-f', '-W', '-b'); - stdout = sys.stdout + return key in ('-f', '-W', '-b') + stdout = fileio.stdout class StringInputStream(): def __init__(self): self.buf = '' @@ -540,7 +541,7 @@ class PonysayTool(): pass def isatty(self): return True - sys.stdout = StringInputStream() + fileio.stdout = StringInputStream() ponysay = Ponysay() ponysay.run(PhonyArgParser(True)) printpony = sys.stdout.buf[:-1].split('\n') @@ -697,7 +698,7 @@ class PonysayTool(): if key == '-W': return ['n'] return None def __contains__(self, key): - return key in ('-f', '-W'); + return key in ('-f', '-W') data = {} @@ -750,7 +751,7 @@ class PonysayTool(): printpony = sys.stdout.buf[:-1].split('\n') sys.stdout = stdout - preprint = '\033[H\033[2J' + preprint = '\[[H\[[2J' if printpony[0].startswith(preprint): printpony[0] = printpony[0][len(preprint):] ponyheight = len(printpony) - len(ponyfile.split('\n')) + 1 - 2 # using fallback balloon @@ -765,8 +766,8 @@ class PonysayTool(): termsize = [int(item) for item in termsize] break - AUTO_PUSH = '\033[01010~' - AUTO_POP = '\033[10101~' + AUTO_PUSH = '\[[01010~' + AUTO_POP = '\[[10101~' modprintpony = '\n'.join(printpony).replace('\n', AUTO_PUSH + '\n' + AUTO_POP) colourstack = ColourStack(AUTO_PUSH, AUTO_POP) buf = '' @@ -774,12 +775,12 @@ class PonysayTool(): buf += c + colourstack.feed(c) modprintpony = buf.replace(AUTO_PUSH, '').replace(AUTO_POP, '') - printpony = [('\033[21;39;49;0m%s%s\033[21;39;49;0m' % (' ' * (termsize[1] - ponywidth), line)) for line in modprintpony.split('\n')] + printpony = [('\[[22;39;49;0m%s%s\[[22;39;49;0m' % (' ' * (termsize[1] - ponywidth), line)) for line in modprintpony.split('\n')] print(preprint, end='') print('\n'.join(printpony), end='') - print('\033[H', end='') + print('\[[H', end='') print('Please see the info manual for details on how to fill out this form') print() @@ -885,17 +886,17 @@ class TextArea(): # TODO support small screens (This is being work on in GNU-Po killptr = None def status(text): - print('\033[%i;%iH\033[7m%s\033[27m\033[%i;%iH' % (termh - 1, 1, ' (' + text + ') ' + '-' * (termw - len(' (' + text + ') ')), self.top + y, innerleft + x), end='') + print('\[[%i;%iH\[[7m%s\[[27m\[[%i;%iH' % (termh - 1, 1, ' (' + text + ') ' + '-' * (termw - len(' (' + text + ') ')), self.top + y, innerleft + x), end='') status('unmodified') - print('\033[%i;%iH' % (self.top, innerleft), end='') + print('\[[%i;%iH' % (self.top, innerleft), end='') def alert(text): if text is None: alert('') else: - print('\033[%i;%iH\033[2K%s\033[%i;%iH' % (termh, 1, text, self.top + y, innerleft + x), end='') + print('\[[%i;%iH\[[2K%s\[[%i;%iH' % (termh, 1, text, self.top + y, innerleft + x), end='') modified = False override = False @@ -904,28 +905,28 @@ class TextArea(): # TODO support small screens (This is being work on in GNU-Po stored = chr(ord('L') - ord('@')) alerted = False edited = False - print('\033[%i;%iH' % (self.top + y, innerleft + x), end='') + print('\[[%i;%iH' % (self.top + y, innerleft + x), end='') while True: if (oldmark is not None) and (oldmark >= 0): if oldmark < oldx: - print('\033[%i;%iH\033[49m%s\033[%i;%iH' % (self.top + oldy, innerleft + oldmark, datalines[oldy][oldmark : oldx], self.top + y, innerleft + x), end='') + print('\[[%i;%iH\[[49m%s\[[%i;%iH' % (self.top + oldy, innerleft + oldmark, datalines[oldy][oldmark : oldx], self.top + y, innerleft + x), end='') elif oldmark > oldx: - print('\033[%i;%iH\033[49m%s\033[%i;%iH' % (self.top + oldy, innerleft + oldx, datalines[oldy][oldx : oldmark], self.top + y, innerleft + x), end='') + print('\[[%i;%iH\[[49m%s\[[%i;%iH' % (self.top + oldy, innerleft + oldx, datalines[oldy][oldx : oldmark], self.top + y, innerleft + x), end='') if (mark is not None) and (mark >= 0): if mark < x: - print('\033[%i;%iH\033[44;37m%s\033[49;39m\033[%i;%iH' % (self.top + y, innerleft + mark, datalines[y][mark : x], self.top + y, innerleft + x), end='') + print('\[[%i;%iH\[[44;37m%s\[[49;39m\[[%i;%iH' % (self.top + y, innerleft + mark, datalines[y][mark : x], self.top + y, innerleft + x), end='') elif mark > x: - print('\033[%i;%iH\033[44;37m%s\033[49;39m\033[%i;%iH' % (self.top + y, innerleft + x, datalines[y][x : mark], self.top + y, innerleft + x), end='') + print('\[[%i;%iH\[[44;37m%s\[[49;39m\[[%i;%iH' % (self.top + y, innerleft + x, datalines[y][x : mark], self.top + y, innerleft + x), end='') if y != oldy: if (oldy > 0) and (leftlines[oldy - 1] == leftlines[oldy]) and (leftlines[oldy] == leftlines[-1]): - print('\033[%i;%iH\033[34m%s\033[39m' % (self.top + oldy, self.left, '>'), end='') + print('\[[%i;%iH\[[34m%s\[[39m' % (self.top + oldy, self.left, '>'), end='') else: - print('\033[%i;%iH\033[34m%s:\033[39m' % (self.top + oldy, self.left, leftlines[oldy]), end='') + print('\[[%i;%iH\[[34m%s:\[[39m' % (self.top + oldy, self.left, leftlines[oldy]), end='') if (y > 0) and (leftlines[y - 1] == leftlines[y]) and (leftlines[y] == leftlines[-1]): - print('\033[%i;%iH\033[1;34m%s\033[21;39m' % (self.top + y, self.left, '>'), end='') + print('\[[%i;%iH\[[1;34m%s\[[22;39m' % (self.top + y, self.left, '>'), end='') else: - print('\033[%i;%iH\033[1;34m%s:\033[21;39m' % (self.top + y, self.left, leftlines[y]), end='') - print('\033[%i;%iH' % (self.top + y, innerleft + x), end='') + print('\[[%i;%iH\[[1;34m%s:\[[22;39m' % (self.top + y, self.left, leftlines[y]), end='') + print('\[[%i;%iH' % (self.top + y, innerleft + x), end='') (oldy, oldx, oldmark) = (y, x, mark) if edited: edited = False @@ -980,10 +981,10 @@ class TextArea(): # TODO support small screens (This is being work on in GNU-Po mark = None killptr = len(killring) - 1 yanked = killring[killptr] - print('\033[%i;%iH%s' % (self.top + y, innerleft + x, yanked + datalines[y][x:]), end='') + print('\[[%i;%iH%s' % (self.top + y, innerleft + x, yanked + datalines[y][x:]), end='') datalines[y] = datalines[y][:x] + yanked + datalines[y][x:] x += len(yanked) - print('\033[%i;%iH' % (self.top + y, innerleft + x), end='') + print('\[[%i;%iH' % (self.top + y, innerleft + x), end='') elif ord(d) == ord('X') - ord('@'): alert('C-x') alerted = True @@ -1034,7 +1035,7 @@ class TextArea(): # TODO support small screens (This is being work on in GNU-Po datalines[y] = dataline = dataline[:x - removed] + dataline[x:] x -= removed mark = None - print('\033[%i;%iH%s%s\033[%i;%iH' % (self.top + y, innerleft, dataline, ' ' * removed, self.top + y, innerleft + x), end='') + print('\[[%i;%iH%s%s\[[%i;%iH' % (self.top + y, innerleft, dataline, ' ' * removed, self.top + y, innerleft + x), end='') edited = True elif ord(d) < ord(' '): if ord(d) == ord('P') - ord('@'): @@ -1055,14 +1056,14 @@ class TextArea(): # TODO support small screens (This is being work on in GNU-Po elif ord(d) == ord('F') - ord('@'): if x < len(datalines[y]): x += 1 - print('\033[C', end='') + print('\[[C', end='') else: alert('At end') alerted = True elif ord(d) == ord('B') - ord('@'): if x > 0: x -= 1 - print('\033[D', end='') + print('\[[D', end='') else: alert('At beginning') alerted = True @@ -1074,17 +1075,17 @@ class TextArea(): # TODO support small screens (This is being work on in GNU-Po x = 0 stored = chr(ord('L') - ord('@')) elif ord(d) == ord('L') - ord('@'): - empty = '\033[0m' + (' ' * self.width + '\n') * len(datalines) - print('\033[%i;%iH%s' % (self.top, self.left, empty), end='') + empty = '\[[0m' + (' ' * self.width + '\n') * len(datalines) + print('\[[%i;%iH%s' % (self.top, self.left, empty), end='') for row in range(0, len(leftlines)): leftline = leftlines[row] + ':' if (leftlines[row - 1] == leftlines[row]) and (leftlines[row] == leftlines[-1]): leftline = '>' - print('\033[%i;%iH\033[%s34m%s\033[%s39m' % (self.top + row, self.left, '1;' if row == y else '', leftline, '21;' if row == y else ''), end='') + print('\[[%i;%iH\[[%s34m%s\[[%s39m' % (self.top + row, self.left, '1;' if row == y else '', leftline, '22;' if row == y else ''), end='') for row in range(0, len(datalines)): - print('\033[%i;%iH%s\033[49m' % (self.top + row, innerleft, datalines[row]), end='') - print('\033[%i;%iH' % (self.top + y, innerleft + x), end='') - elif d == '\033': + print('\[[%i;%iH%s\[[49m' % (self.top + row, innerleft, datalines[row]), end='') + print('\[[%i;%iH' % (self.top + y, innerleft + x), end='') + elif d == '\[': d = sys.stdin.read(1) if d == '[': d = sys.stdin.read(1) @@ -1119,7 +1120,7 @@ class TextArea(): # TODO support small screens (This is being work on in GNU-Po alerted = True continue datalines[y] = dataline = dataline[:x] + dataline[x + removed:] - print('\033[%i;%iH%s%s\033[%i;%iH' % (self.top + y, innerleft, dataline, ' ' * removed, self.top + y, innerleft + x), end='') + print('\[[%i;%iH%s%s\[[%i;%iH' % (self.top + y, innerleft, dataline, ' ' * removed, self.top + y, innerleft + x), end='') mark = None edited = True else: @@ -1150,18 +1151,18 @@ class TextArea(): # TODO support small screens (This is being work on in GNU-Po additional = len(killring[killptr]) - len(yanked) x += additional datalines[y] = dataline - print('\033[%i;%iH%s%s\033[%i;%iH' % (self.top + y, innerleft, dataline, ' ' * max(0, -additional), self.top + y, innerleft + x), end='') + print('\[[%i;%iH%s%s\[[%i;%iH' % (self.top + y, innerleft, dataline, ' ' * max(0, -additional), self.top + y, innerleft + x), end='') else: stored = chr(ord('Y') - ord('@')) else: stored = chr(ord('Y') - ord('@')) elif d == 'O': - d = sys.stdin.read(1) + d = fileio.stdin.read(1) if d == 'H': x = 0 elif d == 'F': x = len(datalines[y]) - print('\033[%i;%iH' % (self.top + y, innerleft + x), end='') + print('\[[%i;%iH' % (self.top + y, innerleft + x), end='') elif d == '\n': stored = chr(ord('N') - ord('@')) else: @@ -1172,7 +1173,7 @@ class TextArea(): # TODO support small screens (This is being work on in GNU-Po if (not override) or (x == len(dataline)): print(insert + dataline[x:], end='') if len(dataline) - x > 0: - print('\033[%iD' % (len(dataline) - x), end='') + print('\[[%iD' % (len(dataline) - x), end='') datalines[y] = dataline[:x] + insert + dataline[x:] if (mark is not None) and (mark >= 0): if mark >= x: @@ -1185,46 +1186,46 @@ class TextArea(): # TODO support small screens (This is being work on in GNU-Po -HOME = os.environ['HOME'] if 'HOME' in os.environ else os.path.expanduser('~') +let HOME = os.environ['HOME'] if 'HOME' in os.environ else os.path.expanduser('~') ''' The user's home directory ''' -pipelinein = not sys.stdin.isatty() +let pipelinein = not os.isatty(0) ''' Whether stdin is piped ''' -pipelineout = not sys.stdout.isatty() +let pipelineout = not os.isatty(1) ''' Whether stdout is piped ''' -pipelineerr = not sys.stderr.isatty() +let pipelineerr = not os.isatty(2) ''' Whether stderr is piped ''' -usage_program = '\033[34;1mponysay-tool\033[21;39m' +let usage_program = '\[[34;1mponysay-tool\[[22;39m' -usage = '\n'.join(['%s %s' % (usage_program, '(--help | --version | --kms)'), - '%s %s' % (usage_program, '(--edit | --edit-rm) \033[33mPONY-FILE\033[39m'), - '%s %s' % (usage_program, '--edit-stash \033[33mPONY-FILE\033[39m > \033[33mSTASH-FILE\033[39m'), - '%s %s' % (usage_program, '--edit-apply \033[33mPONY-FILE\033[39m < \033[33mSTASH-FILE\033[39m'), - '%s %s' % (usage_program, '(--dimensions | --metadata) \033[33mPONY-DIR\033[39m'), - '%s %s' % (usage_program, '--browse \033[33mPONY-DIR\033[39m [-r \033[33mRESTRICTION\033[39m]*'), +let usage = '\n'.join([' '.join((usage_program, '(--help | --version | --kms)')), + ' '.join((usage_program, '(--edit | --edit-rm) \[[33mPONY-FILE\[[39m')), + ' '.join((usage_program, '--edit-stash \[[33mPONY-FILE\[[39m > \[[33mSTASH-FILE\[[39m')), + ' '.join((usage_program, '--edit-apply \[[33mPONY-FILE\[[39m < \[[33mSTASH-FILE\[[39m')), + ' '.join((usage_program, '(--dimensions | --metadata) \[[33mPONY-DIR\[[39m')), + ' '.join((usage_program, '--browse \[[33mPONY-DIR\[[39m [-r \[[33mRESTRICTION\[[39m]*')), ]) -usage = usage.replace('\033[', '\0') +usage = usage.replace('\[[', 'あ') for sym in ('[', ']', '(', ')', '|', '...', '*'): - usage = usage.replace(sym, '\033[2m' + sym + '\033[22m') -usage = usage.replace('\0', '\033[') + usage = usage.replace(sym, '\[[2m' + sym + '\[[22m') +usage = usage.replace('あ', '\[[') ''' Argument parsing ''' -opts = ArgParser(program = 'ponysay-tool', +let opts = ArgParser(program = 'ponysay-tool', description = 'Tool chest for ponysay', usage = usage, longdescription = None) @@ -1244,7 +1245,7 @@ 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-stash'], arg = 'PONY-FILE', help = 'Print applyable metadata from a pony file') -unrecognised = not opts.parse() +let unrecognised = not opts.parse() ''' Whether at least one unrecognised option was used ''' diff --git a/src/spellocorrecter.py b/ponysay/spellocorrecter.krk similarity index 92% rename from src/spellocorrecter.py rename to ponysay/spellocorrecter.krk index 167097e3..d10bfdf5 100644 --- a/src/spellocorrecter.py +++ b/ponysay/spellocorrecter.krk @@ -29,8 +29,7 @@ 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 ponysay.common import printerr, printinfo, gettermsize, endswith class SpelloCorrecter(): # Naïvely and quickly ported and adapted from optimised Java, may not be the nicest, or even fast, Python code @@ -74,18 +73,18 @@ class SpelloCorrecter(): # Naïvely and quickly ported and adapted from optimise for y in range(0, 128): self.M[y] = [0] * 128 self.M[y][0] = y - m0 = self.M[0] - x = 127 + let m0 = self.M[0] + let x = 127 while x > -1: m0[x] = x x -= 1 - previous = '' - self.dictionary[-1] = previous; + let previous = '' + self.dictionary[-1] = previous if ending is not None: for directory in directories: - files = os.listdir(directory) + let files = os.listdir(directory) files.sort() for filename in files: if (not endswith(filename, ending)) or (len(filename) - len(ending) > 127): @@ -108,7 +107,7 @@ class SpelloCorrecter(): # Naïvely and quickly ported and adapted from optimise previous = proper self.reusable[self.dictionaryEnd] = prevCommon else: - files = directories + let files = directories files.sort() for proper in files: if len(proper) > 127: @@ -167,20 +166,20 @@ class SpelloCorrecter(): # Naïvely and quickly ported and adapted from optimise @param used:str The word to correct, it must satisfy all restrictions ''' self.closestDistance = 0x7FFFFFFF - previous = self.dictionary[-1] - prevLen = 0 - usedLen = len(used) + let previous = self.dictionary[-1] + let prevLen = 0 + let usedLen = len(used) - proper = None - prevCommon = 0 + let proper = None + let prevCommon = 0 - d = len(self.dictionary) - 1 + let d = len(self.dictionary) - 1 while d > self.dictionaryEnd: d -= 1 proper = self.dictionary[d] if abs(len(proper) - usedLen) <= self.closestDistance: if previous == self.dictionary[d + 1]: - prevCommon = self.reusable[d]; + prevCommon = self.reusable[d] else: prevCommon = min(prevLen, len(proper)) for i in range(0, prevCommon): @@ -188,8 +187,8 @@ class SpelloCorrecter(): # Naïvely and quickly ported and adapted from optimise prevCommon = i break - skip = min(prevLen, len(proper)) - i = prevCommon + let skip = min(prevLen, len(proper)) + let i = prevCommon while i < skip: for u in range(0, usedLen): if (used[u] == previous[i]) or (used[u] == proper[i]): @@ -197,13 +196,13 @@ class SpelloCorrecter(): # Naïvely and quickly ported and adapted from optimise break i += 1 - common = min(skip, min(usedLen, len(proper))) + let common = min(skip, min(usedLen, len(proper))) for i in range(0, common): if used[i] != proper[i]: common = i break - distance = self.__distance(proper, skip, len(proper), used, common, usedLen) + let distance = self.__distance(proper, skip, len(proper), used, common, usedLen) if self.closestDistance > distance: self.closestDistance = distance @@ -211,7 +210,7 @@ class SpelloCorrecter(): # Naïvely and quickly ported and adapted from optimise elif self.closestDistance == distance: self.corrections.append(proper) - previous = proper; + previous = proper if distance >= 0x7FFFFF00: prevLen = distance & 255 else: diff --git a/src/ucs.py b/ponysay/ucs.krk similarity index 95% rename from src/ucs.py rename to ponysay/ucs.krk index 64941f4b..44aa3f54 100644 --- a/src/ucs.py +++ b/ponysay/ucs.krk @@ -29,7 +29,7 @@ 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 ponysay.common import printerr, printinfo, gettermsize, endswith @@ -46,7 +46,7 @@ class UCS(): @param char:chr The character to test @return :bool Whether the character is a combining character ''' - o = ord(char) + let o = ord(char) if (0x0300 <= o) and (o <= 0x036F): return True if (0x20D0 <= o) and (o <= 0x20FF): return True if (0x1DC0 <= o) and (o <= 0x1DFF): return True @@ -62,7 +62,7 @@ class UCS(): @param string:str A text to count combining characters in @return :int The number of combining characters in the string ''' - rc = 0 + let rc = 0 for char in string: if UCS.isCombining(char): rc += 1