SynEdit Highlighter/ru: what changed
Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.
| Old | New | Line | |
|---|---|---|---|
| 1 | 1 | Для получения дополнительной информации о SynEdit перейдите к статье: [[SynEdit]] | |
| 2 | 2 | ||
| 3 | 3 | ------------------------------------------------------------------------ | |
| 4 | 4 | ||
| 5 | 5 | Прим.перев.: для облегчения читаемости статьи далее под термином **Highlighter** будет подразумеваться механизм(маркер) подсветки синтаксиса. | |
| 6 | 6 | ||
| 7 | 7 | ------------------------------------------------------------------------ | |
| 8 | 8 | ||
| 9 | 9 | # Понимание SynEdit Highlighter | |
| 10 | 10 | ||
| 11 | 11 | ## Взаимоотношения SynEdit - Highlighter | |
| 12 | 12 | ||
| 13 | 13 | **SynEdit - Highlighter** имеют взаимоотношение **N к 1**. | |
| 14 | 14 | ||
| 15 | 15 | - Один экземпляр Highlighter может обслуживать **N** (много) экземпляров SynEdits | |
| 16 | 16 | - Каждый SynEdit имеет только один Highlighter | |
| 17 | 17 | - Но: один текст (текстовый буфер) может иметь много маркеров подсветки синтаксиса, если он используется несколькими SynEdit (каждый SynEdit будет иметь один HL, но все HL будут работать с одним и тем же документом) | |
| 18 | 18 | ||
| 19 | 19 | В результате: | |
| 20 | 20 | ||
| 21 | 21 | - Экземпляр Highlighter не имеет (фиксированной) ссылки на SynEdit. | |
| 22 | 22 | ||
| 23 | 23 | ||
| 24 | 24 | (Однако Highlighter'ы хранят список SynEditTextBuffers, к которому они прикреплены) | |
| 25 | 25 | ||
| 26 | 26 | - Все данные для Highlighter (должны быть) сохранены в SynEdit (фактически в TextBuffer SynEdit (называемом «Линии»). | |
| 27 | 27 | ||
| 28 | 28 | Однако перед каждым вызовом Highlighter SynEdit гарантирует, что для Highlighter.CurrentLines будут установлены текущие строки SynEdits. Таким образом, маркер может получить доступ к данным в любое время. Формат хранения данных определяется маркером (TSynCustomHighlighter.AttachToLines). | |
| 29 | 29 | ||
| 30 | 30 | ## Сканирование и возврат атрибутов подсветки | |
| 31 | 31 | ||
| 32 | 32 | Ожидается, что Highlighter будет работать на основе каждой строки. | |
| 33 | 33 | ||
| 34 | 34 | Если какой-либо текст был изменен, SynEdit будет вызывать (TSynCustomHighlighter.ScanFrom / в настоящее время вызывается из TSynEdit.ScanFrom) с диапазоном строк. Highlighter должен знать состояние предыдущей строки. | |
| 35 | 35 | ||
| 36 | 36 | Если требуются атрибуты подсветки, SynEdit будет запрашивать их также для каждой строки. SynEdit будет проходить через отдельные токены на линии. В настоящее время это происходит из вложенных процедур PaintLines в SynEdit.PaintTextLines. Он вызывает TSynCustomHighlighter.StartAtLineIndex, за которым следует HL.GetTokenEx/HL.GetTokenAttribute до тех пор, пока HL.GetEol имеет значение false. | |
| 37 | 37 | ||
| 38 | 38 | Кроме того, базовый класс для данных Highlighter'а (см. AttachToLines) основан на хранении данных на каждой строке, а TextBuffer (строки) SynEdit выполняет обслуживание этих данных для их синхронизации. То есть: всякий раз, когда строки текста вставляются или удаляются, записи также вставляются или удаляются из данных highlighter'ов (следовательно, в каждой строке должна быть одна запись). | |
| 39 | 39 | ||
| 40 | 40 | Обычно Highlighter'ы сохраняют статус конца строки в этом поле. Поэтому, если Highlighter будет работать со строчкой, он продолжит ввод состояния из предыдущей строки. | |
| 41 | 41 | ||
| 42 | 42 | ## Folding (сворачивание текста) | |
| 43 | 43 | ||
| 44 | 44 | Событие фолдинга (схлопывания/сворачивания текста) SynEdit обрабатывается модулями SynEditFoldedView и SynGutterCodeFolding. Highlighter'ы, которые реализуют сворачивание, должны основываться на TSynCustomFoldHighlighter. | |
| 45 | 45 | ||
| 46 | 46 | Базовая информация для связи между SynEditFoldedView и Highlighter'ом требует 2 значения, сохраненных для каждой строчки (конечно, сам highlighter может хранить больше информации): | |
| 47 | 47 | ||
| 48 | 48 | - FoldLevel в конце строки | |
| 49 | 49 | - Минимальный FoldLevel, встречающийся где-либо в строке | |
| 50 | 50 | ||
| 51 | 51 | Foldlevel указывает, сколько (вложенных) уровней схлопывания/сворачивания текста существует. Он повышается всякий раз, когда уровень сворачивания начинается, и понижается, когда уровень сворачивания заканчивается: | |
| 52 | 52 | ||
| 53 | 53 | ``` pascal | |
| 54 | 54 | EndLvl MinLvl | |
| 55 | 55 | Procedure a; 1 - 0 | |
| 56 | 56 | Begin 2 -- 1 - | |
| 57 | 57 | b:= 1; 2 -- 2 -- | |
| 58 | 58 | if c > b then begin 3 --- 2 -- | |
| 59 | 59 | c:=b; 3 --- 3 --- | |
| 60 | 60 | end else begin 3 --- 2 -- | |
| 61 | 61 | b:=c; 3 --- 3 --- | |
| 62 | 62 | end; 2 -- 2 -- | |
| 63 | 63 | end; 0 0 // Оператор end закрывает оба уровня сворачивания текста: операторов | |
| 64 | 64 | //begin и procedure | |
| 65 | 65 | ``` | |
| 66 | 66 | ||
| 67 | 67 | На строке | |
| 68 | 68 | ||
| 69 | 69 | ``` pascal | |
| 70 | 70 | Procedure a; 1 - 0 | |
| 71 | 71 | ``` | |
| 72 | 72 | ||
| 73 | 73 | MinLvl равен 0, потому что строка началась с уровня 0 (и она никогда не спускалась / не закрывалась). Аналогично во всех строках, где есть только ключевое слово, открывающее уровень сворачивания текста ("begin"). | |
| 74 | 74 | ||
| 75 | 75 | А строка | |
| 76 | 76 | ||
| 77 | 77 | ``` pascal | |
| 78 | 78 | end else begin 3 --- 2 -- | |
| 79 | 79 | ``` | |
| 80 | 80 | ||
| 81 | 81 | начинается с уровня 3, а также заканчивается им (один закрытый, один открытый). Но так как она спускается первой, минимальный уровень, встречающийся где-либо в строке, равен 2. | |
| 82 | 82 | ||
| 83 | 83 | Без MinLvl было бы невозможно сказать, что уровень сворачивания текста заканчивается на этой строке. | |
| 84 | 84 | ||
| 85 | 85 | MaxLvl не существует, потому что уровни сворачивания текста, начинающиеся и заканчивающиеся на одной и той же линии, не могут быть свернуты в любом случае. Не нужно их обнаруживать. | |
| 86 | 86 | ||
| 87 | 87 | ``` pascal | |
| 88 | 88 | if a then begin b:=1; c:=2; end; // нет уровня сворачивания текста на этой строке | |
| 89 | 89 | ``` | |
| 90 | 90 | ||
| 91 | 91 | # Создание SynEdit Highlighter | |
| 92 | 92 | ||
| 93 | 93 | Начиная с версии 0.9.31 rev.35115, сворачивание текста в highlighter'е изменилось. Реализовать базовое свертывание текста теперь проще. | |
| 94 | 94 | ||
| 95 | 95 | Все исходники можно найти в каталоге установки Lazarus в: examples\SynEdit\NewHighlighterTutorial\\ | |
| 96 | 96 | ||
| 97 | 97 | Проект HighlighterTutorial содержит 3 различных примера highlighter'ов: | |
| 98 | 98 | ||
| 99 | 99 | - SimpleHl: используется в шаге 1 ниже | |
| 100 | 100 | - ContextHl: используется в шаге 2 ниже | |
| 101 | 101 | - FoldHl: используется в шаге 3 ниже | |
| 102 | 102 | ||
| 103 | 103 | SimpleHl и ContextHl тоже будут работать с v.0.9.30 Лазаруса | |
| 104 | 104 | ||
| 105 | 105 | Сворачивание текста в highlighter'е в действии | |
| 106 | 106 | ||
| 107 | - | ||
| 108 | - | ||
| 109 | - | ||
| 110 | - | ||
| 107 | + |  | |
| 111 | 108 | ||
| 112 | 109 | ## Основы: возврат токенов и атрибутов | |
| 113 | 110 | ||
| 114 | 111 | Как указано, модуль **SimpleHl** демонстрирует этот процесс. | |
| 115 | 112 | ||
| 116 | 113 | ### Что он делает | |
| 117 | 114 | ||
| 118 | 115 | - Он разбивает каждую строку на слова и пробелы (или табуляции) | |
| 119 | 116 | - Пробелы являются частью текста и также должны быть подсвечены | |
| 120 | 117 | - Этот пример позволяет указать разные цвета для | |
| 121 | 118 | ||
| 122 | 119 | ||
| 123 | 120 | ||
| 124 | 121 | \- текста (по умолчанию не подсвечен) | |
| 125 | 122 | ||
| 126 | 123 | \- пробелов (по умолчанию в серебристой рамке) | |
| 127 | 124 | ||
| 128 | 125 | \- слов, разделенных пробелами, начинающихся с a,e,i,o,u (по умолчанию выделены жирным шрифтом) | |
| 129 | 126 | ||
| 130 | 127 | \- "не" слов (по умолчанию на красном фоне) | |
| 131 | 128 | ||
| 132 | 129 | ### Как это работает | |
| 133 | 130 | ||
| 134 | 131 | - Creation | |
| 135 | 132 | ||
| 136 | 133 | Highlighter создает Атрибуты, которые могут вернуть Words(слова) и Spaces(пробелы). | |
| 137 | 134 | ||
| 138 | 135 | - SetLine | |
| 139 | 136 | ||
| 140 | 137 | Событие вызывается SynEdit до того, как будет прорисована строка (или до того, как потребуется информация о выделении) | |
| 141 | 138 | ||
| 142 | 139 | - GetTokenEx, GetTokenAttribute, Next, GetEol | |
| 143 | 140 | ||
| 144 | 141 | События используются SynEdit для перебора строки. Обратите внимание, что первый токен (слово или пробел) должен быть готов после SetLine, без вызова Next. | |
| 145 | 142 | ||
| 146 | 143 | > **Note:** токены, возвращаемые для каждой строки, должны представлять исходный текст строки и возвращаться в правильном порядке. | |
| 147 | 144 | ||
| 148 | 145 | - GetToken, GetTokenPos, GetTokenKind | |
| 149 | 146 | ||
| 150 | 147 | SynEdit использует их, например, для поиска подходящих скобок. Если tokenKind возвращает разные значения для каждого атрибута, то скобки совпадают только в том случае, если они имеют одинаковый вид (например, если был строковый атрибут, скобки вне строки не будут совпадать с скобками внутри строки). | |
| 151 | 148 | ||
| 152 | 149 | ### Другие заметки | |
| 153 | 150 | ||
| 154 | 151 | Для удобства чтения highlighter не имеет оптимизации, поэтому он может быть очень медленным для больших текстов. Многие из поставляемых highlighter'ов используют хеш-функции, чтобы найти слово (или любую группу символов). | |
| 155 | 152 | ||
| 156 | 153 | ## Шаг 2: Использование диапазонов | |
| 157 | 154 | ||
| 158 | 155 | Как указано, модуль **ContextHl** демонстрирует этот процесс. | |
| 159 | 156 | ||
| 160 | 157 | Следующий пример допускает влияние содержимого строки на последующие строки. Например: "`(*`" в Паскале делает все последующие строки комментарием, пока не будет найден "`*)`". | |
| 161 | 158 | ||
| 162 | 159 | Этот пример расширяет показанный выше **SimpleHl**: Токены `--` и `++` (должны быть обрамлены пробелом или началом/концом строки, чтобы стать их собственным токеном) будут переключать слова, начинающиеся с a,e,i,o,u | |
| 163 | 160 | ||
| 164 | 161 | Несколько `++` и `--` могут быть вложенными. Тогда для каждого слова должны быть заданы `--` и `++`, прежде чем оно снова будет подсвечено. | |
| 165 | 162 | ||
| 166 | 163 | Then we extend the scanner. The pre-scan to store the information calls the same functions as the highlighter. It is automatically called, if anything changes. (It is called for all lines below the changed line, until a line returns the same Range-value as it already had) Затем мы расширяем сканер. Предварительное сканирование для хранения информации вызывает те же функции, что и highlighter. Он автоматически вызывается, если что-то меняется (он вызывается для всех строк ниже измененной строки, пока строка не вернет то же значение Range, что и раньше). | |
| 167 | 164 | ||
| 168 | 165 | Текущее количество "`--`" рассчитывается в | |
| 169 | 166 | ||
| 170 | 167 | ``` pascal | |
| 171 | 168 | FCurRange: Integer; | |
| 172 | 169 | ``` | |
| 173 | 170 | ||
| 174 | 171 | Количество уменьшается посредством "`++`" | |
| 175 | 172 | ||
| 176 | 173 | Для хранения информации мы используем: | |
| 177 | 174 | ||
| 178 | 175 | GetRange | |
| 179 | 176 | Вызывается после полного сканирования строки, чтобы получить значение в конце строки. Значение будет сохранено. | |
| 180 | 177 | ||
| 181 | 178 | SetRange | |
| 182 | 179 | Вызывается до сканирования линии. Устанавливает значение, хранящееся в конце предыдущей строки. | |
| 183 | 180 | ||
| 184 | 181 | ResetRange | |
| 185 | 182 | Вызывается до сканирования 1-й строки (так как предыдущей строки нет). | |
| 186 | 183 | ||
| 187 | 184 | > **Note:** Сканирование запускается при *каждом* изменении строки (при каждом нажатии клавиши). Он сканирует текущую строку и все строки ниже, пока строка не вернет тот же диапазон, который у нее уже был. См.: <http://forum.lazarus.freepascal.org/index.php/topic,21727.msg139420.html#msg139420> | |
| 188 | 185 | ||
| 189 | 186 | ### Важное замечание о диапазонах | |
| 190 | 187 | ||
| 191 | 188 | Назначение диапазона - позволить Highlighter начать сканирование в любой строке. Highlighter никогда не понадобится смотреть на предыдущую строку. Любая информация, необходимая для сканирования текущей строки, может быть получена из значения диапазонов. | |
| 192 | 189 | ||
| 193 | 190 | Пример: | |
| 194 | 191 | ||
| 195 | 192 | ``` pascal | |
| 196 | 193 | writeln; (* | |
| 197 | 194 | readln; | |
| 198 | 195 | *) | |
| 199 | 196 | ``` | |
| 200 | 197 | ||
| 201 | 198 | при сканировании "readln" Highlighter знает из диапазона, который находится в комментарии, ему не нужно осматривать предыдущие строки. | |
| 202 | 199 | ||
| 203 | 200 | Поэтому сканирование может начинаться с любой строки. | |
| 204 | 201 | ||
| 205 | 202 | Это также объясняет примечание в предыдущей главе: "пока строка не вернет тот же диапазон, который у нее уже был". Ибо, даже если текст строки не был изменен, если значение диапазона в начале строк изменилось, то результат сканирования также изменится. | |
| 206 | 203 | ||
| 207 | 204 | ## Шаг 3: Добавление маркеров сворачивания текста | |
| 208 | 205 | ||
| 209 | 206 | Как указано выше, модуль **FoldHl** демонстрирует этот процесс. | |
| 210 | 207 | ||
| 211 | 208 | Например, highlighter должен сворачивать весь текст между отдельно стоящими "`-(-`", "`-)-`". | |
| 212 | 209 | ||
| 213 | 210 | Изменим наследование: | |
| 214 | 211 | ||
| 215 | 212 | ``` pascal | |
| 216 | 213 | uses SynEditHighlighterFoldBase; | |
| 217 | 214 | ... | |
| 218 | 215 | TSynDemoHl = class(TSynCustomFoldHighlighter) | |
| 219 | 216 | ``` | |
| 220 | 217 | ||
| 221 | 218 | Изменим способ хранения информации о диапазоне, поскольку базовый класс использует ее для информации о схлопывании текста: | |
| 222 | 219 | ||
| 223 | 220 | ``` pascal | |
| 224 | 221 | procedure TSynDemoHl.SetRange(Value: Pointer); | |
| 225 | 222 | begin | |
| 226 | 223 | inherited; | |
| 227 | 224 | FCurRange := PtrInt(CodeFoldRange.RangeType); | |
| 228 | 225 | end; | |
| 229 | 226 | ||
| 230 | 227 | procedure TSynDemoHl.ResetRange; | |
| 231 | 228 | begin | |
| 232 | 229 | inherited; | |
| 233 | 230 | FCurRange := 0; | |
| 234 | 231 | end; | |
| 235 | 232 | ||
| 236 | 233 | function TSynDemoHl.GetRange: Pointer; | |
| 237 | 234 | begin | |
| 238 | 235 | CodeFoldRange.RangeType := Pointer(PtrInt(FCurRange)); | |
| 239 | 236 | inherited; | |
| 240 | 237 | end; | |
| 241 | 238 | ``` | |
| 242 | 239 | ||
| 243 | 240 | Теперь добавим код в сканер, который сообщает highlighter'у об открытии и закрытии маркеров схлопывания текста: | |
| 244 | 241 | ||
| 245 | 242 | ``` pascal | |
| 246 | 243 | procedure TSynDemoHl.FindTokenEnd; | |
| 247 | 244 | begin | |
| 248 | 245 | ... | |
| 249 | 246 | ||
| 250 | 247 | if (FTokenEnd = FTokenPos+1) and (FLineText[FTokenPos] = '[') then | |
| 251 | 248 | StartCodeFoldBlock(nil); | |
| 252 | 249 | if (FTokenEnd = FTokenPos+1) and (FLineText[FTokenPos] = ']') then | |
| 253 | 250 | EndCodeFoldBlock(); | |
| 254 | 251 | end; | |
| 255 | 252 | ``` | |
| 256 | 253 | ||
| 257 | 254 | - **Для 0.9.30** | |
| 258 | 255 | ||
| 259 | 256 | Пожалуйста, смотрите историю [этой страницы](http://wiki.lazarus.freepascal.org/index.php?title=SynEdit_Highlighter&oldid=76020), если вы используете версию 0.9.30. | |
| 260 | 257 | ||
| 261 | 258 | #### Подробнее о StartCodeFoldBlock / EndCodeFoldBlock | |
| 262 | 259 | ||
| 263 | 260 | ``` pascal | |
| 264 | 261 | function StartCodeFoldBlock(ABlockType: Pointer; IncreaseLevel: Boolean = true): TSynCustomCodeFoldBlock; virtual; | |
| 265 | 262 | ``` | |
| 266 | 263 | ||
| 267 | 264 | ABlockType | |
| 268 | 265 | может использоваться для указания идентификатора блока.\ | |
| 269 | 266 | ||
| 270 | 267 | Поле обычно не используется в качестве указателя (хотя это и не запрещено). Обычно идентификаторы - это числовое перечисление.\ | |
| 271 | 268 | Если у вас есть блоки разных типов (например, в Паскале: begin/end; repeat/until, ...), и вы не хотите, чтобы блок закрывался по неправильному ключевому слову ("end" не должен закрывать "repeat"), тогда вы можете дать им идентификаторы: | |
| 272 | 269 | ||
| 273 | 270 | ``` pascal | |
| 274 | 271 | StartCodeFoldBlock(PtrUInt(1)) // или другие числа | |
| 275 | 272 | ``` | |
| 276 | 273 | ||
| 277 | 274 | IncreaseLevel | |
| 278 | 275 | Если установлено значение False, будет вставлен блок, который нельзя свернуть.\ | |
| 279 | 276 | Подобные блоки можно использовать для внутреннего отслеживания. | |
| 280 | 277 | ||
| 281 | 278 | ПРИМЕЧАНИЕ: все уровни сворачивания текста должны быть вложенными, они не могут перекрываться. То есть последний открытый уровень сворачивания текста должен быть закрыт первым.\ | |
| 282 | 279 | Это относится к EndLvl, как показано в разделе [[SynEdit Highlighter/ru|Folding (сворачивание текста)]] выше.\ | |
| 283 | 280 | Перекрытия (как `IFDEF` и `begin` в IDE) не могут быть выполнены таким образом. | |
| 284 | 281 | ||
| 285 | 282 | ``` pascal | |
| 286 | 283 | procedure EndCodeFoldBlock(DecreaseLevel: Boolean = True); virtual; | |
| 287 | 284 | ``` | |
| 288 | 285 | ||
| 289 | 286 | DecreaseLevel | |
| 290 | 287 | Параметр *должен* соответствовать `IncreaseLevel`, как это было указано в `StartCodeFoldBlock`\ | |
| 291 | 288 | ||
| 292 | 289 | True означает, что уровень сворачивания текста заканчивается; False означает, что внутренний блок окончен. Если есть несоответствие, уровни сворачивания текста будут либо продолжаться, либо заканчиваться раньше.\ | |
| 293 | 290 | `TopCodeFoldBlockType` может использоваться для указания идентификатора самого внутреннего открытого блока. Можно использовать разные идентификаторы для внутренних блоков, и используя их, чтобы установить значение. | |
| 294 | 291 | ||
| 295 | 292 | ``` pascal | |
| 296 | 293 | function TopCodeFoldBlockType(DownIndex: Integer = 0): Pointer; | |
| 297 | 294 | ``` | |
| 298 | 295 | ||
| 299 | 296 | Возвращает идентификатор самого внутреннего блока. | |
| 300 | 297 | ||
| 301 | 298 | DownIndex | |
| 302 | 299 | может быть использован для получения идентификатора для другого блока. | |
| 303 | 300 | ||
| 304 | 301 | `DownIndex=1` обозначает блок, который окружает самый внутренний. | |
| 305 | 302 | ||
| 306 | 303 | # Конфигурируемые Highlighter'ы (включая сторонние) | |
| 307 | 304 | ||
| 308 | 305 | ## SynAnySyn | |
| 309 | 306 | ||
| 310 | 307 | Настоящий простой Highlighter. Более эталонная реализация, чем реальный пригодный для использования Highlighter. | |
| 311 | 308 | ||
| 312 | 309 | ## SynFacilSyn | |
| 313 | 310 | ||
| 314 | 311 | Гибкий полностью настраиваемый Highlighter. См. [SynFacilSyn](https://github.com/t-edson/SynFacilSyn). | |
| 315 | 312 | ||
| 316 | 313 | # Ссылки | |
| 317 | 314 | ||
| 318 | 315 | Темы на форуме: | |
| 319 | 316 | ||
| 320 | 317 | - "Создание Highlighter'а для синтаксиса С" [[http://www.lazarus.freepascal.org/index.php/topic,10260.0.html topic,10260]] | |
| 321 | 318 | - "Создание Syntax Highlighter" [[http://www.lazarus.freepascal.org/index.php/topic,10959.msg54714 topic,10959.msg54714]] | |
| 322 | 319 | - Получение подсветки для печати [[http://www.lazarus.freepascal.org/index.php/topic,11384.msg57160.html|http://www.lazarus.freepascal.org/index.php/topic,11384.msg57160.html#msg57160 11384.msg57160]] | |
| 323 | 320 | - Некоторые подробности о диапазонах и использовании объектов для хранения, подробнее [[http://forum.lazarus.freepascal.org/index.php/topic,21727.msg139354.html|http://forum.lazarus.freepascal.org/index.php/topic,21727.msg139354.html#msg139354 topic,21727.msg139354]] и [[http://forum.lazarus.freepascal.org/index.php/topic,21727.msg139419.html|http://forum.lazarus.freepascal.org/index.php/topic,21727.msg139419.html#msg139419 topic,21727.msg139419]] | |
| 324 | 321 | - Подробнее о диапазонах, рабочей копии vs immutable, foldblocks...[[http://forum.lazarus.freepascal.org/index.php/topic,30685.msg195464.html|http://forum.lazarus.freepascal.org/index.php/topic,30685.msg195464.html#msg195464 http://forum.lazarus.freepascal.org/index.php/topic,30685]] | |
| 325 | 322 | - Разметка (подсветка) всех вхождений токена (или регулярного выражения)[[http://forum.lazarus.freepascal.org/index.php?topic=26833 topic=26833]] | |
| 326 | 323 | - Разметка и сворачивание информации:: [[http://forum.lazarus.freepascal.org/index.php?topic=30122]] | |
| 327 | 324 | - Как сделать отмену в TSynEditMarkup [[http://forum.lazarus.freepascal.org/index.php/topic,30122.msg207931.html|http://forum.lazarus.freepascal.org/index.php/topic,30122.msg207931.html#msg207931]] | |
| 328 | 325 | ||
| 329 | 326 | - Сворачивание текста | |
| 330 | 327 | - "SynEdit - улучшенные highlighter'ы для обработки Code Folding?" [[http://www.lazarus.freepascal.org/index.php/topic,7879.0.html topic,7879]] | |
| 331 | 328 | - "SynEdit - Добавление поддержки свертывания кода для Java" [[http://www.lazarus.freepascal.org/index.php/topic,7338.0.html topic,7338]] | |
| 332 | 329 | - "CodeFolding" конфигурация [[http://www.lazarus.freepascal.org/index.php/topic,11064 topic,11064]] | |
| 333 | 330 | - Fold блокирует ключевое слово "end" (конец строки перед следующим ключевым словом) [[http://forum.lazarus.freepascal.org/index.php/topic,23411.msg139621.html|http://forum.lazarus.freepascal.org/index.php/topic,23411.msg139621.html#msg139621 topic,23411.msg139621]] | |
| 334 | 331 | - Сворачивание выделенного текста из кода (код пользователя / приложения):: [[http://forum.lazarus.freepascal.org/index.php/topic,24473.msg147312.html|http://forum.lazarus.freepascal.org/index.php/topic,24473.msg147312.html#msg147312 24473.msg147312]] | |
| 335 | 332 | - Получение состояния уровня сворачивания текста (сохранение состояния уровня сворачивания в сеансе работы) [[http://forum.lazarus.freepascal.org/index.php?topic=26748 topic=26748]] | |
| 336 | 333 | ||
| 337 | 334 | --- | |
| 338 | 335 | *From the Free Pascal wiki, page "SynEdit Highlighter/ru", as it stood on 2020-02-11 after a change by Andry, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).* | |
| 339 | 336 | Category: SynEdit |
