From 47ff0e99fc6a84496c1ab616cfb84cc9944646b0 Mon Sep 17 00:00:00 2001 From: Bruno Pedrosa Date: Thu, 24 May 2018 12:26:49 +0200 Subject: [PATCH] New example showing how to use lark+qscintilla (Issue #150) --- examples/examples-requirements.txt | 2 + examples/qscintilla_json.py | 218 +++++++++++++++++++++++++++++ 2 files changed, 220 insertions(+) create mode 100644 examples/examples-requirements.txt create mode 100644 examples/qscintilla_json.py diff --git a/examples/examples-requirements.txt b/examples/examples-requirements.txt new file mode 100644 index 0000000..8f93a87 --- /dev/null +++ b/examples/examples-requirements.txt @@ -0,0 +1,2 @@ +PyQt5==5.10.1 +QScintilla==2.10.4 \ No newline at end of file diff --git a/examples/qscintilla_json.py b/examples/qscintilla_json.py new file mode 100644 index 0000000..01ebf8b --- /dev/null +++ b/examples/qscintilla_json.py @@ -0,0 +1,218 @@ +import sys +import textwrap +import re + +from PyQt5.Qt import * # noqa + +from PyQt5.Qsci import QsciScintilla +from PyQt5.Qsci import QsciLexerCustom + +from editor import Editor + +from lark import Lark, inline_args, Transformer + + +class LexerJson(QsciLexerCustom): + + def __init__(self, parent=None): + super().__init__(parent) + self.create_grammar() + self.create_styles() + + def create_styles(self): + deeppink = QColor(249, 38, 114) + khaki = QColor(230, 219, 116) + mediumpurple = QColor(174, 129, 255) + mediumturquoise = QColor(81, 217, 205) + yellowgreen = QColor(166, 226, 46) + lightcyan = QColor(213, 248, 232) + darkslategrey = QColor(39, 40, 34) + + styles = { + 0: mediumturquoise, + 1: mediumpurple, + 2: yellowgreen, + 3: deeppink, + 4: khaki, + 5: lightcyan + } + + for style, color in styles.items(): + self.setColor(color, style) + self.setPaper(darkslategrey, style) + self.setFont(self.parent().font(), style) + + self.token_styles = { + "__COLON": 5, + "__COMMA": 5, + "__FALSE1": 0, + "__LBRACE": 5, + "__LSQB": 5, + "__NULL2": 0, + "__RBRACE": 5, + "__RSQB": 5, + "__TRUE0": 0, + "ESCAPED_STRING": 4, + "SIGNED_NUMBER": 1, + } + + def create_grammar(self): + grammar = ''' + ?start: value + ?value: object + | array + | string + | SIGNED_NUMBER -> number + | "true" -> true + | "false" -> false + | "null" -> null + array : "[" [value ("," value)*] "]" + object : "{" [pair ("," pair)*] "}" + pair : string ":" value + string : ESCAPED_STRING + %import common.ESCAPED_STRING + %import common.SIGNED_NUMBER + %import common.WS + %ignore WS + ''' + + class TreeToJson(Transformer): + @inline_args + def string(self, s): + return s[1:-1].replace('\\"', '"') + + array = list + pair = tuple + object = dict + number = inline_args(float) + + def null(self, _): return None + + def true(self, _): return True + + def false(self, _): return False + + self.lark = Lark(grammar, parser='lalr', transformer=TreeToJson()) + # All tokens: print([t.name for t in self.lark.parser.lexer.tokens]) + + def defaultPaper(self, style): + return QColor(39, 40, 34) + + def language(self): + return "Json" + + def description(self, style): + return {v: k for k, v in self.token_styles.items()}.get(style, "") + + def styleText(self, start, end): + self.startStyling(start) + text = self.parent().text()[start:end] + last_pos = 0 + + try: + for token in self.lark.lex(text): + ws_len = token.pos_in_stream - last_pos + if ws_len: + self.setStyling(ws_len, 0) # whitespace + + token_len = len(bytearray(token, "utf-8")) + self.setStyling( + token_len, self.token_styles.get(token.type, 0)) + + last_pos = token.pos_in_stream + token_len + except Exception as e: + print(e) + + +class EditorAll(QsciScintilla): + + def __init__(self, parent=None): + super().__init__(parent) + + # Set font defaults + font = QFont() + font.setFamily('Consolas') + font.setFixedPitch(True) + font.setPointSize(8) + font.setBold(True) + self.setFont(font) + + # Set margin defaults + fontmetrics = QFontMetrics(font) + self.setMarginsFont(font) + self.setMarginWidth(0, fontmetrics.width("000") + 6) + self.setMarginLineNumbers(0, True) + self.setMarginsForegroundColor(QColor(128, 128, 128)) + self.setMarginsBackgroundColor(QColor(39, 40, 34)) + self.setMarginType(1, self.SymbolMargin) + self.setMarginWidth(1, 12) + + # Set indentation defaults + self.setIndentationsUseTabs(False) + self.setIndentationWidth(4) + self.setBackspaceUnindents(True) + self.setIndentationGuides(True) + + # self.setFolding(QsciScintilla.CircledFoldStyle) + + # Set caret defaults + self.setCaretForegroundColor(QColor(247, 247, 241)) + self.setCaretWidth(2) + + # Set selection color defaults + self.setSelectionBackgroundColor(QColor(61, 61, 52)) + self.resetSelectionForegroundColor() + + # Set multiselection defaults + self.SendScintilla(QsciScintilla.SCI_SETMULTIPLESELECTION, True) + self.SendScintilla(QsciScintilla.SCI_SETMULTIPASTE, 1) + self.SendScintilla( + QsciScintilla.SCI_SETADDITIONALSELECTIONTYPING, True) + + lexer = LexerJson(self) + self.setLexer(lexer) + + +def main(): + app = QApplication(sys.argv) + ex = EditorAll() + ex.setWindowTitle(__file__) + ex.setText(textwrap.dedent("""\ + { + "_id": "5b05ffcbcf8e597939b3f5ca", + "about": "Excepteur consequat commodo esse voluptate aute aliquip ad sint deserunt commodo eiusmod irure. Sint aliquip sit magna duis eu est culpa aliqua excepteur ut tempor nulla. Aliqua ex pariatur id labore sit. Quis sit ex aliqua veniam exercitation laboris anim adipisicing. Lorem nisi reprehenderit ullamco labore qui sit ut aliqua tempor consequat pariatur proident.", + "address": "665 Malbone Street, Thornport, Louisiana, 243", + "age": 23, + "balance": "$3,216.91", + "company": "BULLJUICE", + "email": "elisekelley@bulljuice.com", + "eyeColor": "brown", + "gender": "female", + "guid": "d3a6d865-0f64-4042-8a78-4f53de9b0707", + "index": 0, + "isActive": false, + "isActive2": true, + "latitude": -18.660714, + "longitude": -85.378048, + "name": "Elise Kelley", + "phone": "+1 (808) 543-3966", + "picture": "http://placehold.it/32x32", + "registered": "2017-09-30T03:47:40 -02:00", + "tags": [ + "et", + "nostrud", + "in", + "fugiat", + "incididunt", + "labore", + "nostrud" + ] + }\ + """)) + ex.resize(800, 600) + ex.show() + sys.exit(app.exec_()) + + +if __name__ == "__main__": + main()