среда, 13 октября 2010 г.

QScintilla: определяем styleText

Вот мы и добрались до самой важной функции лексера void styleText(int start, int end)

Займемся ее реализацией.

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

  //получить исходник
  //выделим кусок памяти
  // +1 - под \0
  char * chars = new char[end - start + 1];
  //заполним кусок обратившись сцинтилле
  editor()->SendScintilla(QsciScintilla::SCI_GETTEXTRANGE,
              start, end, chars);
  //преобразуем в строку
  QString source(chars);
  delete [] chars;
 
  //Оптимизация - кэшируем уже ранее отрисованную строку
  if (source == cache)
   return;
  else
   cache = source;
  //Не работаем с пустой строкой
  if (source.isEmpty())
   return;
  //вызываем функцию отрисовки комментария
  //передаем исходную строку, начало и конец
  commentStyling(source, start, end);
}

* This source code was highlighted with Source Code Highlighter.


В комментариях описано, что мы делаем в этой функции. Здесь мы получаем строку, которую требуется отрисовать (это может быть не только текущая строка, а в том числе и соседние строки, сцинтилла в этом плане довольно умна).
Дальше вызываем функцию commentStyling(source, start, end);

Ее реализация приведена ниже:

bool LexerZ::commentStyling(const QString & line, int start, int end)
{
  //Если в строке вообще нет символов комментария, то ничего не делать
  if (!line.contains("**"))
   return false;
  //Определяем сколько раз встречаются комменты (они могут быть в середине строки, или же line - это может быть на самом деле несколько строк)
  int count = line.count("**");
  int style = Comment;
  int idxStart = 0;
  int idxEnd = idxStart;
  //Обрабатываем каждый символ комментария
  for (int i = 0; i < count; i++)
  {
   idxStart = line.indexOf("**", idxStart);
   if (idxStart == -1)
     break;
   int pos = line.indexOf("\r", idxStart);
   if (pos != -1)
   {
     idxEnd = pos;
   }
   else
   {
     idxEnd  = idxStart + line.mid(idxStart).size();
   }
   //Здесь мы сообщаем, что начинаем новый стиль
   //с позиции start + idxStart
   startStyling(start + idxStart);
   int len = idxEnd - idxStart;
   //А здесь мы сообщаем, что начиная от текущей позиции, определенной startStyling,
   //дальше последуют len символов стиля style == Comment
   setStyling(len, style);
   //Заканчиваем отрисовку стиля
   startStyling(start + idxEnd);

   idxStart = idxEnd;
  } 
 
  return true;
}

* This source code was highlighted with Source Code Highlighter.


Итак, здесь нужно уяснить основной прицип. Сначала мы сообщаем сцинтилле, что с позиции
start + idxStart начнется новый стиль. idxStart это собственно индекс, которого начинается комментарий в текущей строке line.
Дальше мы вычисляем сколько символов занимает коммент. Он может длиться до конца строки, определяемого символом \r. Длина коммента хранится в переменной len.
Затем сообщаем сцинтилле, что len символов это коммент :    setStyling(len, style);       
Получив такое указание, сцинтилла начнет дергать виртуальные функции, которые мы определяли в предыдущем посте, с параметром style. Вот почему я говорил ранее, что название констант и их числовое значение особого смысла не имеют. Мы их сами определяли.
И, наконец, сцинтилле надо сообщить, что стиль закончился startStyling(start + idxEnd);


На этом я закрываю цикл статей о QScintilla.
Если вспомню вдруг что интересное - выложу.

Комментариев нет:

Отправить комментарий