summaryrefslogtreecommitdiff
path: root/python/examples/snippets/QCodeEditor.py
diff options
context:
space:
mode:
authorXusheng <xusheng@vector35.com>2021-07-01 12:34:30 +0800
committerXusheng Li <xushengli@protonmail.com>2021-07-05 10:11:47 +0800
commit13ff200ba134b8704f37eca99c42b70dab0d17dc (patch)
tree876b3db3c53f704b31152aeaede1f2edc9d27b24 /python/examples/snippets/QCodeEditor.py
parent4039a800349dcd587833d3e27d9137e4649818f4 (diff)
Remove snippet and kaitai plugin. Note their individual links.
Diffstat (limited to 'python/examples/snippets/QCodeEditor.py')
-rw-r--r--python/examples/snippets/QCodeEditor.py379
1 files changed, 0 insertions, 379 deletions
diff --git a/python/examples/snippets/QCodeEditor.py b/python/examples/snippets/QCodeEditor.py
deleted file mode 100644
index 7b0c0e09..00000000
--- a/python/examples/snippets/QCodeEditor.py
+++ /dev/null
@@ -1,379 +0,0 @@
-#!/usr/bin/env python2
-# -*- coding: utf-8 -*-
-'''
-Licensed under the terms of the MIT License
-https://github.com/luchko/QCodeEditor
-@author: Ivan Luchko (luchko.ivan@gmail.com)
-
-Python Highlighting added by:
-https://github.com/unihernandez22/QCodeEditor
-@author: unihernandez22
-
-Adapted to Binary Ninja by:
-@author: Jordan Wiens (https://github.com/psifertex)
-
-Integrating syntax highlighting from:
-https://wiki.python.org/moin/PyQt/Python%20syntax%20highlighting
-Released under the Modified BSD License: http://directory.fsf.org/wiki/License:BSD_3Clause
-
-Note that this will not be merged back to the parent repositories as it's been
-modified to be heavily dependent on the BN theme system.
-'''
-
-from PySide2.QtCore import Qt, QRect, QRegExp
-from PySide2.QtWidgets import QWidget, QTextEdit, QPlainTextEdit
-from PySide2.QtGui import (QPainter, QFont, QSyntaxHighlighter, QTextFormat, QTextCharFormat)
-from binaryninjaui import (getMonospaceFont, getThemeColor, ThemeColor)
-
-
-def format(color, style=''):
- """Return a QTextCharFormat with the given attributes."""
- _color = eval('getThemeColor(ThemeColor.%s)' % color)
-
- _format = QTextCharFormat()
- _format.setForeground(_color)
- if 'bold' in style:
- _format.setFontWeight(QFont.Bold)
- if 'italic' in style:
- _format.setFontItalic(True)
-
- return _format
-
-STYLES = {
- 'keyword': format('StackVariableColor'),
- 'operator': format('TokenHighlightColor'),
- 'brace': format('LinearDisassemblySeparatorColor'),
- 'defclass': format('DataSymbolColor'),
- 'string': format('StringColor'),
- 'string2': format('TypeNameColor'),
- 'comment': format('AnnotationColor', 'italic'),
- 'self': format('KeywordColor', 'italic'),
- 'numbers': format('NumberColor'),
- 'numberbar': getThemeColor(ThemeColor.BackgroundHighlightDarkColor),
- 'blockselected': getThemeColor(ThemeColor.TokenHighlightColor),
- 'blocknormal': getThemeColor(ThemeColor.TokenSelectionColor)
-}
-
-class PythonHighlighter (QSyntaxHighlighter):
- """Syntax highlighter for the Python language.
- """
- # Python keywords
- keywords = [
- 'and', 'assert', 'break', 'class', 'continue', 'def',
- 'del', 'elif', 'else', 'except', 'exec', 'finally',
- 'for', 'from', 'global', 'if', 'import', 'in',
- 'is', 'lambda', 'not', 'or', 'pass', 'print',
- 'raise', 'return', 'try', 'while', 'yield',
- 'None', 'True', 'False',
- ]
-
- # Python operators
- operators = [
- '=',
- # Comparison
- '==', '!=', '<', '<=', '>', '>=',
- # Arithmetic
- '\+', '-', '\*', '/', '//', '\%', '\*\*',
- # In-place
- '\+=', '-=', '\*=', '/=', '\%=',
- # Bitwise
- '\^', '\|', '\&', '\~', '>>', '<<',
- ]
-
- # Python braces
- braces = [
- '\{', '\}', '\(', '\)', '\[', '\]',
- ]
- def __init__(self, document):
- QSyntaxHighlighter.__init__(self, document)
-
- # Multi-line strings (expression, flag, style)
- # FIXME: The triple-quotes in these two lines will mess up the
- # syntax highlighting from this point onward
- self.tri_single = (QRegExp("'''"), 1, STYLES['string2'])
- self.tri_double = (QRegExp('"""'), 2, STYLES['string2'])
-
- rules = []
-
- # Keyword, operator, and brace rules
- rules += [(r'\b%s\b' % w, 0, STYLES['keyword'])
- for w in PythonHighlighter.keywords]
- rules += [(r'%s' % o, 0, STYLES['operator'])
- for o in PythonHighlighter.operators]
- rules += [(r'%s' % b, 0, STYLES['brace'])
- for b in PythonHighlighter.braces]
-
- # All other rules
- rules += [
- # 'self'
- (r'\bself\b', 0, STYLES['self']),
-
- # Double-quoted string, possibly containing escape sequences
- (r'"[^"\\]*(\\.[^"\\]*)*"', 0, STYLES['string']),
- # Single-quoted string, possibly containing escape sequences
- (r"'[^'\\]*(\\.[^'\\]*)*'", 0, STYLES['string']),
-
- # 'def' followed by an identifier
- (r'\bdef\b\s*(\w+)', 1, STYLES['defclass']),
- # 'class' followed by an identifier
- (r'\bclass\b\s*(\w+)', 1, STYLES['defclass']),
-
- # From '#' until a newline
- (r'#[^\n]*', 0, STYLES['comment']),
-
- # Numeric literals
- (r'\b[+-]?[0-9]+[lL]?\b', 0, STYLES['numbers']),
- (r'\b[+-]?0[xX][0-9A-Fa-f]+[lL]?\b', 0, STYLES['numbers']),
- (r'\b[+-]?[0-9]+(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\b', 0, STYLES['numbers']),
- ]
-
- # Build a QRegExp for each pattern
- self.rules = [(QRegExp(pat), index, fmt)
- for (pat, index, fmt) in rules]
-
-
- def highlightBlock(self, text):
- """Apply syntax highlighting to the given block of text.
- """
- # Do other syntax formatting
- for expression, nth, format in self.rules:
- index = expression.indexIn(text, 0)
-
- while index >= 0:
- # We actually want the index of the nth match
- index = expression.pos(nth)
- length = len(expression.cap(nth))
- self.setFormat(index, length, format)
- index = expression.indexIn(text, index + length)
-
- self.setCurrentBlockState(0)
-
- # Do multi-line strings
- in_multiline = self.match_multiline(text, *self.tri_single)
- if not in_multiline:
- in_multiline = self.match_multiline(text, *self.tri_double)
-
-
- def match_multiline(self, text, delimiter, in_state, style):
- """Do highlighting of multi-line strings. ``delimiter`` should be a
- ``QRegExp`` for triple-single-quotes or triple-double-quotes, and
- ``in_state`` should be a unique integer to represent the corresponding
- state changes when inside those strings. Returns True if we're still
- inside a multi-line string when this function is finished.
- """
- # If inside triple-single quotes, start at 0
- if self.previousBlockState() == in_state:
- start = 0
- add = 0
- # Otherwise, look for the delimiter on this line
- else:
- start = delimiter.indexIn(text)
- # Move past this match
- add = delimiter.matchedLength()
-
- # As long as there's a delimiter match on this line...
- while start >= 0:
- # Look for the ending delimiter
- end = delimiter.indexIn(text, start + add)
- # Ending delimiter on this line?
- if end >= add:
- length = end - start + add + delimiter.matchedLength()
- self.setCurrentBlockState(0)
- # No; multi-line string
- else:
- self.setCurrentBlockState(in_state)
- length = len(text) - start + add
- # Apply formatting
- self.setFormat(start, length, style)
- # Look for the next match
- start = delimiter.indexIn(text, start + length)
-
- # Return True if still inside a multi-line string, False otherwise
- if self.currentBlockState() == in_state:
- return True
- else:
- return False
-
-
-class QCodeEditor(QPlainTextEdit):
- '''
- QCodeEditor inherited from QPlainTextEdit providing:
-
- numberBar - set by DISPLAY_LINE_NUMBERS flag equals True
- curent line highligthing - set by HIGHLIGHT_CURRENT_LINE flag equals True
- setting up QSyntaxHighlighter
-
- references:
- https://john.nachtimwald.com/2009/08/19/better-qplaintextedit-with-line-numbers/
- http://doc.qt.io/qt-5/qtwidgets-widgets-codeeditor-example.html
-
- '''
- class NumberBar(QWidget):
- '''class that deifnes textEditor numberBar'''
-
- def __init__(self, editor):
- QWidget.__init__(self, editor)
-
- self.editor = editor
- self.editor.blockCountChanged.connect(self.updateWidth)
- self.editor.updateRequest.connect(self.updateContents)
- self.font = QFont()
- self.numberBarColor = STYLES["numberbar"]
-
- def paintEvent(self, event):
-
- painter = QPainter(self)
- painter.fillRect(event.rect(), self.numberBarColor)
-
- block = self.editor.firstVisibleBlock()
-
- # Iterate over all visible text blocks in the document.
- while block.isValid():
- blockNumber = block.blockNumber()
- block_top = self.editor.blockBoundingGeometry(block).translated(self.editor.contentOffset()).top()
-
- # Check if the position of the block is out side of the visible area.
- if not block.isVisible() or block_top >= event.rect().bottom():
- break
-
- # We want the line number for the selected line to be bold.
- if blockNumber == self.editor.textCursor().blockNumber():
- self.font.setBold(True)
- painter.setPen(STYLES["blockselected"])
- else:
- self.font.setBold(False)
- painter.setPen(STYLES["blocknormal"])
- painter.setFont(self.font)
-
- # Draw the line number right justified at the position of the line.
- paint_rect = QRect(0, block_top, self.width(), self.editor.fontMetrics().height())
- painter.drawText(paint_rect, Qt.AlignLeft, str(blockNumber+1))
-
- block = block.next()
-
- painter.end()
-
- QWidget.paintEvent(self, event)
-
- def getWidth(self):
- count = self.editor.blockCount()
- width = self.fontMetrics().width(str(count)) + 10
- return width
-
- def updateWidth(self):
- width = self.getWidth()
- if self.width() != width:
- self.setFixedWidth(width)
- self.editor.setViewportMargins(width, 0, 0, 0);
-
- def updateContents(self, rect, scroll):
- if scroll:
- self.scroll(0, scroll)
- else:
- self.update(0, rect.y(), self.width(), rect.height())
-
- if rect.contains(self.editor.viewport().rect()):
- fontSize = self.editor.currentCharFormat().font().pointSize()
- self.font.setPointSize(fontSize)
- self.font.setStyle(QFont.StyleNormal)
- self.updateWidth()
-
-
- def __init__(self, DISPLAY_LINE_NUMBERS=True, HIGHLIGHT_CURRENT_LINE=True,
- SyntaxHighlighter=None, *args):
- '''
- Parameters
- ----------
- DISPLAY_LINE_NUMBERS : bool
- switch on/off the presence of the lines number bar
- HIGHLIGHT_CURRENT_LINE : bool
- switch on/off the current line highliting
- SyntaxHighlighter : QSyntaxHighlighter
- should be inherited from QSyntaxHighlighter
-
- '''
- super(QCodeEditor, self).__init__()
-
- self.setFont(QFont("Ubuntu Mono", 11))
- self.setLineWrapMode(QPlainTextEdit.NoWrap)
-
- self.DISPLAY_LINE_NUMBERS = DISPLAY_LINE_NUMBERS
-
- if DISPLAY_LINE_NUMBERS:
- self.number_bar = self.NumberBar(self)
-
- if HIGHLIGHT_CURRENT_LINE:
- self.currentLineNumber = None
- self.currentLineColor = STYLES['currentLine']
- self.cursorPositionChanged.connect(self.highligtCurrentLine)
-
- if SyntaxHighlighter is not None: # add highlighter to textdocument
- self.highlighter = SyntaxHighlighter(self.document())
-
- def resizeEvent(self, *e):
- '''overload resizeEvent handler'''
-
- if self.DISPLAY_LINE_NUMBERS: # resize number_bar widget
- cr = self.contentsRect()
- rec = QRect(cr.left(), cr.top(), self.number_bar.getWidth(), cr.height())
- self.number_bar.setGeometry(rec)
-
- QPlainTextEdit.resizeEvent(self, *e)
-
- def highligtCurrentLine(self):
- newCurrentLineNumber = self.textCursor().blockNumber()
- if newCurrentLineNumber != self.currentLineNumber:
- self.currentLineNumber = newCurrentLineNumber
- hi_selection = QTextEdit.ExtraSelection()
- hi_selection.format.setBackground(self.currentLineColor)
- hi_selection.format.setProperty(QTextFormat.FullWidthSelection, True)
- hi_selection.cursor = self.textCursor()
- hi_selection.cursor.clearSelection()
- self.setExtraSelections([hi_selection])
-
-##############################################################################
-
-if __name__ == '__main__':
-
- # TESTING
-
- def run_test():
-
- from PySide2.QtGui import QApplication
- import sys
-
- app = QApplication([])
-
- editor = QCodeEditor(DISPLAY_LINE_NUMBERS=True,
- HIGHLIGHT_CURRENT_LINE=True,
- SyntaxHighlighter=PythonHighlighter)
-
-# text = '''<FINITELATTICE>
-# <LATTICE name="myLattice">
-# <BASIS>
-# <VECTOR>1.0 0.0 0.0</VECTOR>
-# <VECTOR>0.0 1.0 0.0</VECTOR>
-# </BASIS>
-# </LATTICE>
-# <PARAMETER name="L" />
-# <PARAMETER default="L" name="W" />
-# <EXTENT dimension="1" size="L" />
-# <EXTENT dimension="2" size="W" />
-# <BOUNDARY type="periodic" />
-# </FINITELATTICE>
-# '''
- text = """\
-def hello(text):
- print(text)
-
-hello('Hello World')
-
-# Comment"""
- editor.setPlainText(text)
- editor.resize(400,250)
- editor.show()
-
- sys.exit(app.exec_())
-
-
- run_test()