def format(self, s): self.code_blocks = [] # first, temporarily remove any code blocks, # as we don't want them formatted s = self.FENCED_RE.sub(self._remove_code_block, s) s = self.CODE_RE.sub(self._remove_code_inline, s) s = self.INDENTED_RE.sub(self._remove_code_indented, s) # first find bold, and then italic, then the rest s = self.BOLD_RE.sub('\x02\x01\\g<text>\x03', s) s = self.ITALICS_RE.sub('\x02\x04\\g<text>\x03', s) s = self.HIGHLIGHT_RE.sub('\x02\x05\\g<text>\x03', s) s = self.UNDERLINE_RE.sub('\x02\x06\\g<text>\x03', s) s = self.STRIKETHROUGH_RE.sub('\x02\x07\\g<text>\x03', s) # Find and format headers s = self.HEADER_RE1.sub(ansi.with_codes(r'\g<start> \g<name> \g<end>', 1), s) s = self.HEADER_RE2.sub(ansi.with_codes('\\g<text>\n\\g<underline>', 1), s) # now return everything to normal, with the ANSI encoding s = self.AFTER_RE.sub(self._add_ansi_formatting, s) return s
def _add_ansi_formatting(self, match): sub_code = match.group('code') multiline = False prefix = None if sub_code in ('\x1C', '\x1E'): # deal with the special code blocks thing block_num = int(match.group('text')) inner_text = self.code_blocks[block_num] if sub_code == '\x1E': multiline = True prefix = '' elif sub_code == '\x1D': block_num = int(match.group('text')) prefix, inner_text = self.code_blocks[block_num] multiline = True else: inner_text = match.group('text') if multiline: prefix_codes, codes = self.FORMAT_CODES[sub_code] if isinstance(prefix_codes, int): prefix_codes = [prefix_codes] else: codes = self.FORMAT_CODES[sub_code] if isinstance(codes, int): codes = [codes] if multiline: chars, line_chars = self.FORMAT_CHARS[sub_code] else: chars = self.FORMAT_CHARS[sub_code] text = chars + inner_text + chars if multiline: raw_lines = text.splitlines() max_len = max(len(line) for line in raw_lines) res_lines = [("{1}{0: <%s}{1}" % max_len).format(line, line_chars) for line in raw_lines] res = '\n'.join(ansi.with_codes(line, *codes) for line in res_lines) else: res = ansi.with_codes(text, *codes) if multiline and prefix is not None: prefix_raw = ('{1}{0: <%s}{1}' % max_len).format(prefix, line_chars) res = '%s\n%s' % (ansi.with_codes(prefix_raw, *prefix_codes), res) return res
def _process_code_line(self, line, res, more): if self._readline is not None: self._readline.add_history(line) if more: self.write(sys.ps2) else: self.write(sys.ps1) if self.use_ansi: self.write(ansi.with_codes(line, 38, 5, 0xdf)) else: self.write(line) self.write("\n") with self._capture_output() as output: more = self.push(line) res += output.getvalue() output.truncate(0) exc = self.exc_msg self.exc_msg = None return (res, exc, more)
def interact(self, lit_string, name, pause=True, interactive=True): self.name = name self.pause = pause self.interactive = interactive try: sys.ps1 except AttributeError: sys.ps1 = ">>> " try: sys.ps2 except AttributeError: sys.ps2 = "... " try: sys.ps3 except AttributeError: sys.ps3 = '>>> ' if self._env_driver is not None: extra_locals = self._env_driver.setup() self.locals.update(extra_locals) extra_banner = self._env_driver.banner driver_text = " ({0})".format(self._env_driver.DRIVER_NAME) else: extra_banner = "" driver_text = "" cprt = ('Type "help", "copyright", "credits" or "license" for ' 'more information about Python.') self.write("Literate Python Shell{driver_text}\nPython {ver} " "on {platform}\n{cprt}\n" "{extra_banner}\n\n".format(driver_text=driver_text, ver=sys.version, platform=sys.platform, cprt=cprt, extra_banner=extra_banner)) if not interactive and pause: self.write('Press enter to continue after a code block\n\n') try: parser = self.code_parser start = True self.chunks = list(parser.parse(lit_string, name)) for chunk_ind, chunk in enumerate(self.chunks): if isinstance(chunk, parsers.CodeChunk): self._run_code(chunk, chunk_ind) elif not chunk: continue else: if not start and pause and interactive: self.filename = "<stdin>" more = False blanks = 0 while blanks < 2: blank, more = self._interact_once(more) if blank: blanks += 1 else: blanks = 0 if more is None: return # reset exc_msg so it doesn't get # raised after the next code block self.exc_msg = None elif not start and pause: self.no_echo_input(sys.ps3) self.write(self.text_formatter.format(chunk)) start = False complete_msg = ("\n{file} complete! Continuing to interactive " "console...\n\n".format(file=self.name)) if self.use_ansi: self.write(ansi.with_codes(complete_msg, 1)) else: self.write(complete_msg) self.filename = "<stdin>" self.locals['con'] = self more = False while more is not None: blank, more = self._interact_once(more) finally: if self._env_driver is not None: self._env_driver.teardown()