Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QSyntaxHighlighter



  • Hi everyone,

    I have a problem with the syntax Highlighter. I saved the colours for highlighting and the user can change them in the settings while he is editing code. So I wrote a signal colorChanged() and a slot to change the colour for highlighting. The next time you change something in a certain line, the new colors will be applied. This works very well.

    Additionally I also want the complete file to be rehighlighted directly when the user changes the color. I found the "rehighlight()" slot in the QSyntaxHighlighter class. So I connected my colorChanged() signal to the rehighlight slot, but nothing happend (also no error warning). Same behaviour as before.

    I thought the rehighlight slot may got called before the applyColors slot. So I wrote a slot, which first applies the new colors and then rehighlights the whole document. This also didn't work.

    QObject::connect(settings, SIGNAL(colorChanged()), this, SLOT(changeColors()));
    
    void CppHighlighter::changeColors() {
      applyColors();
      rehighlight();
    }
    

    Did I missunderstood the rehighlight slot? Is this a bug? I'm using Qt 5.11


  • Lifetime Qt Champion

    Hi,

    Where do you emit the signal from ?
    How did you change the parameter that defines that ?
    Can you show the code related to handling the highlighting ?



  • Hi,

    I've used QSettings and one saved setting is for example the colour of macros (like #define).
    Here is the setter to set the color of the macro

    void ApplicationSettings::setMacros(const QColor& macros) {
      setValue("macros", macros);
      emit macrosChanged();
      emit colorChanged();
    }
    

    as you can see when one sets the colour for macros the colorChanged signal is emitted.
    You can access the settings in qml and also in every cpp file (as it is global and a context property).
    For example in qml I have designed a ColorPicker, which changes the color of the macros:

    Custom.FoldedColorPicker {
       color: settings.macros
       onClicked: settings.macros = color
     }
    

    Of course I have done the same for serveral other things, which should be highlighted.
    The Syntax Highlighter is implemented similar to the example from qt.
    In the constructor I define some Regular Expressions how the SyntaxHighlighter can find macros and I apply a color to them.

    QStringList macroPatterns;
        macroPatterns << "\\B#include\\b" << "\\B#define\\b" << "\\B#ifndef\\b"
                      << "\\B#endif\\b" << "\\B#if\\b";
        foreach (const QString& pattern, macroPatterns) {
          rule.pattern = QRegularExpression(pattern);
          rule.format = &macroFormat;
          highlightingRules.append(rule);
        }
    

    For the colors I have made a function applyColors()

    void CppHighlighter::applyColors() {
      macroFormat.setForeground(settings->property("macros").value<QColor>());
      ...
    }
    

    As rule.format is a reference to macroFormat, rule.format should be changed too.

    And I have as I said a slot called changeColors (in my Syntax Highlighter), which calls this function "applyColors()" and "rehighlight"

    void CppHighlighter::changeColors() {
      applyColors();
      qDebug() << "Test1" << '\n';
      rehighlight();
      qDebug() << "Test2" << '\n';
    }
    

    This slot is connected to the signal of settings in the constructor of the SyntaxHighlighter

    QObject::connect(settings, SIGNAL(colorChanged()), this, SLOT(changeColors()));
    

    For clarity: Except from the rehighlight() method/slot everything worked fine. So if you change a macro manually, the colour will be updated (because the highlight method is called as usually). I also used qDebug and my console showed Test1 and Test2, so rehighlight() is called.

    I also tried something like this:

    QObject::connect(settings, SIGNAL(colorChanged()), this, SLOT(changeColors()));
     QObject::connect(settings, SIGNAL(colorChanged()), this, SLOT(rehighlight()));
    

    It didn't worked.



  • I forgot to post the code for the highlight method.

    void CppHighlighter::highlightBlock(const QString &text) {
      foreach (const HighlightingRule &rule, highlightingRules) {
        QRegularExpressionMatchIterator matchIterator = rule.pattern.globalMatch(text);
        while (matchIterator.hasNext()) {
          QRegularExpressionMatch match = matchIterator.next();
          setFormat(match.capturedStart(), match.capturedLength(), *rule.format);
        }
      }
    }
    

    But as it worked perfectly, I don't expeect this method to be wrong.



  • I did some try and error and found out that my Syntax Highlighter works as exspected, but not the textArea.
    Here are some outputs

    "#define"
    
    QBrush(QColor(ARGB 1, 0.564706, 0.792157, 0.976471),SolidPattern)
    
    0
    
    7
    

    highlightBlock() is called with the text "#define". It detected the macro from position 0 to 7 and passed this together with the brush to setFormat()

    Rehighlight
    
    New Color:  QBrush(QColor(ARGB 1, 0.937255, 0.603922, 0.603922),SolidPattern)
    
    "#define"
    
    QBrush(QColor(ARGB 1, 0.937255, 0.603922, 0.603922),SolidPattern)
    
    0
    
    7
    
    Rehighlighted
    

    I changed the color. The syntax Highlighter calls the changeColor slot. The new color ist set and the highlightBlock method is called (through rehighlight()). Again the macro "#define is detected" and should be formatted with the new color from position 0 to 7.

    But when I look at my TextArea there has nothing changed. So I add one space.

    "#define "
    
    QBrush(QColor(ARGB 1, 0.937255, 0.603922, 0.603922),SolidPattern)
    
    0
    
    7
    
    

    And the color changes.

    So it seems to me like the text is formatted correctly, but TextArea does not update itself. I should mention that I have a swipeView and the settings are not on the same page as the textArea. So the textArea is not visible anymore while I change the color.

    By the way, I am using a TextArea from Qt Quick Controls 2. And I have done a custom DocumentHandler, which gets the text from the TextArea and creates the SyntaxHighlighter.

    Backend.DocumentHandler {
          id: documentHandler
          document: editor.textDocument
          onLoaded: {
            editor.text = text
          }
    }
    


  • I think my problem is a bug of qt. For some reason the TextArea does not get notified if the textDocument changes. Therefore it does not display the new color.
    Someone reported already the same issue:
    https://bugreports.qt.io/browse/QTBUG-65248
    Almost one year ago and still not solves?

    I found a patch for it, we need to emit the signal:

    void QAbstractTextDocumentLayout::updateBlock(const QTextBlock &block)
    

    This seems to notify the TextArea that something has changed. As we want to rehighlight the complete document, we need to emit the signal for every block. I wrote a simple for loop for it. Didn't find any nicer solution with iterators or a list of blocks and a for each loop. Simply put if after the call of rehighlight().

    void CppHighlighter::changeColors() {
      applyColors();
      rehighlight();
      for(int i = 0; i < document()->blockCount(); ++i) {
        emit document()->documentLayout()->updateBlock(document()->findBlockByNumber(i));
      }
    }
    

    Should I open a new bug report for it? The old one seems to be forgotten and the patch might be helpful for the developers.


  • Lifetime Qt Champion

    @Leon_2001 please comment on the original report. that way you get more attention. duplicate reports do not help. most developers already have 100 open reports and its easy to lose track.

    Note that the best way to get this fixed is sending the patch to Gerrit

    [edit: Fixed link SGaist]



  • Okay :) I commented on it. Hopefully this will solve this issue soon.

    I don't know Gerrit and the link you have provided does not work. Could you correct the link?


  • Lifetime Qt Champion

    Link has been fixed.

    You might also want to start here to see how it's done.



  • I will give it a try tomorrow ;)

    I want to use my chance to ask one further (general) questions to QSyntaxHighlighter.
    Can I use this class also to do things like auto-intendt or to close open (,{ automatically or for code completion? The highlight method seems pretty handy to me and it's probably possible to achieve this with QSyntaxHighligter.
    But as it is called SyntaxHighlighter and as names mostly have a meaning, I wonder if I should do this or use some other approach?


  • Lifetime Qt Champion

    I wouldn't mix that in. Single Responsibility is a key when developing classes.

    You might be interested in KDE's KTextEditor. They provide a complete pretty complete code editor that is used in e.g. Kate and KDevelop.



  • That's what I thought ;)

    Very good idea. Maybe I get some inspiration from this if the source code is not too heavy


Log in to reply