Компоненты для подсветки синтаксиса. Новый взгляд.
Если Вы читаете этот текст, полагаю, Вам либо интересен сам предмет разговора, либо (как впрочем, и мне) просто любопытно знакомство с новым кодом, представленным на суд Королевства. Что же. Постараюсь заинтересовать и тех и других. Поехали. Сразу попытаюсь взять быка за рога. Среди читателей найдется немало таких, кто с самого начала попытается заявить о том, что существует, наконец, SynEdit от http://synedit.sourceforge.net/, который поддерживает любой существующий на сегодняшний день синтаксис (кроме *) и позволяет описать любой необходимый, используя некоторые правила и/или шаблоны. Или, например, подобный компонент можно посмотреть на http://www.delphikingdom.ru/asp/viewitem.asp?catalogid=923. Как говорится, зачем изобретать велосипед? Все это так. Кроме нескольких нюансов. Во-первых, это просто интересно. SynEdit не поддерживает пропорциональные шрифты (я его понимаю :-)). Но поддержка любых шрифтов - это одно из основных начальных требований к моему компоненту. Разработку TMPSyntaxMemo я начинал тогда, когда мне много времени приходилось работать с монитором низкого качества, на котором шрифт Courier в любой его ипостаси выглядел глазопедом-убийцей. На его фоне Arial в MS Visual Studio.Net (Basic.Net - для наладонника, каюсь) был как глоток воздуха. Это был, если хотите, тот вызов, на который я не откликнуться просто не мог; Секции . Кто работал в MS VS или в Delphi 8, знает, что это такое. Это супер, когда любую семантически законченную часть кода можно просто свернуть и не наматывать километры на мышином колесе, пытаясь перейти от одной процедуры к другой. Вы часто пользуетесь Code Explorer в Delphi? Если бы он не сворачивался постоянно даже при незначительных изменениях кода и переключениями между закладками, может, от него было бы больше пользы. У меня лично нервов не хватает. Да, да, я помню, закладки, конечно. Особенно, когда о них вспоминаешь вовремя. Рис.1 Общий вид тестовой программы. Нажата клавиша Ctrl. Итак, компонент TMPSyntaxMemo . Сначала перечислю основные его отличия от известных мне, существующих на сегодняшний день, аналогов. По порядку (не путать со степенью важности - для каждого она своя - есть смысл проглядеть список до конца).
const TmrColors: array [Boolean] of TColor = (clBlue, clNavy); MySynMemo.SyntaxAttributes.FontColor[ 172 ] := TmrColors[fTmrTimes]; MySynMemo.Invalidate; fTmrTimes := not fTmrTimes; type TUserTokenEvent = procedure (Sender: TObject; Word: string ; Pos, Line: Integer; var Token: TToken) of object ; property OnParseWord: TUserTokenEvent;Где:
Это значительно расширяет возможности компонента. Изначально предполагалось его использовать для редактирования некоторого скрипта с синтаксисом, базирующемся на синтаксисе Forth**. Кто знает - поймет - это незабываемо. Одной из особенностей языка Forth является то, что его словарный запас постоянно растет (в том числе и ключевые слова (!)) при загрузке и компиляции программ. Это, пожалуй, единственный язык программирования на свете, который позволяет описывать новые конструкции языка (например, новый тип цикла) средствами самого языка. Таким образом, необходимо динамически, в RunTime пополнять словарь синтаксического редактора. Понятно, что вышеупомянутый SynEdit здесь уже не поможет. В данном случае, у нас развязаны руки. Самый простой способ обслуживания прерывания TUserTokenEvent есть в примере (FormMain.OnCreate) - создаем TStringList, задаем его Sorted := True и заполняем его ключевыми словами. В процедуре определения типа слова выполняем что-либо подобное if fDelphiKeyWords.Find(LowerCase(Word), n) then Token := 231 ; Если Вы не забыли предварительно настроить визуальные атрибуты токена с типом 231, Вы непременно получите требуемый результат. Зуб даю :-). function GetWordAtPos( const X, Y: Integer; var WordIndex, Row: Integer): Boolean; function CharPosToWordIndex( const Col, Row: Integer): Integer; Это открывает некоторые дополнительные возможности управления визуальным отображением ключевых слов Вашего редактора. Например, можно определить, когда заданное слово, являющееся именем пользовательской процедуры, используется в другой процедуре, а когда оно описывается или декларируется, и, таким образом, как-либо это подчеркнуть. Ниже приведен список комбинаций клавиш для работы с секциями текста
TWordInfoEvent = procedure (Sender: TMPCustomSyntaxMemo; const X, Y, WordIndex, Row: Integer; Showing: Boolean) of object ;и получить сведения о выбранном слове примерно так (см. пример) with Memo.Lines.Parser[Row].Tokens[WordIndex] do begin LabelWordInfo.Caption := Copy(Memo.Lines[Row], stStart + 1 , stLength); MemoWInfo.Lines.Clear; MemoWInfo.Lines.Append( 'Start at ' + IntToStr(stStart)); MemoWInfo.Lines.Append( 'Length is ' + IntToStr(stLength)); MemoWInfo.Lines.Append( 'Token is #' + IntToStr(stToken)); end ; Я предлагаю Вам попробовать использовать этот компонент в своих проектах. Вы можете вносить любые изменения в исходный код, использовать его частично или полностью. Единственное требование - ссылка на автора в коммерческих продуктах (). Исходный код был создан в D7. Не думаю, что возникнут какие-либо сложности при открытии его в более ранние версии Delphi. Код снабжен умеренным количеством комментариев, но, по крайней мере, для всех процедур указано их предназначение и некоторые особенности. К сожалению, справку я так и не написал. Оправданием мне может служить то, что изначально компонент должен был интегрироваться в некоторую систему, где справка по внутреннему коду не нужна в принципе. Обсуждение компонента приветствуется. Критика принимается только аргументированная. Вопросы, за исключением "зачем этот надо?" можно задавать напрямую с пометкой "TMPSyntaxMemo". Вот и все. Всех благ.
Страница сайта http://silicontaiga.ru
Оригинал находится по адресу http://silicontaiga.ru/home.asp?artId=5131 |