LINUX.ORG.RU

[QsciScintilla]Проблема с отображением Кириллицы


0

1

Из научно-спортивного интереса осваиваю Qt и QsciScintilla в частности. Решил разработать подсветку синтаксиса для виртуального языка. И сразу возникла проблема следующего характера: если в качестве лексера для QsciScintilla указать собственный (производный от QsciLexerCustom), то подсветка синтаксиса при вводе кириллицы превращается в абсурд, если же использовать готовый, например QsciLexerCPP, то все стилизируется корректно.

#ifndef GMLSCILEXER_H
#define GMLSCILEXER_H

#include <QObject>

#include <Qsci/qsciscintilla.h>
#include <Qsci/qscilexercustom.h>
#include <QColor>
#include <QFont>

class GMLsciLexer : public QsciLexerCustom
{
    Q_OBJECT
public:
    explicit GMLsciLexer(QObject *parent = 0);
private:
    //! Возвращает название языка
    virtual const char * language() const;
    //! Цвета для стилей
    virtual QColor defaultColor(int style) const;
    //! Шрифты для стилей
    virtual QFont defaultFont(int style) const;
    //! Бакгроунд для стилей
    virtual QColor defaultPaper(int style) const;
    //! Разбор текста на стили
    virtual void styleText (int start, int end);
    //! Описание
    virtual QString description (int style) const;
    //! Подстветить комментарии
    bool comments (QString source, int start, int end);

    enum
    {
        Default = 0,
        Comment = 1,
        Binary  = 2,
        String  = 3,
        Keyword1 = 4,
        Keyword2 = 5,
        Keyword3 = 6,
        Keyword4 = 7,
        Const  = 8
    };

signals:
public slots:
};

#endif // GMLSCILEXER_H
#include "gmlscilexer.h"

GMLsciLexer::GMLsciLexer(QObject *parent) :
    QsciLexerCustom(parent)
{
}

const char * GMLsciLexer::language() const
{
    return "GML";
}

QColor GMLsciLexer::defaultColor(int style) const
{
    if (style == Comment)
    {
        return QColor(0x00,0x7f,0x00);
    }
    return QsciLexer::defaultColor(style);
}

QFont GMLsciLexer::defaultFont(int style) const
{
    QFont f;
    if (style == Comment)
    {
#if defined(Q_OS_WIN)
        f.setFamily("Comic Sans");
#else
        f.setFamily("Sans Serif");
#endif
        f.setItalic(true);
    }
    else
    {
        f = QsciLexer::defaultFont(style);
    }
    return f;
}

QColor GMLsciLexer::defaultPaper(int style) const
{
    if (style == Comment)
    {
        return QColor(0xff,0xff,0xff);
    }
    return QsciLexer::defaultPaper(style);
}

void GMLsciLexer::styleText(int start, int end)
{
    //editor() - функция из родительского класса.
    //Возвращает указатель на QsciScintilla
    if (!editor())
        return;
    QsciScintilla * editor = this->editor();
    QString source = editor->text();
    comments(source, start, end);
}

QString GMLsciLexer::description (int style) const
{
    switch (style)
    {
    case Comment:
        return "Comment";
    case Default:
        return "Default";
    }
    return QString(style);
}

bool GMLsciLexer::comments(QString source, int start, int end)
{
    int count = source.count("//");
    int style = Comment;
    int idxStart = start;
    int idxEnd = idxStart;
    //Обрабатываем каждый символ комментария
    for (int i = 0; i < count; i++)
    {
        idxStart = source.indexOf("//", idxStart);
        if (idxStart == -1)
            break;
#if defined(Q_WS_X11)
        int pos = source.indexOf("\r\n", idxStart);
#elif defined(Q_WS_WIN)
        int pos = source.indexOf("\n", idxStart);
#endif
        if (pos != -1)
        {
            idxEnd = pos;
        }
        else
        {
            idxEnd  = idxStart + source.mid(idxStart).size();
        }
        //Здесь мы сообщаем, что начинаем новый стиль
        //с позиции start + idxStart
        startStyling(idxStart);
        int len = idxEnd - idxStart;
        //А здесь мы сообщаем, что начиная от текущей позиции, определенной startStyling,
        //дальше последуют len символов стиля style == Comment
        setStyling(len, style);
        //Заканчиваем отрисовку стиля
        startStyling(idxEnd);
        idxStart = idxEnd;
    }
}

★★★

Тут смотри, у styleText() в аргументах позиции в байтах, и startStyling() с setStyling() тоже принимают индексы в байтах.
Т.е. QString::indexOf() тут уже не подходит, т.к. возвращает индекс символа.

Потом, ты, каждый раз, идёшь по всему тексту, хотя тебе нужно искать только между start и end.

source.count(«//») перед циклом - лишнее. comments() без return... =)

summatus ()
Ответ на: комментарий от summatus

Ну вот, как-то так с QByteArray можно сделать

void GMLsciLexer::styleText(int start, int end)
{
    //editor() - функция из родительского класса.
    //Возвращает указатель на QsciScintilla
    if (!editor())
        return;
    QsciScintilla * editor = this->editor();

    QByteArray section;
    section.resize( end - start );
    editor->SendScintilla( QsciScintilla::SCI_GETTEXTRANGE, start, end, section.data() );

    QList< QByteArray > lines = section.split( '\n' );

    foreach ( const QByteArray& line, lines ) {
        int index = line.indexOf( "//" );

        if ( index != -1 ) {
            startStyling( start + index );
            int len = line.size() - index;
            setStyling( len, Comment );
            setStyling( 1, Default );
        }

        start += line.size();
    }

    //QString source = editor->text();
    //comments(source, start, end);
}
summatus ()
Ответ на: комментарий от summatus

Спасибо, помогло.

Жаль, что к QByteArray нельзя применить QRegExp для поиска. Возможность использовать конструкции вроде:

idxStart = source.indexOf(QRegExp(«\\b»+word+«\\b»), idxStart);

могла бы облегчить задачу. А так слова прийдется выделять вручную.

Genuine ★★★ ()
Ответ на: комментарий от Genuine

Если это всё что нужно, то можно просто посчитать байты QString::indexOf()

    QString str( line );
    int charIndex = str.indexOf( QRegExp( ...
    int byteIndex = 0;

    for ( int i = 0; i < charIndex; ++i ) {
        byteIndex += ( str.at( i ).unicode() < 255 ) ? 1 : 2;
    }

И byteIndex уже передавать в startStyling() и т.д.

Но вообще, обычно, подсветка ЯП на регэкспах - это фигня. Будет тормозить. Помотри, может проще взять за основу один из лексеров scintilla (т.е. унаследовать QsciLexer например).

summatus ()
Ответ на: комментарий от summatus

>Помотри, может проще взять за основу один из лексеров scintilla (т.е. унаследовать QsciLexer например)

Спасибо за наводку, наследование QsciLexer дейсвительно выглядит более приемлемо, чем наследование QsciLexerCustom.

Genuine ★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.