def checkBadLoopCollect(code): """ Look for bad loop like 'for i in range(len(list))' Documentation: https://youtu.be/OSGv2VnC0go?t=4m47s """ sequence = [(Token.Keyword, '^for$'), (Token.Name, '^\w+$'), (Token.Operator.Word, '^in$'), (Token.Name.Builtin, '^range$|^xrange$'), (Token.Punctuation, '^\($'), (Token.Name.Builtin, '^len$'), (Token.Punctuation, '^\($'), (Token.Name, '^\w+$')] lexer = PythonLexer() lexer.add_filter('tokenmerge') tokens = pygments.lex(code, lexer) badLoopCollectIdiom = PythonIdiom('badLoop') lineNumber = 1 while True: lineAux = _findSeqInTokens(sequence, tokens) if lineAux < 0: break lineNumber += lineAux -1 badLoopCollectIdiom.addNew(lineNumber) log("badLoopCollect found in lines {0}".format(badLoopCollectIdiom.getLines())) return badLoopCollectIdiom
def findBadUseImport(code): """ Find when use from foo import * Documentation: http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html#importing https://docs.python.org/2/howto/doanddont.html#from-module-import """ sequence = [(Token.Keyword.Namespace, '^from$'), (Token.Name.Namespace, '.*'), (Token.Keyword.Namespace, '^import$'), (Token.Operator, '\*')] lexer = PythonLexer() lexer.add_filter('tokenmerge') tokens = pygments.lex(code, lexer) badUseImport = PythonIdiom('badImport') lineNumber = 1 while True: lineAux = _findSeqInTokens(sequence, tokens) if lineAux < 0: break lineNumber += lineAux -1 badUseImport.addNew(lineNumber) log("badUseImport found in lines {0}".format(badUseImport.getLines())) return badUseImport
def checkNotRange(code): """ Check if there is: for xx in [0,1,2] instead of for xxx in (x)range Documentation: https://youtu.be/OSGv2VnC0go?t=3m4s """ sequence = [(Token.Keyword, '^for$'), (Token.Name, '^\w+$'), (Token.Operator.Word, '^in$'), (Token.Punctuation, '^\[$'), (Token.Literal.Number.Integer, '^\d$')] lexer = PythonLexer() lexer.add_filter('tokenmerge') tokens = pygments.lex(code, lexer) notRangeIdiom = PythonIdiom('notRange') lineNumber = 1 while True: lineAux = _findSeqInTokens(sequence, tokens) if lineAux < 0: break lineNumber += lineAux -1 notRangeIdiom.addNew(lineNumber) log("badForIn found in lines {0}".format(notRangeIdiom.getLines())) return notRangeIdiom
def findDocstring(code): """Find the use of documentation in the functions, classes or script Documentation: https://www.python.org/dev/peps/pep-0257/ """ lexer = PythonLexer() lexer.add_filter('tokenmerge') classDefToken = (Token.Keyword, '^class$') functDefToken = (Token.Keyword, '^def$') tokens = pygments.lex(code, lexer) docIdiom = PythonIdiom('docstring') docstringFound = defaultdict(int) typeDoc = 'module' lineNumber = 1 for ttype, word in tokens: if _sameToken((ttype, word), classDefToken): typeDoc = 'class' elif _sameToken((ttype, word), functDefToken): typeDoc = 'function' elif ttype == Token.Literal.String.Doc: docstringFound[typeDoc] += 1 docIdiom.addNew(lineNumber) lineNumber += _getNewLines((ttype, word)) for typeDoc in docstringFound: log("type %s: %d found" % (typeDoc, docstringFound[typeDoc])) log('DocString found in lines: ' + str(docIdiom.getLines())) return docIdiom
def basicStructure(code): sequence = [] lexer = PythonLexer() lexer.add_filter('tokenmerge') tokens = pygments.lex(code, lexer) for token in tokens: print token
def python_line_tokens(code_lines, blank_lines=False): from pygments.lexers import PythonLexer lexer = PythonLexer() code_str = "".join(code_lines) all_tokens = list(lexer.get_tokens(code_str, unfiltered=True)) line_tokens = [] current_line = [] for t in all_tokens: if t[1] == u"\n": line_tokens.append(current_line) current_line = [] else: current_line.append(t) rows = [] for i, tokens in enumerate(line_tokens): # Check for blank line line_str = code_lines[i].rstrip() if (not blank_lines) and len(line_str.strip()) == 0: continue for t in tokens: kind, value = str(t[0]), t[1] yield line_str, i, kind, value, t
def python_prettify(code, style): lexer = PythonLexer() lexer.add_filter(VisibleWhitespaceFilter(spaces=" ")) pretty_code = highlight( code, lexer, HtmlFormatter( linenos=style, linenostart=0)) # print(pretty_code) return format_html('{}', mark_safe(pretty_code))
def redent(s): """ Shamelessly stolen from infobob(#python bot) code https://code.launchpad.net/~pound-python/infobat/infobob """ lexer = PythonLexer() lexer.add_filter(_RedentFilter()) return highlight(s, lexer, NullFormatter())
def _analyse_source_code(self, source_code): lexer = PythonLexer() token_source = lexer.get_tokens(source_code) for token_type, value in token_source: if len(value) > 3 and value.startswith('gl') and ord('A') <= ord(value[2]) <= ord('Z'): self.gl_functions.add(value) elif len(value) > 3 and value.startswith('GL_'): self.gl_constants.add(value)
def python_token_metrics(code_lines, indent_size=4): from pygments.lexers import PythonLexer indent_regex = re.compile(r"^\s*") lexer = PythonLexer() code_str = "".join(code_lines) all_tokens = list(lexer.get_tokens(code_str, unfiltered=True)) line_tokens = [] current_line = [] for t in all_tokens: if t[1] == u"\n": line_tokens.append(current_line) current_line = [] else: current_line.append(t) rows = [] for i, tokens in enumerate(line_tokens): line_number = i + 1 # Check for blank line line_str = code_lines[i].rstrip() if len(line_str.strip()) == 0: rows.append([line_number, 0, 0, 0, 0, 0, 0]) continue assert len(tokens) > 0, "No tokens for line" num_keywords = 0 num_identifiers = 0 num_operators = 0 line_length = len(line_str) line_indent = len(indent_regex.findall(line_str)[0]) / indent_size # Indentation is not considered line_str_noindent = line_str.lstrip() line_length_noindent = len(line_str_noindent) whitespace_prop = line_str_noindent.count(" ") / float(line_length_noindent) for t in tokens: kind, value = str(t[0]), t[1] if kind.startswith(u"Token.Keyword"): num_keywords += 1 elif kind.startswith(u"Token.Name"): num_identifiers += 1 elif kind.startswith(u"Token.Operator"): num_operators += 1 rows.append([line_number, line_length_noindent, num_keywords, num_identifiers, num_operators, whitespace_prop, line_indent]) columns = ["line", "line_length", "keywords", "identifiers", "operators", "whitespace_prop", "line_indent"] return pandas.DataFrame(rows, columns=columns)
def testWorksAsExpected(self): code = ''' """ Increment number of decision points in function.""" #if tok and tok.text in McCabeKeywords: if (tok[0][0] == b'Keyword') and tok[1] in McCabeKeywords: self.metrics['mccabe'] += 1 ''' result = [(Token.Text, u' '), (Token.Literal.String.Doc, u'""" Increment number of decision points in function."""'), (Token.Text, u'\n'), (Token.Text, u' '), (Token.Comment, u'#if tok and tok.text in McCabeKeywords:'), (Token.Text, u'\n'), (Token.Text, u' '), (Token.Keyword, u'if'), (Token.Text, u' '), (Token.Punctuation, u'('), (Token.Name, u'tok'), (Token.Punctuation, u'['), (Token.Literal.Number.Integer, u'0'), (Token.Punctuation, u']'), (Token.Punctuation, u'['), (Token.Literal.Number.Integer, u'0'), (Token.Punctuation, u']'), (Token.Text, u' '), (Token.Operator, u'=='), (Token.Text, u' '), (Token.Name, u'b'), (Token.Literal.String, u"'"), (Token.Literal.String, u'Keyword'), (Token.Literal.String, u"'"), (Token.Punctuation, u')'), (Token.Text, u' '), (Token.Operator.Word, u'and'), (Token.Text, u' '), (Token.Name, u'tok'), (Token.Punctuation, u'['), (Token.Literal.Number.Integer, u'1'), (Token.Punctuation, u']'), (Token.Text, u' '), (Token.Operator.Word, u'in'), (Token.Text, u' '), (Token.Name, u'McCabeKeywords'), (Token.Punctuation, u':'), (Token.Text, u'\n'), (Token.Text, u' '), (Token.Name.Builtin.Pseudo, u'self'), (Token.Operator, u'.'), (Token.Name, u'metrics'), (Token.Punctuation, u'['), (Token.Literal.String, u"'"), (Token.Literal.String, u'mccabe'), (Token.Literal.String, u"'"), (Token.Punctuation, u']'), (Token.Text, u' '), (Token.Operator, u'+'), (Token.Operator, u'='), (Token.Text, u' '), (Token.Literal.Number.Integer, u'1'), (Token.Text, u'\n'), (Token.Text, u' '), (Token.Text, u'\n')] lex = PythonLexer() tokenList = lex.get_tokens(code) self.assertEqual(list(tokenList), result)
def __init__(self): """ constructor """ self._lexer = PythonLexer() self._formatter = HtmlFormatter() self._document = QtGui.QTextDocument() self._document.setDefaultStyleSheet(self._formatter.get_style_defs()) self._format_cache = dict()
class PythonTest(unittest.TestCase): def setUp(self): self.lexer = PythonLexer() def test_cls_builtin(self): """ Tests that a cls token gets interpreted as a Token.Name.Builtin.Pseudo """ fragment = 'class TestClass():\n @classmethod\n def hello(cls):\n pass\n' tokens = [ (Token.Keyword, 'class'), (Token.Text, ' '), (Token.Name.Class, 'TestClass'), (Token.Punctuation, '('), (Token.Punctuation, ')'), (Token.Punctuation, ':'), (Token.Text, '\n'), (Token.Text, ' '), (Token.Name.Decorator, '@classmethod'), (Token.Text, '\n'), (Token.Text, ' '), (Token.Keyword, 'def'), (Token.Text, ' '), (Token.Name.Function, 'hello'), (Token.Punctuation, '('), (Token.Name.Builtin.Pseudo, 'cls'), (Token.Punctuation, ')'), (Token.Punctuation, ':'), (Token.Text, '\n'), (Token.Text, ' '), (Token.Keyword, 'pass'), (Token.Text, '\n'), ] self.assertEqual(tokens, list(self.lexer.get_tokens(fragment)))
def get_tokens_unprocessed(self, text): for index, token, value in \ PythonLexer.get_tokens_unprocessed(self, text): if token is Name and value in self.EXTRA_KEYWORDS: yield index, Keyword.Pseudo, value else: yield index, token, value
class PygmentsHighlighter(object): """ highlight python code with a QSyntaxHighlighter, callable class (e.g. function with a state) to """ def __init__(self): """ constructor """ self._lexer = PythonLexer() self._formatter = HtmlFormatter() self._document = QtGui.QTextDocument() self._document.setDefaultStyleSheet(self._formatter.get_style_defs()) self._format_cache = dict() def __call__(self, code): """ makes this class callable, actually do the highlightning """ index = 0 for token, text in self._lexer.get_tokens(code): length = len(text) char_format = self._get_format(token) pygmentsHighlighter._setFormat(index, length, char_format) index += length def _get_format(self, token): """ get the QTextCharFormat for a token """ if token in self._format_cache: return self._format_cache[token] # get format from document code, html = next(self._formatter._format_lines([(token, u"dummy")])) self._document.setHtml(html) char_format = QtGui.QTextCursor(self._document).charFormat() # cache result self._format_cache[token] = char_format return char_format
def __init__(self, makecolors = True, style = standardcols): if makecolors: self.makecolorpairs() if style is None: style = standardcols self.style = style self.lexer = PythonLexer()
def __init__(self, prompt='>>> ', continuation='... ', parent=None): QTextEdit.__init__(self, parent) self.shutting_down = False self.compiler = CommandCompiler() self.buf = self.old_buf = [] self.history = History([''], dynamic.get('console_history', [])) self.prompt_frame = None self.allow_output = False self.prompt_frame_format = QTextFrameFormat() self.prompt_frame_format.setBorder(1) self.prompt_frame_format.setBorderStyle(QTextFrameFormat.BorderStyle_Solid) self.prompt_len = len(prompt) self.doc.setMaximumBlockCount(int(prefs['scrollback'])) self.lexer = PythonLexer(ensurenl=False) self.tb_lexer = PythonTracebackLexer() self.context_menu = cm = QMenu(self) # {{{ cm.theme = ThemeMenu(cm) # }}} self.formatter = Formatter(prompt, continuation, style=prefs['theme']) p = QPalette() p.setColor(p.Base, QColor(self.formatter.background_color)) p.setColor(p.Text, QColor(self.formatter.color)) self.setPalette(p) self.key_dispatcher = { # {{{ Qt.Key_Enter : self.enter_pressed, Qt.Key_Return : self.enter_pressed, Qt.Key_Up : self.up_pressed, Qt.Key_Down : self.down_pressed, Qt.Key_Home : self.home_pressed, Qt.Key_End : self.end_pressed, Qt.Key_Left : self.left_pressed, Qt.Key_Right : self.right_pressed, Qt.Key_Backspace : self.backspace_pressed, Qt.Key_Delete : self.delete_pressed, } # }}} motd = textwrap.dedent('''\ # Python {0} # {1} {2} '''.format(sys.version.splitlines()[0], __appname__, __version__)) sys.excepthook = self.unhandled_exception self.controllers = [] QTimer.singleShot(0, self.launch_controller) with EditBlock(self.cursor): self.render_block(motd)
def get_tokens_unprocessed(self, text): for index, token, value in PythonLexer.get_tokens_unprocessed(self, text): if token is Name and value in self.EXTRA_KEYWORDS: yield index, Keyword, value elif token is Name and value in self.EXTRA_FUNC: yield index, Name.Function, value else: yield index, token, value
class CursesParser: def __init__(self, makecolors = True, style = standardcols): if makecolors: self.makecolorpairs() if style is None: style = standardcols self.style = style self.lexer = PythonLexer() @classmethod def makecolorpairs(cls): """Initializes curses for colors, makes a color pair of (color, defaultbg) for every color, and initializes self.colorpairs as a dictionary with a color -> colorpair mapping""" if hasattr(cls, 'colorpairs'): return cls.colorpairs curses.start_color() curses.use_default_colors() maxcolors = curses.COLORS maxpairs = curses.COLOR_PAIRS totalmax = min(maxcolors+1, maxpairs) cls.colorpairs = {} for colpr in range(1,totalmax): if colpr >= maxpairs: break col = colpr % maxcolors curses.init_pair(colpr, col, -1) cls.colorpairs[col] = curses.color_pair(colpr) return cls.colorpairs def get_colors(self, raw): """Uses pygments to parse the text, and yields (text, color, attr) tuples""" for tkn, txt in self.lexer.get_tokens(raw): notyielded = True while notyielded: if tkn is None: yield (txt, None, None) notyielded = False elif tkn in self.style: col, attr = self.style[tkn] yield (txt, col, attr) notyielded = False else: tkn = tkn.parent def parsetoscr(self, scr, raw): """Parses text, and uses scr.addstr to print the text directly.""" self.makecolorpairs() for (txt, col, attr) in self.get_colors(raw): fullattr = attr if attr is None: fullattr = curses.A_NORMAL if col is not None: # and col in self.colorpairs: fullattr |= self.colorpairs[col] scr.addstr(txt, fullattr)
def get_context(string): """ Assuming the cursor is at the end of the specified string, get the context (a list of names) for the symbol at cursor position. """ lexer = PythonLexer() context = [] reversed_tokens = list(lexer.get_tokens(string)) reversed_tokens.reverse() # Pygments often tacks on a newline when none is specified in the input. # Remove this newline. if reversed_tokens and reversed_tokens[0][1].endswith('\n') and \ not string.endswith('\n'): reversed_tokens.pop(0) current_op = '' for token, text in reversed_tokens: if is_token_subtype(token, Token.Name): # Handle a trailing separator, e.g 'foo.bar.' if current_op == '.': if not context: context.insert(0, '') # Handle non-separator operators and punction. elif current_op: break context.insert(0, text) current_op = '' # Pygments doesn't understand that, e.g., '->' is a single operator # in C++. This is why we have to build up an operator from # potentially several tokens. elif token is Token.Operator or token is Token.Punctuation: current_op = text + current_op # Break on anything that is not a Operator, Punctuation, or Name. else: break return context
def __init__(self, parent, lexer=None): super(PygmentsHighlighter, self).__init__(parent) try: self._lexer = get_lexer_by_name(lexer) except: self._lexer = PythonLexer() # Caches for formats and brushes. self._brushes = {} self._formats = {}
def get_tokens_unprocessed(self, text): for index, token, value in PythonLexer.get_tokens_unprocessed(self, text): if token is Name and value in self.EXTRA_CLASSES: yield index, Name.Class, value elif token is Name and value in self.EXTRA_BUILTINS: yield index, Name.Function, value elif token is Name and value in self.EXTRA_CONSTS: yield index, Keyword.Constant, value elif token in (Name, Punctuation): yield index, Text, value else: yield index, token, value
def findUseMapFilterReduce(code): """ Find the use of map, filter and reduce builtins in the code. A better option is the use of generators and list comprehensions Documentation: Fluent Python page 142 https://docs.python.org/2/library/functions.html#map https://docs.python.org/2/library/functions.html#filter https://docs.python.org/2/library/functions.html#reduce """ filterToken = (Token.Name.Builtin, '^filter$') mapToken = (Token.Name.Builtin, '^map$') reduceToken = (Token.Name.Builtin, '^reduce$') tokensFound = {'filter': 0, 'map': 0, 'reduce': 0} lexer = PythonLexer() lexer.add_filter('tokenmerge') tokens = pygments.lex(code, lexer) lineNumber = 1 mapIdiom = PythonIdiom('map') filterIdiom = PythonIdiom('filter') reduceIdiom = PythonIdiom('reduce') for token in tokens: lineNumber += _getNewLines(token) if _sameToken(token, filterToken): tokensFound['filter'] += 1 filterIdiom.addNew(lineNumber) elif _sameToken(token, reduceToken): tokensFound['reduce'] += 1 reduceIdiom.addNew(lineNumber) elif _sameToken(token, mapToken): tokensFound['map'] += 1 mapIdiom.addNew(lineNumber) log('filter found in lines: ' + str(filterIdiom.getLines())) log('map found in lines: ' + str(mapIdiom.getLines())) log('reduce found in lines: ' + str(reduceIdiom.getLines())) return [mapIdiom, filterIdiom, reduceIdiom]
def __init__(self, parent, lexer=None): super(PygmentsHighlighter, self).__init__(parent) self._document = self.document() self._formatter = HtmlFormatter(nowrap=True) self.set_style('default') if lexer is not None: self._lexer = lexer else: if PY3: self._lexer = Python3Lexer() else: self._lexer = PythonLexer()
def __init__(self, *args, **kw): super(FrontendWidget, self).__init__(*args, **kw) # FrontendWidget protected variables. self._bracket_matcher = BracketMatcher(self._control) self._call_tip_widget = CallTipWidget(self._control) self._completion_lexer = CompletionLexer(PythonLexer()) self._copy_raw_action = QtGui.QAction('Copy (Raw Text)', None) self._hidden = False self._highlighter = FrontendHighlighter(self) self._input_splitter = self._input_splitter_class(input_mode='cell') self._kernel_manager = None self._request_info = {} # Configure the ConsoleWidget. self.tab_width = 4 self._set_continuation_prompt('... ') # Configure the CallTipWidget. self._call_tip_widget.setFont(self.font) self.font_changed.connect(self._call_tip_widget.setFont) # Configure actions. action = self._copy_raw_action key = QtCore.Qt.CTRL | QtCore.Qt.SHIFT | QtCore.Qt.Key_C action.setEnabled(False) action.setShortcut(QtGui.QKeySequence(key)) action.setShortcutContext(QtCore.Qt.WidgetWithChildrenShortcut) action.triggered.connect(self.copy_raw) self.copy_available.connect(action.setEnabled) self.addAction(action) # Connect signal handlers. document = self._control.document() document.contentsChange.connect(self._document_contents_change) # Set flag for whether we are connected via localhost. self._local_kernel = kw.get('local_kernel', FrontendWidget._local_kernel)
def __str__(self) -> str: out = [] try: from pygments import highlight from pygments.formatters import HtmlFormatter from pygments.lexers import PythonLexer formatter = HtmlFormatter( style="friendly", lineanchors=True, linenos=True, wrapcode=True ) out.append(f"<style>{formatter.get_style_defs('.highlight')}</style>") out.append(highlight(str(self.code_block), PythonLexer(), formatter)) except ImportError: out.append(f"<pre><code>{self.code_block}</code></pre>") if self.advertise: out.append(Advertisement().html()) if self.session_info: out.append("<details><summary>Session Info</summary>") out.append(f"<pre><code>{SessionInfo()}</code></pre>") out.append("</details>") return "\n".join(out)
def save_correct(lti=lti): assignment_id = request.form.get('question_id', None) status = float(request.form.get('status', "0.0")) lis_result_sourcedid = request.form.get('lis_result_sourcedid', None) if assignment_id is None: return jsonify(success=False, message="No Assignment ID given!") user = User.from_lti("canvas", session["pylti_user_id"], session.get("user_email", ""), session.get("lis_person_name_given", ""), session.get("lis_person_name_family", "")) assignment = Assignment.by_id(assignment_id) if status == 1: submission = Submission.save_correct(user.id, assignment_id) else: submission = assignment.get_submission(user.id) if submission.correct: message = "Success!" else: message = "Incomplete" url = url_for('lti_assignments.get_submission_code', submission_id=submission.id, _external=True) if lis_result_sourcedid is None: return jsonify(success=False, message="Not in a grading context.") if assignment.mode == 'maze': lti.post_grade(float(submission.correct), "<h1>{0}</h1>".format(message), endpoint=lis_result_sourcedid) else: lti.post_grade( float(submission.correct), "<h1>{0}</h1>".format(message) + "<div>Latest work in progress: <a href='{0}' target='_blank'>View</a></div>" .format(url) + "<div>Touches: {0}</div>".format(submission.version) + "Last ran code:<br>" + highlight(submission.code, PythonLexer(), HtmlFormatter()), endpoint=lis_result_sourcedid) return jsonify(success=True)
def do_install(self, name, data): if name in data: utils.makedirs(self.output_dir) LOGGER.notice('Downloading: ' + data[name]) zip_file = BytesIO() zip_file.write(requests.get(data[name]).content) LOGGER.notice('Extracting: {0} into themes'.format(name)) utils.extract_all(zip_file) dest_path = os.path.join('themes', name) else: try: theme_path = utils.get_theme_path(name) except: LOGGER.error("Can't find theme " + name) return False utils.makedirs(self.output_dir) dest_path = os.path.join(self.output_dir, name) if os.path.exists(dest_path): LOGGER.error("{0} is already installed".format(name)) return False LOGGER.notice('Copying {0} into themes'.format(theme_path)) shutil.copytree(theme_path, dest_path) confpypath = os.path.join(dest_path, 'conf.py.sample') if os.path.exists(confpypath): LOGGER.notice( 'This plugin has a sample config file. Integrate it with yours in order to make this theme work!' ) print('Contents of the conf.py.sample file:\n') with codecs.open(confpypath, 'rb', 'utf-8') as fh: print( indent( pygments.highlight(fh.read(), PythonLexer(), TerminalFormatter()), 4 * ' ')) LOGGER.notice( 'Remember to set THEME="{0}" in conf.py to use this theme.'.format( name)) return True
def _init_pygments(self): if not self.config.use_pygments: return False try: from pygments.lexers import PythonLexer from pygments.formatters import TerminalFormatter, Terminal256Formatter except ImportError: return False if hasattr(self, '_fmt'): return True if hasattr(self.config, 'formatter'): self._fmt = self.config.formatter else: Formatter = (Terminal256Formatter if self.config.use_terminal256formatter and '256color' in os.environ.get('TERM', '') else TerminalFormatter) self._fmt = Formatter(bg=self.config.bg, colorscheme=self.config.colorscheme) self._lexer = PythonLexer() return True
class SourceCodeWidget(Widget): params = { 'widget': 'The name of the widget', 'module': 'Whether to display the entire module', 'source': 'Optional source code', 'code': 'The actual rendered source code', 'title': ' An optional title for the document', } template = "${code}" engine_name = 'mako' container_options = { 'width': 625, 'height': 675, 'title': 'View Source', 'icon': 'comment.png', 'top': 50, 'left': 300 } hidden = True module = False title = None def update_params(self, d): super(SourceCodeWidget, self).update_params(d) title = d.widget.__class__.__name__ if not d.source: try: d.widget = moksha.get_widget(d.widget) except Exception, e: d.widget = namedAny(d.widget) if d.module: obj = namedAny(d.widget.__module__) else: obj = d.widget.__class__ d.source = inspect.getsource(obj) html_args = {'full': True} if d.title: html_args['title'] = d.title d.code = highlight(d.source, PythonLexer(), HtmlFormatter(**html_args))
def do_install(self, name, data): """Download and install a theme.""" if name in data: utils.makedirs(self.output_dir) url = data[name] LOGGER.info("Downloading '{0}'".format(url)) try: zip_data = requests.get(url).content except requests.exceptions.SSLError: LOGGER.warning("SSL error, using http instead of https (press ^C to abort)") time.sleep(1) url = url.replace('https', 'http', 1) zip_data = requests.get(url).content zip_file = io.BytesIO() zip_file.write(zip_data) LOGGER.info("Extracting '{0}' into themes/".format(name)) utils.extract_all(zip_file) dest_path = os.path.join(self.output_dir, name) else: dest_path = os.path.join(self.output_dir, name) try: theme_path = utils.get_theme_path_real(name, self.site.themes_dirs) LOGGER.error("Theme '{0}' is already installed in {1}".format(name, theme_path)) except Exception: LOGGER.error("Can't find theme {0}".format(name)) return False confpypath = os.path.join(dest_path, 'conf.py.sample') if os.path.exists(confpypath): LOGGER.warning('This theme has a sample config file. Integrate it with yours in order to make this theme work!') print('Contents of the conf.py.sample file:\n') with io.open(confpypath, 'r', encoding='utf-8-sig') as fh: if self.site.colorful: print(pygments.highlight(fh.read(), PythonLexer(), TerminalFormatter())) else: print(fh.read()) return True
def parse_single(self, hunk_no, file_no, start, stop): start = self.chunk_start(start) stop = self.chunk_end(stop) self._hunk_no = hunk_no self._file_no = file_no self._snippet_start = start self._snippet_end = stop for i, line in self._read_reverse(start=start): line_tokens = list(lex(line, PythonLexer())) if self.is_func_or_class(line_tokens): self._snippet_body.append(line_tokens) self._snippet_start = i if self._is_complete(): self._reset(soft=True) return self.parse(start=i, stop=stop) else: self._snippet_body.append(line_tokens) self._snippet_end = i
def parsekeywordpairs(signature): tokens = PythonLexer().get_tokens(signature) stack = [] substack = [] parendepth = 0 begin = False for token, value in tokens: if not begin: if token is Token.Punctuation and value == u'(': begin = True continue if token is Token.Punctuation: if value == u'(': parendepth += 1 elif value == u')': parendepth -= 1 elif value == ':' and parendepth == -1: # End of signature reached break if parendepth > 0: substack.append(value) continue if (token is Token.Punctuation and (value == ',' or (value == ')' and parendepth == -1))): stack.append(substack[:]) del substack[:] continue if value and value.strip(): substack.append(value) d = {} for item in stack: if len(item) >= 3: d[item[0]] = ''.join(item[2:]) return d
def show_notebook(self, fname): """display a short summary of the cells of a notebook""" formatter = HtmlFormatter() lexer = PythonLexer() # publish the CSS for pygments highlighting display(HTML(""" <style type='text/css'> %s </style> """ % formatter.get_style_defs() )) nb = nbformat.read(fname, as_version=4) html = [] for cell in nb.cells: html.append("<h4>%s cell</h4>" % cell.cell_type) if cell.cell_type == 'code': html.append(highlight(cell.source, lexer, formatter)) else: html.append("<pre>%s</pre>" % cell.source) display(HTML('\n'.join(html)))
def __init__(self, main_window): """ desc: Constructor. arguments: main_window: The main-window object. """ self.setup(main_window) self.css = u'<style type="text/css">' with safe_open(self.main_window.theme.resource(u'markdown.css')) as fd: self.css += fd.read() % {u'background_image' : \ os.path.abspath(self.main_window.theme.resource( u'background.png'))} if highlight is not None: self.traceback_lexer = TracebackLexer() self.python_lexer = PythonLexer() self.html_formatter = HtmlFormatter() self.css += self.html_formatter.get_style_defs(u'.highlight') self.re_script = re.compile( r'^~~~\s*.(?P<syntax>\w+)(?P<script>.*?)^~~~', re.S | re.M) self.css += u'</style>' if markdown is not None: self.ext = [attr_list.AttrListExtension(), extra.ExtraExtension(), toc.TocExtension(title=u'Overview'), u'markdown.extensions.tables'] self.footer = u''' <p> <a class="dismiss-button" href="opensesame://action.close_current_tab">%s</a> </p> <div class="footer"> OpenSesame %s %s ā Copyright <a href="http://www.cogsci.nl/smathot">Sebastiaan MathĆ“t</a> 2010-2016 </div> ''' % (_(u'Dismiss this message'), metadata.__version__, metadata.codename)
def run(): if not request.args: return jsonify(error=True) if 'exec' in request.args.keys(): global prefix global console command = request.args['exec'] print(command) output = io.StringIO() old_stdout = sys.stdout old_stderr = sys.stderr sys.stdout = sys.stderr = output try: execute = console.push(command) finally: sys.stdout = old_stdout sys.stderr = old_stderr output = output.getvalue() if not prefix: prefix = '>>> ' result = prefix + command + '\n' + output html = highlight(result, PythonLexer(), HtmlFormatter()) if execute: prefix = '... ' else: prefix = '>>> ' return jsonify(command=command, execute=output, prefix=prefix, code=html) elif 'restore' in request.args.keys(): if request.args['restore']: console = code.InteractiveConsole() return jsonify(restored=True) else: return jsonify(restored=False) else: return jsonify(error=True)
def print_code_block(code_block): ''' Prints a code block from Stack Overflow with syntax highlighting. On Stack Overflow, the code in a HTML 'code' element contains a 'span' element for each token. Because of this, it's necessary to grab each of the 'code' element's 'span' elements' values to get the actual code. Parameter {bs4.Tag} code_block: 'soup' of a HTML 'code' element from a Stack Overflow post. ''' token_colors = { 'Token.Keyword': 'blue', 'Token.Name.Builtin.Pseudo': 'blue', 'Token.Literal.Number.Integer': 'green', 'Token.Literal.Number.Float': 'green', 'Token.Comment.Single': 'green', 'Token.Comment.Hashbang': 'green', 'Token.Literal.String.Single': 'yellow', 'Token.Literal.String.Double': 'yellow', 'Token.Literal.String.Doc': 'yellow' } print('') # Store the code's text. code = get_src_code(code_block) # Loop over code, and highlight. for token, content in pygments.lex(code, PythonLexer()): try: print(colored(content, token_colors[str(token)]), end='') except KeyError: print(content, end='') print('')
def _format_sql(sql, data, format='html'): popts = {} if data.get('remove_comments'): popts['strip_comments'] = True if data.get('keyword_case', 'undefined') not in ('undefined', ''): popts['keyword_case'] = data.get('keyword_case') if data.get('identifier_case', 'undefined') not in ('undefined', ''): popts['identifier_case'] = data.get('identifier_case') if data.get('n_indents', None) is not None: val = data.get('n_indents') try: popts['indent_width'] = max(1, min(1000, int(val))) popts['reindent'] = True except (ValueError, TypeError): pass if (not 'indent_width' in popts and data.get('reindent', '').lower() in ('1', 'true', 't')): popts['indent_width'] = 2 popts['reindent'] = True if data.get('output_format', None) is not None: popts['output_format'] = data.get('output_format') logging.debug('Format: %s, POPTS: %r', format, popts) logging.debug(sql) sql = sqlparse.format(sql, **popts) if format in ('html', 'json'): if data.get('highlight', False): if popts['output_format'] == 'python': lexer = PythonLexer() elif popts['output_format'] == 'php': lexer = PhpLexer() else: lexer = SqlLexer() sql = highlight(sql, lexer, HtmlFormatter()) else: sql = ('<textarea class="resizable" ' 'style="height: 350px; margin-top: 1em;">%s</textarea>' % sql) return sql
class SourceCodeWidget(twc.Widget): widget = twc.Param('The name of the widget') module = twc.Param('Whether to display the entire module', default=False) source = twc.Param('Optional source code', default=None) title = twc.Variable(' An optional title for the document') code = twc.Variable('The actual rendered source code') template = "mako:moksha.widgets.templates.sourcecode" container_options = { 'width': 625, 'height': 675, 'title': 'View Source', 'icon': 'comment.png', 'top': 50, 'left': 300 } hidden = twc.Param(default=True) module = twc.Param(default=False) title = twc.Param(default=None) def prepare(self): super(SourceCodeWidget, self).prepare() title = self.widget.__class__.__name__ if not self.source: try: self.widget = moksha.utils.get_widget(self.widget) except Exception, e: self.widget = namedAny(self.widget) if self.module: obj = namedAny(self.widget.__module__) else: obj = self.widget.__class__ self.source = inspect.getsource(obj) html_args = {'full': True} if self.title: html_args['title'] = self.title self.code = highlight(self.source, PythonLexer(), HtmlFormatter(**html_args))
def print_contributer_lines(contributer, diff_infos): output = [] for diff_info in diff_infos: lines = diff_info["reviewers"].get(contributer) if not lines: continue shl.print_section(shl.BOLD, diff_info["from_hash"], diff_info["file"], file=output) prev_line = None for line in lines: try: from pygments import highlight from pygments.lexers import PythonLexer from pygments.formatters import TerminalFormatter code = highlight(line["code_line"], PythonLexer(), TerminalFormatter()) except ImportError: code = line["code_line"] cur_line = int(line["line_num"]) if prev_line and prev_line + 1 < cur_line: output.append(" .") output.append(" .") output.append(" .") output.append("{line_num: >5}|\t{code_line}".format( line_num=line["line_num"], code_line=code.rstrip())) prev_line = cur_line output.append("\n\n") pydoc.pager("\n".join(output))
def displayArray(): fs = open('temp.py', 'w') rawArray = getHtml('test.py') plotCount = rawArray.pop() fs.write(duplicate(rawArray)) subprocess.call([sys.executable, 'temp.py']) displayText = '' css = '<head><script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script><script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js" ></script><script type="text/javascript" src="' + url_for( 'static', filename='main.js') + '"></script><style>' + HtmlFormatter( ).get_style_defs( '.highlight' ) + 'body {margin: 20px 50px;}img{width:90vw;}</style></head>' for x in rawArray: displayText = displayText + highlight(''.join(x), PythonLexer(), HtmlFormatter()) if plotCount > 0: displayText += '<img src="' + url_for( 'static', filename='testplot.png') + '">' plotCount -= 1 displayText = '<body>' + displayText + '</body>' return css + displayText
def showcase_code(pyfile, class_name=False, showcase=False): """shows content of py file""" if showcase: with open(pyfile) as f: code = f.read() if class_name: #1. find beginning (class + <name>) index = code.find(f'class {class_name}') code = code[index:] #2. find end (class (new class!) or end of script) end_index = code[7:].find('class') code = code[:end_index] formatter = HtmlFormatter() return IPython.display.HTML( '<style type="text/css">{}</style>{}'.format( formatter.get_style_defs('.highlight'), highlight(code, PythonLexer(), formatter))) pass
def get_code(extracted_tb): try: trace = next((trace for trace in extracted_tb if 'site-packages' not in trace[0]), None) if not trace: return None filename = trace[0] lineno = trace[1] offset = 10 with open(filename, encoding='utf-8') as f: code_context = list(islice(f, lineno - offset, lineno + offset)) return highlight(''.join(code_context), PythonLexer(), HtmlFormatter( noclasses=True, linenos='table', hl_lines=[offset, offset], linenostart=(lineno - offset + 1), ) ) except Exception as e: return "Unable to extract code. {}".format(e)
def injectable_definition(inj_name): """ Get the source of an injectable function. If an injectable is a registered Python variable and not a function then all that is returned is {'type': 'variable'}. If the column is a registered function then the JSON returned has keys "type", "filename", "lineno", "text", and "html". "text" is the raw text of the function, "html" has been marked up by Pygments. """ inj_type = orca.injectable_type(inj_name) if inj_type == 'variable': return jsonify(type='variable') else: filename, lineno, source = \ orca.get_injectable_func_source_data(inj_name) html = highlight(source, PythonLexer(), HtmlFormatter()) return jsonify( type='function', filename=filename, lineno=lineno, text=source, html=html)
def get_function_source(fn): src = inspect.getsource(fn) lines = src.splitlines() # Get indentation line = lines[1] indent = len(line) - len(line.lstrip()) output = [] count = len(lines) for i, line in enumerate(lines): # Ignore function declaration and final return statement if i == 0 or i == count - 1: continue # Strip indentation output.append(line[indent:]) code = '\n'.join(output).strip() lexer = PythonLexer() formatter = HtmlFormatter(noclasses=True) code = highlight(code, lexer, formatter) return code
def stacktraces(): # First map thread IDs to thread names id_name = {} for thread in threading.enumerate(): id_name[thread.ident] = thread.name code = [] for threadId, stack in sys._current_frames().items(): code.append("\n# ThreadID: %s, Name: %s" % (threadId, id_name.get(threadId, "UNKNOWN"))) for filename, lineno, name, line in traceback.extract_stack(stack): code.append('File: "%s", line %d, in %s' % (filename, lineno, name)) if line: code.append(" %s" % (line.strip())) return highlight( "\n".join(code), PythonLexer(), HtmlFormatter( full=False, # style="native", noclasses=True, ))
def table_definition(table_name): """ Get the source of a table function. If a table is registered DataFrame and not a function then all that is returned is {'type': 'dataframe'}. If the table is a registered function then the JSON returned has keys "type", "filename", "lineno", "text", and "html". "text" is the raw text of the function, "html" has been marked up by Pygments. """ if orca.table_type(table_name) == 'dataframe': return jsonify(type='dataframe') filename, lineno, source = \ orca.get_raw_table(table_name).func_source_data() html = highlight(source, PythonLexer(), HtmlFormatter()) return jsonify( type='function', filename=filename, lineno=lineno, text=source, html=html)
def send_item_processing_failed_email(order_item, task_id, exception, task_args, traceback): UserModel = get_user_model() recipients = UserModel.objects.filter(is_staff=True).exclude(email="") send_email( subject=render_to_string("oseoserver/order_item_failed_subject.txt", context={ "site_name": Site.objects.get_current().name, "item_identifier": order_item.identifier }).strip("\n"), message=render_to_string( "oseoserver/order_item_failed.html", { "item_identifier": order_item, "task_id": task_id, "args": task_args, "exception": exception, "traceback": highlight(traceback, PythonLexer(), HtmlFormatter()), }), recipients=recipients, html=True, order=order_item.batch.order)
def callback_worker(self, queue_actual, idx): signal_handler = WorkerSignalHandler() while not signal_handler.kill_now: try: body = queue_actual.get(block=True, timeout=1) except QueueEmpty: continue except Exception as e: logger.error("Exception on worker thread, restarting: " + str(e)) continue try: if 'job_id' not in body and 'ad_hoc_command_id' not in body: raise Exception( 'Payload does not have a job_id or ad_hoc_command_id') if settings.DEBUG: from pygments import highlight from pygments.lexers import PythonLexer from pygments.formatters import Terminal256Formatter from pprint import pformat logger.info('Body: {}'.format( highlight(pformat(body, width=160), PythonLexer(), Terminal256Formatter(style='friendly')))) try: if 'job_id' in body: JobEvent.create_from_data(**body) elif 'ad_hoc_command_id' in body: AdHocCommandEvent.create_from_data(**body) except DatabaseError as e: logger.error( 'Database Error Saving Job Event: {}'.format(e)) except Exception as exc: import traceback tb = traceback.format_exc() logger.error('Callback Task Processor Raised Exception: %r', exc) logger.error('Detail: {}'.format(tb))
def page_desc(module_desc): module_path, name = module_desc['file'], module_desc['name'] var_name = module_desc.get('var_name', None) plotting._default_document = Document() namespace = {} execfile(module_path, namespace) if var_name: objs = [namespace[var_name]] else: objs = plotting.curdoc().get_context().children embed_snippet = "" for i, obj in enumerate(objs): filename = name + "." + str(i) + ".js" js, tag = autoload_static( obj, Resources(mode="server", root_url=HOSTED_STATIC_ROOT), os.path.join(DETAIL_URL_ROOT, filename)) embed_snippet += tag with open(os.path.join(SNIPPET_BUILD_DIR, filename), "w'") as f: f.write(js) detail_snippet = highlight( open(module_path).read(), PythonLexer(), HtmlFormatter()) return dict( name=name, embed_snippet=embed_snippet, detail_snippet=detail_snippet, detail_page_url=DETAIL_URL_ROOT + name + ".html", prev_detail_url="", prev_detail_name="", next_detail_url="", next_detail_name='', )
def page_desc(module_desc): module_path, name = module_desc['file'], module_desc['name'] var_name = module_desc.get('var_name', None) plotting_helpers._PLOTLIST = [] namespace = {} execfile(module_path, namespace) if var_name: objects = [namespace[var_name]] else: objects = plotting_helpers._PLOTLIST embed_snippet = "" for i, obj in enumerate(objects): # this _id business is just to have nice readable names for # the embed snippet files obj._id = name if len(objects) == 1 else name + "." + str(i) embed_snippet += obj.create_html_snippet( embed_save_loc=SNIPPET_BUILD_DIR, static_path=HOSTED_STATIC_ROOT, embed_base_url=DETAIL_URL_ROOT) detail_snippet = highlight( open(module_path).read(), PythonLexer(), HtmlFormatter()) return dict( name=name, embed_snippet=embed_snippet, detail_snippet=detail_snippet, detail_page_url=DETAIL_URL_ROOT + name + ".html", prev_detail_url="", prev_detail_name="", next_detail_url="", next_detail_name='', )
def to_cyjs_elements_json_str(A) -> dict: sys.path.insert(0, "/tmp/") import lambdas lexer = PythonLexer() formatter = HtmlFormatter() elements = { "nodes": [ { "data": { "id": n, "label": n.attr["label"], "parent": n.attr["parent"], "shape": n.attr["shape"], "color": n.attr["color"], "textValign": "center", "tooltip": get_tooltip(n, lambdas) # "tooltip": highlight(get_tooltip(n, lambdas), lexer, formatter), } } for n in A.nodes() ] + flatten(get_cluster_nodes(A)), "edges": [ { "data": { "id": f"{edge[0]}_{edge[1]}", "source": edge[0], "target": edge[1], } } for edge in A.edges() ], } json_str = json.dumps(elements, indent=2) os.remove("/tmp/preprocessed_code.f") return json_str
def _init_pygments(self): if not self.config.use_pygments: return False try: from pygments.lexers import PythonLexer from pygments.formatters import TerminalFormatter, Terminal256Formatter except ImportError: return False if hasattr(self, '_fmt'): return True if hasattr(self.config, 'formatter'): self._fmt = self.config.formatter else: if (self.config.use_terminal256formatter or (self.config.use_terminal256formatter is None and "256color" in os.environ.get("TERM", ""))): Formatter = Terminal256Formatter else: Formatter = TerminalFormatter self._fmt = Formatter(bg=self.config.bg, colorscheme=self.config.colorscheme) self._lexer = PythonLexer() return True
def configuracao(request, file=''): """Renders the 'configuracao' page.""" assert isinstance(request, HttpRequest) context = BaseView(request).context() geo = context['geo'] server = context['server'] port = int(context['port']) config_files = ExecuteRemoteCommand( server, port, 'BuildBotControls->config_files->' + geo) config_files = config_files.split(';') config_files.reverse() file_css = '' file_content = '' if (file): command = 'BuildBotControls->configfile_content->{0}->{1}'.format( geo, file) file_content = ExecuteRemoteCommand(server, 9999, command) file_content = highlight(file_content, PythonLexer(), HtmlFormatter()) file_css = HtmlFormatter().get_style_defs('.highlight') context.update({ 'menu': 'adminBuildBot/configuracao', 'appname': 'adminPromax', 'title': 'adminBuildBot/Configuração', 'year': datetime.now().year, 'request': request, 'config_files': config_files, 'file_content': file_content, 'file_css': file_css, }) return render(request, 'adminBuildBot/configuracao.html', context)
class PygmentsHighlighter(QtGui.QSyntaxHighlighter): """ Syntax highlighter that uses Pygments for parsing. """ style = DefaultStyle # Could be MonokaiStyle, FriendlyStyle, etc. def __init__(self, parent, lexer=None): super(PygmentsHighlighter, self).__init__(parent) try: self._lexer = get_lexer_by_name(lexer) except: self._lexer = PythonLexer() # Caches for formats and brushes. self._brushes = {} self._formats = {} @handle_exception_in_method def highlightBlock(self, qstring): """ Highlight a block of text. """ qstring = compat.unicode(qstring) prev_data = self.previous_block_data() if prev_data is not None: self._lexer._epd_state_stack = prev_data.syntax_stack elif hasattr(self._lexer, '_epd_state_stack'): del self._lexer._epd_state_stack index = 0 # Lex the text using Pygments for token, text in self._lexer.get_tokens(qstring): l = len(text) format = self._get_format(token) if format is not None: self.setFormat(index, l, format) index += l if hasattr(self._lexer, '_epd_state_stack'): data = BlockUserData(syntax_stack=self._lexer._epd_state_stack) self.currentBlock().setUserData(data) # there is a bug in pyside and it will crash unless we # hold on to the reference a little longer data = self.currentBlock().userData() # Clean up for the next go-round. del self._lexer._epd_state_stack def previous_block_data(self): """ Convenience method for returning the previous block's user data. """ return self.currentBlock().previous().userData() def _get_format(self, token): """ Returns a QTextCharFormat for token or None. """ if token in self._formats: return self._formats[token] result = None for key, value in self.style.style_for_token(token) .items(): if value: if result is None: result = QtGui.QTextCharFormat() if key == 'color': result.setForeground(self._get_brush(value)) elif key == 'bgcolor': result.setBackground(self._get_brush(value)) elif key == 'bold': result.setFontWeight(QtGui.QFont.Bold) elif key == 'italic': result.setFontItalic(True) elif key == 'underline': result.setUnderlineStyle( QtGui.QTextCharFormat.SingleUnderline) elif key == 'sans': result.setFontStyleHint(QtGui.QFont.SansSerif) elif key == 'roman': result.setFontStyleHint(QtGui.QFont.Times) elif key == 'mono': result.setFontStyleHint(QtGui.QFont.TypeWriter) elif key == 'border': # Borders are normally used for errors. We can't do a border # so instead we do a wavy underline result.setUnderlineStyle( QtGui.QTextCharFormat.WaveUnderline) result.setUnderlineColor(self._get_color(value)) self._formats[token] = result return result def _get_brush(self, color): """ Returns a brush for the color. """ result = self._brushes.get(color) if result is None: qcolor = self._get_color(color) result = QtGui.QBrush(qcolor) self._brushes[color] = result return result def _get_color(self, color): qcolor = QtGui.QColor() qcolor.setRgb(int(color[:2], base=16), int(color[2:4], base=16), int(color[4:6], base=16)) return qcolor
def _lex_python_result(tb): " Return token list for Python string. " lexer = PythonLexer() return lexer.get_tokens(tb)
def setUp(self): self.lexer = PythonLexer()
def get_tokens_unprocessed(self, text): for index, token, value in PythonLexer.get_tokens_unprocessed(self, text): if index==self.offset-1: # need to shift by 1 yield index, Error, value else: yield index, token, value
class Console(QTextEdit): running = pyqtSignal() running_done = pyqtSignal() @property def doc(self): return self.document() @property def cursor(self): return self.textCursor() @property def root_frame(self): return self.doc.rootFrame() def unhandled_exception(self, type, value, tb): if type == KeyboardInterrupt: return try: sio = StringIO.StringIO() traceback.print_exception(type, value, tb, file=sio) fe = sio.getvalue() prints(fe) try: val = unicode(value) except: val = repr(value) msg = '<b>%s</b>:'%type.__name__ + val error_dialog(self, _('ERROR: Unhandled exception'), msg, det_msg=fe, show=True) except BaseException: pass def __init__(self, prompt='>>> ', continuation='... ', parent=None): QTextEdit.__init__(self, parent) self.shutting_down = False self.compiler = CommandCompiler() self.buf = self.old_buf = [] self.history = History([''], dynamic.get('console_history', [])) self.prompt_frame = None self.allow_output = False self.prompt_frame_format = QTextFrameFormat() self.prompt_frame_format.setBorder(1) self.prompt_frame_format.setBorderStyle(QTextFrameFormat.BorderStyle_Solid) self.prompt_len = len(prompt) self.doc.setMaximumBlockCount(int(prefs['scrollback'])) self.lexer = PythonLexer(ensurenl=False) self.tb_lexer = PythonTracebackLexer() self.context_menu = cm = QMenu(self) # {{{ cm.theme = ThemeMenu(cm) # }}} self.formatter = Formatter(prompt, continuation, style=prefs['theme']) p = QPalette() p.setColor(p.Base, QColor(self.formatter.background_color)) p.setColor(p.Text, QColor(self.formatter.color)) self.setPalette(p) self.key_dispatcher = { # {{{ Qt.Key_Enter : self.enter_pressed, Qt.Key_Return : self.enter_pressed, Qt.Key_Up : self.up_pressed, Qt.Key_Down : self.down_pressed, Qt.Key_Home : self.home_pressed, Qt.Key_End : self.end_pressed, Qt.Key_Left : self.left_pressed, Qt.Key_Right : self.right_pressed, Qt.Key_Backspace : self.backspace_pressed, Qt.Key_Delete : self.delete_pressed, } # }}} motd = textwrap.dedent('''\ # Python {0} # {1} {2} '''.format(sys.version.splitlines()[0], __appname__, __version__)) sys.excepthook = self.unhandled_exception self.controllers = [] QTimer.singleShot(0, self.launch_controller) with EditBlock(self.cursor): self.render_block(motd) def shutdown(self): dynamic.set('console_history', self.history.serialize()) self.shutting_down = True for c in self.controllers: c.kill() def contextMenuEvent(self, event): self.context_menu.popup(event.globalPos()) event.accept() # Controller management {{{ @property def controller(self): return self.controllers[-1] def no_controller_error(self): error_dialog(self, _('No interpreter'), _('No active interpreter found. Try restarting the' ' console'), show=True) def launch_controller(self, *args): c = Controller(self) c.write_output.connect(self.show_output, type=Qt.QueuedConnection) c.show_error.connect(self.show_error, type=Qt.QueuedConnection) c.interpreter_died.connect(self.interpreter_died, type=Qt.QueuedConnection) c.interpreter_done.connect(self.execution_done) self.controllers.append(c) def interpreter_died(self, controller, returncode): if not self.shutting_down and controller.current_command is not None: error_dialog(self, _('Interpreter died'), _('Interpreter dies while executing a command. To see ' 'the command, click Show details'), det_msg=controller.current_command, show=True) def execute(self, prompt_lines): c = self.root_frame.lastCursorPosition() self.setTextCursor(c) self.old_prompt_frame = self.prompt_frame self.prompt_frame = None self.old_buf = self.buf self.buf = [] self.running.emit() self.controller.runsource('\n'.join(prompt_lines)) def execution_done(self, controller, ret): if controller is self.controller: self.running_done.emit() if ret: # Incomplete command self.buf = self.old_buf self.prompt_frame = self.old_prompt_frame c = self.prompt_frame.lastCursorPosition() c.insertBlock() self.setTextCursor(c) else: # Command completed try: self.old_prompt_frame.setFrameFormat(QTextFrameFormat()) except RuntimeError: # Happens if enough lines of output that the old # frame was deleted pass self.render_current_prompt() # }}} # Prompt management {{{ @dynamic_property def cursor_pos(self): doc = ''' The cursor position in the prompt has the form (row, col). row starts at 0 for the first line col is 0 if the cursor is at the start of the line, 1 if it is after the first character, n if it is after the nth char. ''' def fget(self): if self.prompt_frame is not None: pos = self.cursor.position() it = self.prompt_frame.begin() lineno = 0 while not it.atEnd(): bl = it.currentBlock() if bl.contains(pos): return (lineno, pos - bl.position()) it += 1 lineno += 1 return (-1, -1) def fset(self, val): row, col = val if self.prompt_frame is not None: it = self.prompt_frame.begin() lineno = 0 while not it.atEnd(): if lineno == row: c = self.cursor c.setPosition(it.currentBlock().position()) c.movePosition(c.NextCharacter, n=col) self.setTextCursor(c) break it += 1 lineno += 1 return property(fget=fget, fset=fset, doc=doc) def move_cursor_to_prompt(self): if self.prompt_frame is not None and self.cursor_pos[0] < 0: c = self.prompt_frame.lastCursorPosition() self.setTextCursor(c) def prompt(self, strip_prompt_strings=True): if not self.prompt_frame: yield u'' if strip_prompt_strings else self.formatter.prompt else: it = self.prompt_frame.begin() while not it.atEnd(): bl = it.currentBlock() t = unicode(bl.text()) if strip_prompt_strings: t = t[self.prompt_len:] yield t it += 1 def set_prompt(self, lines): self.render_current_prompt(lines) def clear_current_prompt(self): if self.prompt_frame is None: c = self.root_frame.lastCursorPosition() self.prompt_frame = c.insertFrame(self.prompt_frame_format) self.setTextCursor(c) else: c = self.prompt_frame.firstCursorPosition() self.setTextCursor(c) c.setPosition(self.prompt_frame.lastPosition(), c.KeepAnchor) c.removeSelectedText() c.setPosition(self.prompt_frame.firstPosition()) def render_current_prompt(self, lines=None, restore_cursor=False): row, col = self.cursor_pos cp = list(self.prompt()) if lines is None else lines self.clear_current_prompt() for i, line in enumerate(cp): start = i == 0 end = i == len(cp) - 1 self.formatter.render_prompt(not start, self.cursor) self.formatter.render(self.lexer.get_tokens(line), self.cursor) if not end: self.cursor.insertBlock() if row > -1 and restore_cursor: self.cursor_pos = (row, col) self.ensureCursorVisible() # }}} # Non-prompt Rendering {{{ def render_block(self, text, restore_prompt=True): self.formatter.render(self.lexer.get_tokens(text), self.cursor) self.cursor.insertBlock() self.cursor.movePosition(self.cursor.End) if restore_prompt: self.render_current_prompt() def show_error(self, is_syntax_err, tb, controller=None): if self.prompt_frame is not None: # At a prompt, so redirect output return prints(tb, end='') try: self.buf.append(tb) if is_syntax_err: self.formatter.render_syntax_error(tb, self.cursor) else: self.formatter.render(self.tb_lexer.get_tokens(tb), self.cursor) except: prints(tb, end='') self.ensureCursorVisible() QApplication.processEvents() def show_output(self, raw, which='stdout', controller=None): def do_show(): try: self.buf.append(raw) self.formatter.render_raw(raw, self.cursor) except: import traceback prints(traceback.format_exc()) prints(raw, end='') if self.prompt_frame is not None: with Prepender(self): do_show() else: do_show() self.ensureCursorVisible() QApplication.processEvents() # }}} # Keyboard management {{{ def keyPressEvent(self, ev): text = unicode(ev.text()) key = ev.key() action = self.key_dispatcher.get(key, None) if callable(action): action() elif key in (Qt.Key_Escape,): QTextEdit.keyPressEvent(self, ev) elif text: self.text_typed(text) else: QTextEdit.keyPressEvent(self, ev) def left_pressed(self): lineno, pos = self.cursor_pos if lineno < 0: return if pos > self.prompt_len: c = self.cursor c.movePosition(c.PreviousCharacter) self.setTextCursor(c) elif lineno > 0: c = self.cursor c.movePosition(c.Up) c.movePosition(c.EndOfLine) self.setTextCursor(c) self.ensureCursorVisible() def up_pressed(self): lineno, pos = self.cursor_pos if lineno < 0: return if lineno == 0: b = self.history.back() if b is not None: self.set_prompt(b) else: c = self.cursor c.movePosition(c.Up) self.setTextCursor(c) self.ensureCursorVisible() def backspace_pressed(self): lineno, pos = self.cursor_pos if lineno < 0: return if pos > self.prompt_len: self.cursor.deletePreviousChar() elif lineno > 0: c = self.cursor c.movePosition(c.Up) c.movePosition(c.EndOfLine) self.setTextCursor(c) self.ensureCursorVisible() def delete_pressed(self): self.cursor.deleteChar() self.ensureCursorVisible() def right_pressed(self): lineno, pos = self.cursor_pos if lineno < 0: return c = self.cursor cp = list(self.prompt(False)) if pos < len(cp[lineno]): c.movePosition(c.NextCharacter) elif lineno < len(cp)-1: c.movePosition(c.NextCharacter, n=1+self.prompt_len) self.setTextCursor(c) self.ensureCursorVisible() def down_pressed(self): lineno, pos = self.cursor_pos if lineno < 0: return c = self.cursor cp = list(self.prompt(False)) if lineno >= len(cp) - 1: b = self.history.forward() if b is not None: self.set_prompt(b) else: c = self.cursor c.movePosition(c.Down) self.setTextCursor(c) self.ensureCursorVisible() def home_pressed(self): if self.prompt_frame is not None: mods = QApplication.keyboardModifiers() ctrl = bool(int(mods & Qt.CTRL)) if ctrl: self.cursor_pos = (0, self.prompt_len) else: c = self.cursor c.movePosition(c.StartOfLine) c.movePosition(c.NextCharacter, n=self.prompt_len) self.setTextCursor(c) self.ensureCursorVisible() def end_pressed(self): if self.prompt_frame is not None: mods = QApplication.keyboardModifiers() ctrl = bool(int(mods & Qt.CTRL)) if ctrl: self.cursor_pos = (len(list(self.prompt()))-1, self.prompt_len) c = self.cursor c.movePosition(c.EndOfLine) self.setTextCursor(c) self.ensureCursorVisible() def enter_pressed(self): if self.prompt_frame is None: return if not self.controller.is_alive: return self.no_controller_error() cp = list(self.prompt()) if cp[0]: try: ret = self.compiler('\n'.join(cp)) except: pass else: if ret is None: c = self.prompt_frame.lastCursorPosition() c.insertBlock() self.setTextCursor(c) self.render_current_prompt() return else: self.history.enter(cp) self.execute(cp) def text_typed(self, text): if self.prompt_frame is not None: self.move_cursor_to_prompt() self.cursor.insertText(text) self.render_current_prompt(restore_cursor=True) self.history.current = list(self.prompt())
def __init__(self, **options): PythonLexer.__init__(self, **options)