Why doesn't my QsciLexerCustom subclass work in PyQt4 using QsciScintilla?

Posted by Jon Watte on Stack Overflow See other posts from Stack Overflow or by Jon Watte
Published on 2010-04-22T21:20:25Z Indexed on 2010/04/22 21:23 UTC
Read the original article Hit count: 278

Filed under:
|
|
|
|

My end goal is to get Erlang syntax highlighting in QsciScintilla using PyQt4 and Python 2.6. I'm running on Windows 7, but will also need Ubuntu support.

PyQt4 is missing the necessary wrapper code for the Erlang lexer/highlighter that "base" scintilla has, so I figured I'd write a lightweight one on top of QsciLexerCustom. It's a little bit problematic, because the Qsci wrapper seems to really want to talk about line+index rather than offset-from-start when getting/setting subranges of text. Meanwhile, the lexer gets arguments as offset-from-start. For now, I get a copy of the entire text, and split that up as appropriate.

I have the following lexer, and I apply it with setLexer(). It gets all the appropriate calls when I open a new file and sets this as the lexer, and prints a bunch of appropriate lines based on what it's doing... but there is no styling in the document. I tried making all the defined styles red, and the document is still stubbornly black-on-white, so apparently the styles don't really "take effect"

What am I doing wrong? If nobody here knows, what's the appropriate discussion forum where people might actually know these things? (It's an interesting intersection between Python, Qt and Scintilla, so I imagine the set of people who would know is small)

Let's assume prefs.declare() just sets up a dict that returns the value for the given key (I've verified this -- it's not the problem). Let's assume scintilla is reasonably properly constructed into its host window QWidget. Specifically, if I apply a bundled lexer (such as QsciLexerPython), it takes effect and does show styled text.

prefs.declare('font.name.margin', "MS Dlg")
prefs.declare('font.size.margin', 8)
prefs.declare('font.name.code', "Courier New")
prefs.declare('font.size.code', 10)
prefs.declare('color.editline', "#d0e0ff")

class LexerErlang(Qsci.QsciLexerCustom):
  def __init__(self, obj = None):
    Qsci.QsciLexerCustom.__init__(self, obj)
    self.sci = None
    self.plainFont = QtGui.QFont()
    self.plainFont.setPointSize(int(prefs.get('font.size.code')))
    self.plainFont.setFamily(prefs.get('font.name.code'))
    self.marginFont = QtGui.QFont()
    self.marginFont.setPointSize(int(prefs.get('font.size.code')))
    self.marginFont.setFamily(prefs.get('font.name.margin'))
    self.boldFont = QtGui.QFont()
    self.boldFont.setPointSize(int(prefs.get('font.size.code')))
    self.boldFont.setFamily(prefs.get('font.name.code'))
    self.boldFont.setBold(True)
    self.styles = [
      Qsci.QsciStyle(0, QtCore.QString("base"), QtGui.QColor("#000000"), QtGui.QColor("#ffffff"), self.plainFont, True),
      Qsci.QsciStyle(1, QtCore.QString("comment"), QtGui.QColor("#008000"), QtGui.QColor("#eeffee"), self.marginFont, True),
      Qsci.QsciStyle(2, QtCore.QString("keyword"), QtGui.QColor("#000080"), QtGui.QColor("#ffffff"), self.boldFont, True),
      Qsci.QsciStyle(3, QtCore.QString("string"), QtGui.QColor("#800000"), QtGui.QColor("#ffffff"), self.marginFont, True),
      Qsci.QsciStyle(4, QtCore.QString("atom"), QtGui.QColor("#008080"), QtGui.QColor("#ffffff"), self.plainFont, True),
      Qsci.QsciStyle(5, QtCore.QString("macro"), QtGui.QColor("#808000"), QtGui.QColor("#ffffff"), self.boldFont, True),
      Qsci.QsciStyle(6, QtCore.QString("error"), QtGui.QColor("#000000"), QtGui.QColor("#ffd0d0"), self.plainFont, True),
    ]
    print("LexerErlang created")
  def description(self, ix):
    for i in self.styles:
      if i.style() == ix:
        return QtCore.QString(i.description())
    return QtCore.QString("")
  def setEditor(self, sci):
    self.sci = sci
    Qsci.QsciLexerCustom.setEditor(self, sci)
    print("LexerErlang.setEditor()")
  def styleText(self, start, end):
    print("LexerErlang.styleText(%d,%d)" % (start, end))
    lines = self.getText(start, end)
    offset = start
    self.startStyling(offset, 0)
    print("startStyling()")
    for i in lines:
      if i == "":
        self.setStyling(1, self.styles[0])
        print("setStyling(1)")
        offset += 1
        continue
      if i[0] == '%':
        self.setStyling(len(i)+1, self.styles[1])
        print("setStyling(%)")
        offset += len(i)+1
        continue
      self.setStyling(len(i)+1, self.styles[0])
      print("setStyling(n)")
      offset += len(i)+1
  def getText(self, start, end):
    data = self.sci.text()
    print("LexerErlang.getText(): " + str(len(data)) + " chars")
    return data[start:end].split('\n')

Applied to the QsciScintilla widget as follows:

_lexers = { 'erl': (Q.SCLEX_ERLANG, LexerErlang), 'hrl': (Q.SCLEX_ERLANG, LexerErlang), 'html': (Q.SCLEX_HTML, Qsci.QsciLexerHTML), 'css': (Q.SCLEX_CSS, Qsci.QsciLexerCSS), 'py': (Q.SCLEX_PYTHON, Qsci.QsciLexerPython), 'php': (Q.SCLEX_PHP, Qsci.QsciLexerHTML), 'inc': (Q.SCLEX_PHP, Qsci.QsciLexerHTML), 'js': (Q.SCLEX_CPP, Qsci.QsciLexerJavaScript), 'cpp': (Q.SCLEX_CPP, Qsci.QsciLexerCPP), 'h': (Q.SCLEX_CPP, Qsci.QsciLexerCPP), 'cxx': (Q.SCLEX_CPP, Qsci.QsciLexerCPP), 'hpp': (Q.SCLEX_CPP, Qsci.QsciLexerCPP), 'c': (Q.SCLEX_CPP, Qsci.QsciLexerCPP), 'hxx': (Q.SCLEX_CPP, Qsci.QsciLexerCPP), 'tpl': (Q.SCLEX_CPP, Qsci.QsciLexerCPP), 'xml': (Q.SCLEX_XML, Qsci.QsciLexerXML), }

... inside my document window class ...

def addContentsDocument(self, contents, title): handler = self.makeScintilla() handler.title = title sci = handler.sci sci.append(contents) self.tabWidget.addTab(sci, title) self.tabWidget.setCurrentWidget(sci) self.applyLexer(sci, title) EventBus.bus.broadcast('command.done', {'text': 'Opened ' + title}) return handler

def applyLexer(self, sci, title): (language, lexer) = language_and_lexer_from_title(title) if lexer: l = lexer() print("making lexer: " + str(l)) sci.setLexer(l) else: print("setting lexer by id: " + str(language)) sci.SendScintilla(Qsci.QsciScintillaBase.SCI_SETLEXER, language) linst = sci.lexer() print("lexer: " + str(linst))

def makeScintilla(self): sci = Qsci.QsciScintilla() sci.setUtf8(True) sci.setTabIndents(True) sci.setIndentationsUseTabs(False) sci.setIndentationWidth(4) sci.setMarginsFont(self.smallFont) sci.setMarginWidth(0, self.smallFontMetrics.width('00000')) sci.setFont(self.monoFont) sci.setAutoIndent(True) sci.setBraceMatching(Qsci.QsciScintilla.StrictBraceMatch) handler = SciHandler(sci) self.handlers[sci] = handler sci.setMarginLineNumbers(0, True) sci.setCaretLineVisible(True) sci.setCaretLineBackgroundColor(QtGui.QColor(prefs.get('color.editline'))) return handler

Let's assume the rest of the application works, too (because it does :-)

© Stack Overflow or respective owner

Related posts about python

Related posts about pyqt4