def editText(self, text, jumpIndex=None, highlight=None): """Return the text as edited by the user. Uses a Tkinter edit box because we don't have a console editor Parameters: * text - a Unicode string * jumpIndex - an integer: position at which to put the caret * highlight - a substring; each occurrence will be highlighted """ try: import gui except ImportError as e: print('Could not load GUI modules: %s' % e) return text editor = gui.EditBoxWindow() return editor.edit(text, jumpIndex=jumpIndex, highlight=highlight)
def editText(self, text, jumpIndex=None, highlight=None): """Return the text as edited by the user. Uses a Tkinter edit box because we don't have a console editor @param text: the text to be edited @type text: unicode @param jumpIndex: position at which to put the caret @type jumpIndex: int @param highlight: each occurrence of this substring will be highlighted @type highlight: unicode @return: the modified text, or None if the user didn't save the text file in his text editor @rtype: unicode or None """ try: import gui except ImportError as e: print('Could not load GUI modules: %s' % e) return text editor = gui.EditBoxWindow() return editor.edit(text, jumpIndex=jumpIndex, highlight=highlight)
class UI: def __init__(self): pass def printColorizedInUnix(self, text, targetStream): lastColor = None for key, value in unixColors.iteritems(): text = text.replace('\03{%s}' % key, value) # just to be sure, reset the color text += unixColors['default'] targetStream.write(text.encode(config.console_encoding, 'replace')) def printColorizedInWindows(self, text, targetStream): """ This only works in Python 2.5 or higher. """ if ctypes_found: std_out_handle = ctypes.windll.kernel32.GetStdHandle(-11) # Color tags might be cascaded, e.g. because of transliteration. # Therefore we need this stack. colorStack = [] tagM = True while tagM: tagM = colorTagR.search(text) if tagM: # print the text up to the tag. targetStream.write(text[:tagM.start()].encode( config.console_encoding, 'replace')) newColor = tagM.group('name') if newColor == 'default': if len(colorStack) > 0: colorStack.pop() if len(colorStack) > 0: lastColor = colorStack[-1] else: lastColor = 'default' ctypes.windll.kernel32.SetConsoleTextAttribute( std_out_handle, windowsColors[lastColor]) else: colorStack.append(newColor) # set the new color ctypes.windll.kernel32.SetConsoleTextAttribute( std_out_handle, windowsColors[newColor]) text = text[tagM.end():] # print the rest of the text targetStream.write(text.encode(config.console_encoding, 'replace')) # just to be sure, reset the color ctypes.windll.kernel32.SetConsoleTextAttribute( std_out_handle, windowsColors['default']) else: # ctypes is only available since Python 2.5, and we won't # try to colorize without it. Instead we add *** after the text as a whole # if anything needed to be colorized. lines = text.split('\n') for line in lines: line, count = colorTagR.subn('', line) if count > 0: line += '***' line += '\n' targetStream.write( line.encode(config.console_encoding, 'replace')) def printColorized(self, text, targetStream): if config.colorized_output: if sys.platform == 'win32': self.printColorizedInWindows(text, targetStream) else: self.printColorizedInUnix(text, targetStream) else: targetStream.write(text.encode(config.console_encoding, 'replace')) def output(self, text, toStdout=False): """ If a character can't be displayed in the encoding used by the user's terminal, it will be replaced with a question mark or by a transliteration. """ if config.transliterate: # Encode our unicode string in the encoding used by the user's console, # and decode it back to unicode. Then we can see which characters # can't be represented in the console encoding. codecedText = text.encode(config.console_encoding, 'replace').decode( config.console_encoding) transliteratedText = '' # Note: A transliteration replacement might be longer than the original # character, e.g. ч is transliterated to ch. prev = "-" for i in xrange(len(codecedText)): # work on characters that couldn't be encoded, but not on # original question marks. if codecedText[i] == '?' and text[i] != u'?': try: transliterated = transliterator.transliterate( text[i], default='?', prev=prev, next=text[i + 1]) except IndexError: transliterated = transliterator.transliterate( text[i], default='?', prev=prev, next=' ') # transliteration was successful. The replacement # could consist of multiple letters. # mark the transliterated letters in yellow. transliteratedText += '\03{lightyellow}%s\03{default}' % transliterated transLength = len(transliterated) # memorize if we replaced a single letter by multiple letters. if len(transliterated) > 0: prev = transliterated[-1] else: # no need to try to transliterate. transliteratedText += codecedText[i] prev = codecedText[i] text = transliteratedText if toStdout: targetStream = sys.stdout else: targetStream = sys.stderr self.printColorized(text, targetStream) def input(self, question, password=False): """ Works like raw_input(), but returns a unicode string instead of ASCII. Unlike raw_input, this function automatically adds a space after the question. """ # sound the terminal bell to notify the user if config.ring_bell: sys.stdout.write('\07') # TODO: make sure this is logged as well self.output(question + ' ') if password: import getpass text = getpass.getpass('') else: text = raw_input() text = unicode(text, config.console_encoding) return text def inputChoice(self, question, options, hotkeys, default=None): options = options[:] # we don't want to edit the passed parameter for i in range(len(options)): option = options[i] hotkey = hotkeys[i] # try to mark a part of the option name as the hotkey m = re.search('[%s%s]' % (hotkey.lower(), hotkey.upper()), option) if hotkey == default: caseHotkey = hotkey.upper() else: caseHotkey = hotkey if m: pos = m.start() options[i] = '%s[%s]%s' % (option[:pos], caseHotkey, option[pos + 1:]) else: options[i] = '%s [%s]' % (option, caseHotkey) # loop until the user entered a valid choice while True: prompt = '%s (%s)' % (question, ', '.join(options)) answer = self.input(prompt) if answer.lower() in hotkeys or answer.upper() in hotkeys: return answer elif default and answer == '': # empty string entered return default def editText(self, text, jumpIndex=None, highlight=None): """ Uses a Tkinter edit box because we don't have a console editor Parameters: * text - a Unicode string * jumpIndex - an integer: position at which to put the caret * highlight - a substring; each occurence will be highlighted """ try: import gui except ImportError, e: print 'Could not load GUI modules: %s' % e return text editor = gui.EditBoxWindow() return editor.edit(text, jumpIndex=jumpIndex, highlight=highlight)
class UI: def __init__(self): self.stdin = sys.stdin self.stdout = sys.stdout self.stderr = sys.stderr self.encoding = config.console_encoding self.transliteration_target = config.transliteration_target self.stderr = sys.stderr self.stdout = sys.stdout def init_handlers(self, root_logger, default_stream='stderr'): """Initialize the handlers for user output. This method initializes handler(s) for output levels VERBOSE (if enabled by config.verbose_output), INFO, STDOUT, WARNING, ERROR, and CRITICAL. STDOUT writes its output to sys.stdout; all the others write theirs to sys.stderr. """ if default_stream == 'stdout': default_stream = self.stdout elif default_stream == 'stderr': default_stream = self.stderr # default handler for display to terminal default_handler = TerminalHandler(self, strm=default_stream) if config.verbose_output: default_handler.setLevel(VERBOSE) else: default_handler.setLevel(INFO) # this handler ignores levels above INPUT default_handler.addFilter(MaxLevelFilter(INPUT)) default_handler.setFormatter( TerminalFormatter(fmt="%(message)s%(newline)s")) root_logger.addHandler(default_handler) # handler for level STDOUT output_handler = TerminalHandler(self, strm=self.stdout) output_handler.setLevel(STDOUT) output_handler.addFilter(MaxLevelFilter(STDOUT)) output_handler.setFormatter( TerminalFormatter(fmt="%(message)s%(newline)s")) root_logger.addHandler(output_handler) # handler for levels WARNING and higher warning_handler = TerminalHandler(self, strm=self.stderr) warning_handler.setLevel(logging.WARNING) warning_handler.setFormatter( TerminalFormatter(fmt="%(levelname)s: %(message)s%(newline)s")) root_logger.addHandler(warning_handler) def printNonColorized(self, text, targetStream): # We add *** after the text as a whole if anything needed to be colorized. lines = text.split('\n') for i, line in enumerate(lines): if i > 0: line = "\n" + line line, count = colorTagR.subn('', line) if count > 0: line += ' ***' targetStream.write(line.encode(self.encoding, 'replace')) printColorized = printNonColorized def _print(self, text, targetStream): if config.colorized_output: self.printColorized(text, targetStream) else: self.printNonColorized(text, targetStream) def output(self, text, toStdout=False, targetStream=None): """ If a character can't be displayed in the encoding used by the user's terminal, it will be replaced with a question mark or by a transliteration. """ if config.transliterate: # Encode our unicode string in the encoding used by the user's # console, and decode it back to unicode. Then we can see which # characters can't be represented in the console encoding. # We need to take min(console_encoding, transliteration_target) # the first is what the terminal is capable of # the second is how unicode-y the user would like the output codecedText = text.encode(self.encoding, 'replace').decode(self.encoding) if self.transliteration_target: codecedText = codecedText.encode( self.transliteration_target, 'replace').decode(self.transliteration_target) transliteratedText = '' # Note: A transliteration replacement might be longer than the # original character, e.g. ч is transliterated to ch. prev = "-" for i in xrange(len(codecedText)): # work on characters that couldn't be encoded, but not on # original question marks. if codecedText[i] == '?' and text[i] != u'?': try: transliterated = transliterator.transliterate( text[i], default='?', prev=prev, next=text[i + 1]) except IndexError: transliterated = transliterator.transliterate( text[i], default='?', prev=prev, next=' ') # transliteration was successful. The replacement # could consist of multiple letters. # mark the transliterated letters in yellow. transliteratedText += '\03{lightyellow}%s\03{default}' \ % transliterated transLength = len(transliterated) # memorize if we replaced a single letter by multiple # letters. if len(transliterated) > 0: prev = transliterated[-1] else: # no need to try to transliterate. transliteratedText += codecedText[i] prev = codecedText[i] text = transliteratedText if not targetStream: if toStdout: targetStream = self.stdout else: targetStream = self.stderr self._print(text, targetStream) def _raw_input(self): return raw_input() def input(self, question, password=False): """ Ask the user a question and return the answer. Works like raw_input(), but returns a unicode string instead of ASCII. Unlike raw_input, this function automatically adds a space after the question. """ # sound the terminal bell to notify the user if config.ring_bell: sys.stdout.write('\07') # TODO: make sure this is logged as well self.output(question + ' ') if password: import getpass text = getpass.getpass('') else: text = self._raw_input() text = unicode(text, self.encoding) return text def inputChoice(self, question, options, hotkeys, default=None): """ Ask the user a question with a predefined list of acceptable answers. """ options = options[:] # we don't want to edit the passed parameter for i in range(len(options)): option = options[i] hotkey = hotkeys[i] # try to mark a part of the option name as the hotkey m = re.search('[%s%s]' % (hotkey.lower(), hotkey.upper()), option) if hotkey == default: caseHotkey = hotkey.upper() else: caseHotkey = hotkey if m: pos = m.start() options[i] = '%s[%s]%s' % (option[:pos], caseHotkey, option[pos + 1:]) else: options[i] = '%s [%s]' % (option, caseHotkey) # loop until the user entered a valid choice while True: prompt = '%s (%s)' % (question, ', '.join(options)) answer = self.input(prompt) if answer.lower() in hotkeys or answer.upper() in hotkeys: return answer elif default and answer == '': # empty string entered return default def editText(self, text, jumpIndex=None, highlight=None): """Return the text as edited by the user. Uses a Tkinter edit box because we don't have a console editor Parameters: * text - a Unicode string * jumpIndex - an integer: position at which to put the caret * highlight - a substring; each occurence will be highlighted """ try: import gui except ImportError, e: print 'Could not load GUI modules: %s' % e return text editor = gui.EditBoxWindow() return editor.edit(text, jumpIndex=jumpIndex, highlight=highlight)
class UI: def __init__(self): self.stdin = sys.stdin self.stdout = sys.stdout self.stderr = sys.stderr self.encoding = config.console_encoding self.transliteration_target = config.transliteration_target def printNonColorized(self, text, targetStream): # We add *** after the text as a whole if anything needed to be colorized. lines = text.split('\n') for line in lines: line, count = colorTagR.subn('', line) if count > 0: line += '***' line += '\n' targetStream.write(line.encode(self.encoding, 'replace')) printColorized = printNonColorized def _print(self, text, targetStream): if config.colorized_output: self.printColorized(text, targetStream) else: self.printNonColorized(text, targetStream) def output(self, text, toStdout=False): """ If a character can't be displayed in the encoding used by the user's terminal, it will be replaced with a question mark or by a transliteration. """ if config.transliterate: # Encode our unicode string in the encoding used by the user's console, # and decode it back to unicode. Then we can see which characters # can't be represented in the console encoding. # We need to take min(console_encoding, transliteration_target) # the first is what the terminal is capable of # the second is how unicode-y the user would like the output codecedText = text.encode(self.encoding, 'replace').decode(self.encoding) if self.transliteration_target: codecedText = codecedText.encode( self.transliteration_target, 'replace').decode(self.transliteration_target) transliteratedText = '' # Note: A transliteration replacement might be longer than the original # character, e.g. ч is transliterated to ch. prev = "-" for i in xrange(len(codecedText)): # work on characters that couldn't be encoded, but not on # original question marks. if codecedText[i] == '?' and text[i] != u'?': try: transliterated = transliterator.transliterate( text[i], default='?', prev=prev, next=text[i + 1]) except IndexError: transliterated = transliterator.transliterate( text[i], default='?', prev=prev, next=' ') # transliteration was successful. The replacement # could consist of multiple letters. # mark the transliterated letters in yellow. transliteratedText += '\03{lightyellow}%s\03{default}' % transliterated transLength = len(transliterated) # memorize if we replaced a single letter by multiple letters. if len(transliterated) > 0: prev = transliterated[-1] else: # no need to try to transliterate. transliteratedText += codecedText[i] prev = codecedText[i] text = transliteratedText if toStdout: targetStream = self.stdout else: targetStream = self.stderr self._print(text, targetStream) def _raw_input(self): return raw_input() def input(self, question, password=False): """ Works like raw_input(), but returns a unicode string instead of ASCII. Unlike raw_input, this function automatically adds a space after the question. """ # sound the terminal bell to notify the user if config.ring_bell: sys.stdout.write('\07') # TODO: make sure this is logged as well self.output(question + ' ') if password: import getpass text = getpass.getpass('') else: text = self._raw_input() text = unicode(text, self.encoding) return text def inputChoice(self, question, options, hotkeys, default=None): options = options[:] # we don't want to edit the passed parameter for i in range(len(options)): option = options[i] hotkey = hotkeys[i] # try to mark a part of the option name as the hotkey m = re.search('[%s%s]' % (hotkey.lower(), hotkey.upper()), option) if hotkey == default: caseHotkey = hotkey.upper() else: caseHotkey = hotkey if m: pos = m.start() options[i] = '%s[%s]%s' % (option[:pos], caseHotkey, option[pos + 1:]) else: options[i] = '%s [%s]' % (option, caseHotkey) # loop until the user entered a valid choice while True: prompt = '%s (%s)' % (question, ', '.join(options)) answer = self.input(prompt) if answer.lower() in hotkeys or answer.upper() in hotkeys: return answer elif default and answer == '': # empty string entered return default def editText(self, text, jumpIndex=None, highlight=None): """ Uses a Tkinter edit box because we don't have a console editor Parameters: * text - a Unicode string * jumpIndex - an integer: position at which to put the caret * highlight - a substring; each occurence will be highlighted """ try: import gui except ImportError, e: print 'Could not load GUI modules: %s' % e return text editor = gui.EditBoxWindow() return editor.edit(text, jumpIndex=jumpIndex, highlight=highlight)