Версия для печати
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум на Исходниках.RU > Delphi: Общие вопросы > Подстветка синтаксиса и неизвестных слов


Автор: k.sovailo 26.02.18, 20:13
Добрый день, уважаемые программисты. Написал я как-то редактор кода (состоящего из 30 команд и нескольких слов), добавлял-добавлял функционал, и вот редактор стал неработоспособным. Захотел переписать. Поскольку проект будет опубликован, хотел сделать это качественно и красиво. Выбор пал на SynEdit, потому что сам я так же красиво и быстро вряд ли сделаю. Даже с собственным синтаксисом разобрался, но:

а) Как подсвечивать числа? Для них даже есть tkNumbers, но ни как его прикрепить в SynHightlighterSample, ни как подсунуть в SynGen - не знаю.

б) Сделал автозамену минуса на длинное тире (в редакторе работаю с большими объёмами текста на русском), но оказалось неудобно вбивать сам минус. Можно ли при вводе символа узнать, будет ли он введён в строку или нет и в зависимости от этого превращать или не превращать в тире? Было бы очень удобно.

в) Можно ли подчёркивать неизвестные редактору слова? Список слов заранее неизвестен. Также по возможности искать только тогда, когда слово уже введено и пользователь нажимает пробел, чтоб не тратить время зря. А если в Idle - ещё лучше! Поиск вроде достаточно быстрый, но мало ли, вдруг кто-то 100500 слов в словарь введёт.

г) Как выделить сроку цветом? Уж больно красиво IDE ошибки выкидывает.

Прошу не кидать тапки слишком больно, потому что кроме "Hightlighters: How To" никакого нормального описания не нашёл. Если есть мануалы и я проглядел - прошу кинуть, английский читаю. Или может есть компонент попроще и посовременней? Заранее спасибо.

Автор: Fr0sT 27.02.18, 07:54
б) - что значит "будет ли он введён в строку или нет"? Можно использовать логику Ворда и заменять только если после минуса введен пробел - тире всегда отделяется пробелами, а минус aka дефис наоборот. Сработает только если не ожидается математических выражений.

в) - насчет самого подчеркивания не в курсе, но сам процесс в моем представлении такой:
1. Подчеркивать только в видимой области (можно еще плюс экран или два сверху и снизу)
2. Запускать поиск неизвестных слов фоновым потоком
3. Переподсвечивать при событии редактирования - любом. Потому что может быть удаление, вырезка целого фрагмента текста, вставка текста и т.д. Можно, конечно, вычленять событие именно прямого набора слова и проверять только его, но, учитывая п.2, это небольшая экономия
4. Как минимум бинарный поиск, а лучше бинарное дерево для поиска - твое всё. Хэш-таблицы в этом плане, как мне кажется, будут хуже, т.к. потребуется еще вычислять хэши.
5. Можно хранить кеш уже подсвеченных слов, чтобы не пробегать поиском по словарю каждый раз. Набор этих слов явно будет более-менее ограниченным (имея в виду п.1), в отличие от словаря. Но это, в общем-то, не сильно критично учитывая п.2.

Добавлено
Есть еще https://github.com/bonecode/BCEditor
И https://github.com/Alexey-T/ATSynEdit, но он под Лазарус

Автор: k.sovailo 27.02.18, 22:24
Fr0sT, спасибо за ссылки, как-то прочитаю. Логика замены дефиса но тире у меня сейчас такая как в ворде, что очень напрягает при написании формул в редакторе. (Что и стало одной из последних капель в сторону переписывания редактора). И я хотел узнать, когда я ввожу символ, будет ли он принадлежать токену "строка". Покрасится ли в синий, в общем? Но я тут покопался в логике всего этого юнита и таки смог сделать подсветку чисел:

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    function TSynSampleSyn.IdentKind(MayBe: PWideChar): TtkTokenKind;
    var
      Key: Cardinal;
      CanBeNumber: boolean;
    begin
      fToIdent := MayBe;
      //начало отсебятины
      Key:=0;             //Не буду объявлять ещё один счётчик
      CanBeNumber:=true;
      while (MayBe[Key]<>#0)and(CanBeNumber) do begin
        CanBeNumber:=CanBeNumber and (MayBe[Key] in ['0'..'9']);
        Inc(Key);
      end;
      if CanBeNumber then begin
        fStringLen := MayBe - fToIdent; //HashKey выставляло fStringLen
        Result:=tkKey
      end
      else begin
      //конец отсебятины
        Key := HashKey(MayBe);
        if Key <= High(fIdentFuncTable) then
          Result := fIdentFuncTable[Key](KeyIndices[Key])
        else
          Result := tkIdentifier;
      end;
    end;


А ещё надо было добавить '0'..'9' в распознаваемые символы в методе Next. Кроме того, IdentKind вечно запускается дважды с одним параметром, хотя откуда - не могу отследить, слишком сложно. Думаю, будет иметь смысл запомнить последние входные данные и последний результат, чтоб не считать заново. А вообще, думаю, если переписать всё, что ниже Next заново, то можно и динамический синтаксис сделать, и вообще много чего. А узнать, куда вводим, вроде можно через fRange. В общем, мне пока работы хватит, сделаю (или не сделаю) - напишу.

Автор: k.sovailo 28.02.18, 16:21
Попробовал. fRange и fTokenID - оба приватные поля, служат для чтения и отрисовки каждой сроки, изменяются по сложному принципу. Строка 'hello"world"1234' будет вызывать Next 8 раз с : fTokenID=tkIdentifier, fTokenID=tkString, fTokenID=tkNember и fTokenI=tkNull, а потом всё по второму кругу, уже для отрисовки. Принцип смутно понятен. В общем, отследить куда я вставляю символ (в какой токен) будет непросто, при том, что создавать компонент типа TMySynEdit и перекрывать методы - та ещё морока, компилятор каждый раз ругается. В общем, буду дальше читать, но если кто вдруг знает/делал - прошу поделится.

Powered by Invision Power Board (https://www.invisionboard.com)
© Invision Power Services (https://www.invisionpower.com)