QScintilla Solidity custom syntax highlighter not working in Ubuntu
-
wrote on 14 Sept 2023, 23:30 last edited by
Hi!
I made a custom syntax highlighter for Solidity using QScintilla and the solidity lexer provided by pygments in Python.
It works perfectly in Windows, but I'm porting my app to Ubuntu and it throws an assertion error.
This is my code:
from PyQt6.Qsci import QsciLexerCustom from PyQt6.QtGui import QColor, QFont from pygments_lexer_solidity import SolidityLexer class CustomSolidityLexer(QsciLexerCustom): def __init__(self, parent): super().__init__(parent) # default text settings self.setDefaultColor(QColor("#ff000000")) self.setDefaultPaper(QColor("#ffffffff")) # define custom styles self._define_styles([QColor("#ff000000"),QColor("#ff7f0000"), QColor("#ff0000bf"), QColor("#ff007f00")]) self.token_style = { 'Token.Keyword' : 3, 'Token.Operator' : 2, 'Token.Keyword.Declaration' : 3, 'Token.Keyword.Type' : 2, 'Token.Name.Builtin' : 3, 'Token.Keyword.Constant' : 1, 'Token.Punctuation' : 1, 'Token.Name.Function' : 2, 'Token.Comment.Single' : 1 } def _define_styles(self, color_list): for i, color in enumerate(color_list): self.setColor(color, i) self.setPaper(QColor("#ffffffff"), i) self.setFont(self.parent().window_font) def language(self): return "Solidity" def description(self, style: int): if style == 0: return "Style_0" elif style == 1: return "Style_1" elif style == 2: return "Style_2" elif style == 3: return "Style_3" def styleText(self, start: int, end: int): lexer = SolidityLexer() self.startStyling(start) text = self.parent().text()[start:end] # tokenize the text token_list = lexer.get_tokens(text) token_list = [(token[0], token[1], len(bytearray(token[1], "utf-8"))) for token in token_list] # style text in a loop for token in token_list: try: self.setStyling(token[2], self.token_style[str(token[0])]) except: self.setStyling(token[2], 0)
And the exception is the following:
Thanks!!
-
Hi!
I made a custom syntax highlighter for Solidity using QScintilla and the solidity lexer provided by pygments in Python.
It works perfectly in Windows, but I'm porting my app to Ubuntu and it throws an assertion error.
This is my code:
from PyQt6.Qsci import QsciLexerCustom from PyQt6.QtGui import QColor, QFont from pygments_lexer_solidity import SolidityLexer class CustomSolidityLexer(QsciLexerCustom): def __init__(self, parent): super().__init__(parent) # default text settings self.setDefaultColor(QColor("#ff000000")) self.setDefaultPaper(QColor("#ffffffff")) # define custom styles self._define_styles([QColor("#ff000000"),QColor("#ff7f0000"), QColor("#ff0000bf"), QColor("#ff007f00")]) self.token_style = { 'Token.Keyword' : 3, 'Token.Operator' : 2, 'Token.Keyword.Declaration' : 3, 'Token.Keyword.Type' : 2, 'Token.Name.Builtin' : 3, 'Token.Keyword.Constant' : 1, 'Token.Punctuation' : 1, 'Token.Name.Function' : 2, 'Token.Comment.Single' : 1 } def _define_styles(self, color_list): for i, color in enumerate(color_list): self.setColor(color, i) self.setPaper(QColor("#ffffffff"), i) self.setFont(self.parent().window_font) def language(self): return "Solidity" def description(self, style: int): if style == 0: return "Style_0" elif style == 1: return "Style_1" elif style == 2: return "Style_2" elif style == 3: return "Style_3" def styleText(self, start: int, end: int): lexer = SolidityLexer() self.startStyling(start) text = self.parent().text()[start:end] # tokenize the text token_list = lexer.get_tokens(text) token_list = [(token[0], token[1], len(bytearray(token[1], "utf-8"))) for token in token_list] # style text in a loop for token in token_list: try: self.setStyling(token[2], self.token_style[str(token[0])]) except: self.setStyling(token[2], 0)
And the exception is the following:
Thanks!!
wrote on 14 Sept 2023, 23:36 last edited byI forgot to add, pygment lexer returns a tuple like (<<token type>>, <<token>>, <<token character length>>).
-
I forgot to add, pygment lexer returns a tuple like (<<token type>>, <<token>>, <<token character length>>).
Hi,
Can you provide the procedure you used to prepare your environment as well as a minimal script that triggers your issue ?
The code itself does not seem wrong per se.
-
Hi,
Can you provide the procedure you used to prepare your environment as well as a minimal script that triggers your issue ?
The code itself does not seem wrong per se.
-
Hi,
Can you provide the procedure you used to prepare your environment as well as a minimal script that triggers your issue ?
The code itself does not seem wrong per se.
wrote on 28 Sept 2023, 22:34 last edited byI'm sorry I took so long to answer.
I'm running it inside a virtual environment (venv) and installed requirements with a requirements.txt that in this case should be something like this: (extracted the dependencies that apply to the minimal script)
Pygments==2.15.1
pygments-lexer-solidity==0.7.0
pyparsing==3.1.0
PyQt6==6.4.0
PyQt6-QScintilla==2.13.3
PyQt6-Qt6==6.5.1
PyQt6-sip==13.5.1
QScintilla==2.13.3And a minimal script that triggers the issue would be this one:
import sys from PyQt6.QtWidgets import * from PyQt6.QtCore import * from PyQt6.QtGui import * from PyQt6.Qsci import * import re from pygments_lexer_solidity import SolidityLexer class CustomSolidityLexer(QsciLexerCustom): # insert class definition in the first post pass myCodeSample = r"""pragma solidity 0.8.0; contract Test { uint count = 0; address owner; constructor() public { owner = msg.sender; } }""" class CustomMainWindow(QMainWindow): def __init__(self): super(CustomMainWindow, self).__init__() self.setGeometry(300, 300, 800, 400) self.setWindowTitle("QScintilla Test") # 2. Create frame and layout # --------------------------- self.__frm = QFrame(self) self.__frm.setStyleSheet("QWidget { background-color: #ffeaeaea }") self.__lyt = QVBoxLayout() self.__frm.setLayout(self.__lyt) self.setCentralWidget(self.__frm) self.__myFont = QFont() self.__myFont.setPointSize(14) self.__editor = QsciScintilla() self.__editor.setText(myCodeSample) # 'myCodeSample' is a string containing some C-code self.__editor.setLexer(None) # We install lexer later self.__editor.setUtf8(True) # Set encoding to UTF-8 self.__editor.setFont(self.__myFont) # Gets overridden by lexer later on # 2. End-of-line mode # -------------------- self.__editor.setEolMode(QsciScintilla.EolMode.EolUnix) self.__editor.setEolVisibility(False) # 3. Indentation # --------------- self.__editor.setIndentationsUseTabs(False) self.__editor.setTabWidth(4) self.__editor.setIndentationGuides(True) self.__editor.setTabIndents(True) self.__editor.setAutoIndent(True) # 4. Caret # --------- self.__editor.setCaretForegroundColor(QColor("#ff0000ff")) self.__editor.setCaretLineVisible(True) self.__editor.setCaretLineBackgroundColor(QColor("#1f0000ff")) self.__editor.setCaretWidth(2) self.__editor.setMarginType(0, QsciScintilla.MarginType.NumberMargin) self.__editor.setMarginWidth(0, "0000") self.__editor.setMarginsForegroundColor(QColor("#ff888888")) self.__lexer = CustomSolidityLexer(self.__editor) self.__editor.setLexer(self.__lexer) self.__lyt.addWidget(self.__editor) self.show() if __name__ == '__main__': app = QApplication(sys.argv) myGUI = CustomMainWindow() sys.exit(app.exec())
-
I'm sorry I took so long to answer.
I'm running it inside a virtual environment (venv) and installed requirements with a requirements.txt that in this case should be something like this: (extracted the dependencies that apply to the minimal script)
Pygments==2.15.1
pygments-lexer-solidity==0.7.0
pyparsing==3.1.0
PyQt6==6.4.0
PyQt6-QScintilla==2.13.3
PyQt6-Qt6==6.5.1
PyQt6-sip==13.5.1
QScintilla==2.13.3And a minimal script that triggers the issue would be this one:
import sys from PyQt6.QtWidgets import * from PyQt6.QtCore import * from PyQt6.QtGui import * from PyQt6.Qsci import * import re from pygments_lexer_solidity import SolidityLexer class CustomSolidityLexer(QsciLexerCustom): # insert class definition in the first post pass myCodeSample = r"""pragma solidity 0.8.0; contract Test { uint count = 0; address owner; constructor() public { owner = msg.sender; } }""" class CustomMainWindow(QMainWindow): def __init__(self): super(CustomMainWindow, self).__init__() self.setGeometry(300, 300, 800, 400) self.setWindowTitle("QScintilla Test") # 2. Create frame and layout # --------------------------- self.__frm = QFrame(self) self.__frm.setStyleSheet("QWidget { background-color: #ffeaeaea }") self.__lyt = QVBoxLayout() self.__frm.setLayout(self.__lyt) self.setCentralWidget(self.__frm) self.__myFont = QFont() self.__myFont.setPointSize(14) self.__editor = QsciScintilla() self.__editor.setText(myCodeSample) # 'myCodeSample' is a string containing some C-code self.__editor.setLexer(None) # We install lexer later self.__editor.setUtf8(True) # Set encoding to UTF-8 self.__editor.setFont(self.__myFont) # Gets overridden by lexer later on # 2. End-of-line mode # -------------------- self.__editor.setEolMode(QsciScintilla.EolMode.EolUnix) self.__editor.setEolVisibility(False) # 3. Indentation # --------------- self.__editor.setIndentationsUseTabs(False) self.__editor.setTabWidth(4) self.__editor.setIndentationGuides(True) self.__editor.setTabIndents(True) self.__editor.setAutoIndent(True) # 4. Caret # --------- self.__editor.setCaretForegroundColor(QColor("#ff0000ff")) self.__editor.setCaretLineVisible(True) self.__editor.setCaretLineBackgroundColor(QColor("#1f0000ff")) self.__editor.setCaretWidth(2) self.__editor.setMarginType(0, QsciScintilla.MarginType.NumberMargin) self.__editor.setMarginWidth(0, "0000") self.__editor.setMarginsForegroundColor(QColor("#ff888888")) self.__lexer = CustomSolidityLexer(self.__editor) self.__editor.setLexer(self.__lexer) self.__lyt.addWidget(self.__editor) self.show() if __name__ == '__main__': app = QApplication(sys.argv) myGUI = CustomMainWindow() sys.exit(app.exec())
-
From the looks of it, the last entry of the token list is the one that makes the styling go past the end.
I would say don't style the last line feed.