def render_step(self): line = deepcopy(self.code_box.listing.lines[self.position - 1]) self.undo_line = line token = line.parts[-1][0] if self._inside_string(line): # inside a multi-line string, don't reparse, just append parts = deepcopy(line.parts) parts[-1] = CodePart(token, parts[-1].text + self.source) replace_line = CodeLine(parts, line.lexer) else: # not inside a string if token_is_a(token, String): # last token is a string, parse the source and append source_line = parse_source(self.source, line.lexer)[0] new_parts = line.parts + source_line.parts replace_line = CodeLine(new_parts, line.lexer) else: # last token isn't a string, reparse the whole line text = line.text + self.source replace_line = parse_source(text, line.lexer)[0] if self.cursor: replace_line.parts.append(CodePart(Token, '\u2588')) self.code_box.listing.replace_line(self.position, replace_line)
def render_step(self): import subprocess args = self.cmd.strip().split(' ') # subprocess 3.7 command is easier to understand, replace code with # whats in comment when py3.6 support is dropped # #result = subprocess.run(args, capture_output=True, text=True) result = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) lexer = PurdyLexer.factory_from_name('con') new_lines = [] for row in result.stdout.split('\n'): part = CodePart(Token.Generic.Output, row) new_lines.append(CodeLine([ part, ], lexer)) self.undo_position = len(self.code_box.listing.lines) + 1 self.undo_size = len(new_lines) self.code_box.listing.insert_lines(0, new_lines)
def test_misc(self): blank = BlankCodeLine() self.assertEqual('', blank.render_line(None)) lexer = PurdyLexer.factory_from_name('py3') line = CodeLine([ CodePart(Token.Text, 'foo'), ], lexer, line_number=10) expected = 'CodeLine(" 10 foo")' self.assertEqual(expected, line.__repr__())
def _line_to_steps(self, line, insert_pos, replace_pos): steps = [] # --- Skip animation for "output" content first_token = line.parts[0].token is_console = self.code.lexer.is_console if is_console and not token_is_a(first_token, Generic.Prompt): # in console mode only lines with prompts get typewriter # animation, everything else is just added directly return [ steplib.InsertRows(self.code_box, insert_pos, line), ] # --- Typewriter animation # insert a blank row first with contents of line changing what is on # it as animation continues dummy_parts = [ CodePart(Token, ''), ] row_line = CodeLine(dummy_parts, self.code.lexer) step = steplib.InsertRows(self.code_box, insert_pos, row_line) steps.append(step) current_parts = [] num_parts = len(line.parts) for count, part in enumerate(line.parts): if part.token in self.continuous: # part is a chunk that gets output all together, replace the # dummy line with the whole contents current_parts.append(part) row_line = CodeLine(deepcopy(current_parts), self.code.lexer) step = steplib.ReplaceRows(self.code_box, replace_pos, row_line) steps.append(step) if part.token == Generic.Prompt: # stop animation if this is a prompt, wait for keypress steps.append(steplib.CellEnd()) elif count == 0 and token_is_a( part.token, Token.Text) and (part.text.rstrip() == ''): # first token is leading whitespace, don't animate it, just # insert it current_parts.append(part) row_line = CodeLine(deepcopy(current_parts), self.code.lexer) step = steplib.ReplaceRows(self.code_box, replace_pos, row_line) steps.append(step) else: new_part = CodePart(part.token, '') current_parts.append(new_part) typewriter = '' for letter in part.text: typewriter += letter new_part = CodePart(part.token, typewriter) current_parts[-1] = new_part output_parts = deepcopy(current_parts) # If not last step in animation, add a cursor to the line is_last_part = (count + 1 == num_parts) is_last_letter = (len(typewriter) == len(part.text)) if not (is_last_part and is_last_letter): output_parts.append(CodePart(Token, '\u2588')) row_line = CodeLine(output_parts, self.code.lexer) step = steplib.ReplaceRows(self.code_box, replace_pos, row_line) steps.append(step) steps.append(steplib.Sleep(self.delay_until_next_letter)) return steps
from unittest import TestCase from pygments.token import Token from purdy.parser import CodePart, CodeLine, PurdyLexer # ============================================================================= py3_lexer = PurdyLexer.factory_from_name('py3') bash_lexer = PurdyLexer.factory_from_name('bash') PY_CODE_LINES = [ CodeLine([ CodePart(Token.Comment.Single, '# Sample Code'), ], py3_lexer), CodeLine([ CodePart(Token.Text, ''), ], py3_lexer), CodeLine([ CodePart(Token.Keyword, 'def'), CodePart(Token.Text, ' '), CodePart(Token.Name.Function, 'foo'), CodePart(Token.Punctuation, '('), CodePart(Token.Punctuation, ')'), CodePart(Token.Punctuation, ':'), ], py3_lexer), CodeLine([ CodePart(Token.Text, ' '), CodePart(Token.Literal.String.Doc, '"""Multi-line'), ], py3_lexer), CodeLine([