Sign in Join
Wiki copytemporary

SynEdit/ru: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11**SynEdit** - пакет [[Syntax highlighting|подсветки синтаксиса]] для edit/memo, доступный на [[SynEdit tab/ru|вкладке SynEdit]] с поддержкой многих языков/синтаксиса.
22
33SynEdit, содержащийся в Lazarus, был ответветлен от [SynEdit 1.0.3](https://sourceforge.net/projects/synedit/files/), адаптирован и довольно сильно расширен. Изменения перечислены ниже.
44
55Пакет Lazarus содержит компонент редактора исходного кода под названием \[TSynEdit/ru\|\[TSynEdit\]\], несколько подсветок синтаксиса и другие компоненты, используемые для редактирования исходного кода.
66
77Лицензирован на тех же условиях, что и исходный SynEdit (MPL или GPL).
88
99## Оригинальная версия против версии Lazarus
1010
1111Версия Lazarus поддерживается в основном [[[User:Martin|Martin Friebe]]. Martin написал на форуме, что было добавлено в версию Lazarus с момента появления fork:
1212
1313Большие изменения, добавленные в версию Lazarus:
1414
1515- сворачивание блоков кода
1616- настраиваемые боковое поле / части бокового поля
1717- общий текст между несколькими редакторами
1818- поддержка utf-8
1919- плагин для синхронизации
2020- базовая поддержка RTL/LTR
2121- настройка мыши через MouseActions
2222- переписаны различные модули подсветки/разметки
2323
2424Кодовые базы версий Delphi / Lazarus были независимо переработаны. Осталось очень мало совпадений.
2525
2626## SynEdit 2.0 port
2727
2828Существует альтернативный порт оригинальной версии SynEdit версии 2.0.x. Активность не поддерживается, последний коммит (сейчас июнь 2014) был в 2011 году.
2929
3030- [[SynEdit/port]]
3131- [Github page](https://github.com/rnapoles/)
3232
3333## SynEdit в IDE
3434
3535SynEdit в Lazarus - это встроенный пакет, потому что среда IDE использует его сама. Поэтому пакет не может быть удален из списка установки. Чтобы удалить записи из палитры компонентов, пакет SynEditDsgn можно удалить из установки.
3636
3737## Использование SynEdit
3838
3939### Подсветка
4040
4141- Есть несколько стандартных маркеров подсветки (см. [[SynEdit tab/ru|вкладку SynEdit]] в [[Component Palette/ru|палитре компонентов]])
4242- Существуют сценарии подсветки, которые можно адаптировать ко многим другим форматам файлов:
4343 - [[TSynAnySyn]] (стандартный, на палитре компонентов по умолчанию)
4444 - [[TSynPositionHighlighter]] (стандартный, **не** на палитре компонентов)
4545 - [[TSynUniHighlighter]] (стандартный, **не** на палитре компонентов)
4646 - SynFacilSyn ([Github](https://github.com/t-edson/SynFacilSyn))
4747- Существуют и другие сторонние маркеры подсветки: SynCacheSyn, SynGeneralSyn, SynRCSyn, SynRubySyn, SynSDDSyn, SynSMLSyn, SynSTSyn, SynTclTkSyn, SynUnrealSyn, SynURISyn, SynVBScriptSyn, SynVrml97Syn, [см. здесь](http://bugs.freepascal.org/view.php?id=18248).
4848- Вы можете написать новый маркер подсветки, см. информацию в [[SynEdit Highlighter]].
4949
5050### Изменение существующего маркера подсветки
5151
5252Иногда у вас может появиться желание отредактировать существующие маркеры подсветки (как этого хотел я несколько дней назад), которые уже существуют. В этом примере мы собираемся отредактировать маркер подсветку для паскаль-подобного кода (classname: [[TSynPasSyn]]; package: SynEdit V1.0; unit: SynHighlighterPas.pas).
5353
5454Скажем, мы хотим достичь того, чтобы наше приложение (в данном случае Lazarus) различало три типа комментариев, которые существуют в Pascal:
5555
5656``` pascal
5757 (* ansi *)
5858 { bor }
5959 // Slash
6060```
6161
6262Это может быть полезно, если вы хотите различать различные типы ваших комментариев (например, "Description", "Note", "Reference" и т.д.) и хотите, чтобы они были, например, окрашивались по-разному.
6363
6464> **Note:** На случай, если вы что-то сломаете, я предлагаю сделать несколько "NEW" и "/NEW"-комментариев, но вам не нужно
6565
6666- Сначала откройте модуль "SynHighlighterPas", который должен находиться в вашем SynEdit-каталоге.
6767- Поскольку мы не хотим создавать несовместимости, мы создаем новый перечислимый тип, который поможет нам позже идентифицировать наш комментарий:
6868
6969Напр., под объявлением "tkTokenKind" напишите это:
7070
7171``` pascal
7272 {NEW}
7373 TtckCommentKind = (tckAnsi, tckBor, tckSlash);
7474 {/NEW}
7575```
7676
7777- В объявлении "TSynPasSyn" найдите "FTokenID" и добавьте следующее между "FTokenID" и следующим полем
7878
7979``` pascal
8080 {NEW}
8181 FCommentID: TtckCommentKind;
8282 {/NEW}
8383 //Это создает новое поле, где мы можем хранить информацию, какой у нас комментарий
8484```
8585
8686- В объявлении "TSynPasSyn" найдите "fCommentAttri" и добавьте следующее между "fCommentAttri" и следующим полем
8787
8888``` pascal
8989 {NEW}
9090 fCommentAttri_Ansi: TSynHighlighterAttributes;
9191 fCommentAttri_Bor: TSynHighlighterAttributes;
9292 fCommentAttri_Slash: TSynHighlighterAttributes;
9393 {/NEW}
9494 //Это позволяет нам возвращать различные атрибуты для каждого типа комментариев.
9595```
9696
9797- Затем найдите определение конструктора "TSynPasSyn", которое должно быть "constructor TSynPasSyn.Create(AOwner: TComponent);"
9898- Нам нужно создать наши новые атрибуты, таким образом, мы добавляем наши атрибуты где-нибудь в конструкторе (я предлагаю после значения по умолчанию "fCommentAttri")
9999
100100``` pascal
101101 (...)
102102 AddAttribute(fCommentAttri);
103103 {NEW}
104104 fCommentAttri_Ansi := TSynHighlighterAttributes.Create(SYNS_AttrComment+'_Ansi', SYNS_XML_AttrComment+'_Ansi'); // Последние две строки - это заголовок и сохраненное имя
105105 //Если вы хотите иметь настройки по умолчанию для вашего атрибута, вы можете, например, добавить это:
106106 //fCommentAttri_Ansi.Background := clBlack; //Установит "Background" в "clBlack" по умолчанию
107107 AddAttribute(fCommentAttri_Ansi);
108108 fCommentAttri_Bor := TSynHighlighterAttributes.Create(SYNS_AttrComment+'_Bor', SYNS_XML_AttrComment+'_Bor');
109109 AddAttribute(fCommentAttri_Bor);
110110 fCommentAttri_Slash := TSynHighlighterAttributes.Create(SYNS_AttrComment+'_Slash', SYNS_XML_AttrComment+'_Slash');
111111 AddAttribute(fCommentAttri_Slash);
112112 {/NEW}
113113 (...)
114114```
115115
116116- «Сложная» часть теперь состоит в том, чтобы найти места в коде, где "FTokenID" установлен в "tkComment", и установить наш «подтип» одинаково (конечно, я их уже поискал :)
117117
118118``` pascal
119119procedure TSynPasSyn.BorProc;
120120(...)
121121 fTokenID := tkComment;
122122 {NEW}
123123 FCommentID:=tckBor;
124124 {/NEW}
125125 if rsIDEDirective in fRange then
126126(...)
127127```
128128
129129``` pascal
130130procedure TSynPasSyn.AnsiProc;
131131begin
132132 fTokenID := tkComment;
133133 {NEW}
134134 FCommentID:=tckAnsi;
135135 {/NEW}
136136(...)
137137```
138138
139139``` pascal
140140procedure TSynPasSyn.RoundOpenProc;
141141(...)
142142 fTokenID := tkComment;
143143 {NEW}
144144 FCommentID:=tckAnsi;
145145 {/NEW}
146146 fStringLen := 2; // length of "(*"
147147(...)
148148```
149149
150150``` pascal
151151procedure TSynPasSyn.SlashProc;
152152begin
153153 if fLine[Run+1] = '/' then begin
154154 fTokenID := tkComment;
155155 {NEW}
156156 FCommentID:=tckSlash;
157157 {/NEW}
158158 if FAtLineStart then begin
159159(...)
160160```
161161
162162``` pascal
163163procedure TSynPasSyn.SlashContinueProc;
164164(...)
165165 fTokenID := tkComment;
166166 {NEW}
167167 FCommentID:=tckSlash;
168168 {/NEW}
169169 while not(fLine[Run] in [#0, #10, #13]) do
170170(...)
171171```
172172
173173- Теперь нам просто нужно извлечь информацию при вызове "GetTokenAttribute" и вернуть правильный атрибут, поэтому мы отредактируем "GetTokenAttribute" следующим образом:
174174
175175``` pascal
176176function TSynPasSyn.GetTokenAttribute: TSynHighlighterAttributes;
177177begin
178178 case GetTokenID of
179179 tkAsm: Result := fAsmAttri;
180180 {OLD
181181 tkComment: Result := fCommentAttri; //Это закомментировано и на всякий пожарный сохранено, поэтому оно будет игнорироваться
182182 /OLD}
183183 {NEW}
184184 tkComment: begin
185185 if (FCommentID=tckAnsi) then Result:=fCommentAttri_Ansi //Тип - AnsiComment
186186 else
187187 if (FCommentID=tckBor) then Result:=fCommentAttri_Bor //Тип - BorComment
188188 else
189189 if (FCommentID=tckSlash) then Result:=fCommentAttri_Slash //Тип - SlashComment
190190 else
191191 Result:=fCommentAttri //Если наш код каким-то образом упал, возврат к умолчанию
192192 end;
193193 {/NEW}
194194 tkIDEDirective: begin
195195(...)
196196```
197197
198198Если вы используете lazarus, просто переустановите SynEdit-Package, если нет, перекомпилируйте ваш проект/пакет/\<аналог\>.
199199
200200**ГОТОВО! Нет, серьезно, теперь вы готовы отличать различные типы комментариев.**
201201
202202Lazarus-IDE автоматически определяет, какие атрибуты существуют, и показывает их в опциях, например сохраняет их, если вы их изменяете. Если ваше приложение/IDE не делает этого, вам придется установить Color/Font/ и т.д. новых атрибутов где-то вручную (например, в конструкторе TSynPasSyn)
203203
204204### Плагины для автозавершения кода
205205
206206Для SynEdit есть 3 подключаемых плагина автозавершения кода:
207207
208208[[TSynCompletion]]
209209
210-- Предлагает список слов в раскрывающемся списке с помощью сочетания клавиш (по умолчанию: <span class="kbd">Ctrl</span>+<span class="kbd">space</span>).
210+- Предлагает список слов в раскрывающемся списке с помощью сочетания клавиш (по умолчанию: `Ctrl`+`space`).
211211- Используется в IDE для автозавершения идентификатора.
212212- Включен в примеры.
213213- Доступен в палитре компонентов (начиная с 0.9.3x).
214214
215215Пример кода, чтобы вызвать автозавершение, всплывает программно (т.е. без нажатия сочетания клавиш):
216216
217217``` pascal
218218YourSynEdit.CommandProcessor(YourSynCompletion.ExecCommandID, '', nil)
219219```
220220
221221[[TSynAutoComplete]]
222222
223223- Заменяет текущий токен фрагментом текста. **Не** интерактивный. **Не** выпадающий.
224224- Включен в примеры.
225225- Доступен в палитре компонентов.
226226
227227[[TSynEditAutoComplete]]
228228
229229- Основной шаблон модуля. **Не** выпадающий.
230230- Используется IDE для шаблонов кода. IDE содержит дополнительный код, расширяющий эту функцию (IDE добавляет макросы выпадающего списка и синхронизации).
231231- **Не** включен в примеры.
232232
233233Todo: Различия между 2-м и 3-м должны быть задокументированы. Может быть, они могут быть объединены.
234234
235235### Логическая/Физическая позиция каретки
236236
237237SynEdit предлагает положение каретки (текстовый мигающий курсор) в 2 различных формах:
238238
239239- Физический X/Y: соответствует визуальной (холст) позиции
240240- Логический X/Y: соответствует байтовому смещению текста
241241
242242Оба основаны на 1 (отсчет начинается с 1). В настоящее время координаты Y всегда одинаковы. Это может измениться в будущем.
243243
244244Физическая координата
245245это позиция в сетке дисплея (без учета прокрутки). То есть:
246246
247247обе буквы "a" и "â" занимают ОДНУ ячейку в сетке, увеличивая физический x на 1. Несмотря на то, что в кодировке utf8 "a" занимает один байт, а "â" занимает несколько байтов.
248248
249249однако символ табуляции (#9), помимо одного байта и одного символа, может занимать несколько ячеек в сетке, увеличивая физический x более, чем на одну позицию. Есть также некоторые символы в китайском и восточном языках, которые занимают 2 позиции в сетке (гуглите отличие full-width(полной ширины) от half-width (полуширины) символа).
250250
251251Логическая координата
252252смещение байта в строчке, содержащей строку.
253253
254254буква «а» имеет 1 байт и увеличивается на 1
255255
256256буква "â" имеет 2 (или 3) байта и увеличивается на эту величину
257257
258258символ tab имеет 1 байт и увеличивается на эту величину.
259259
260260Ни один из 2 не дает позицию в символах/кодовых точках UTF8 (например, для Utf8Copy или Utf8Length).
261261
262262Физический X всегда отсчитывается слева от текста, даже если он прокручивается. Чтобы получить grid-x текущего прокручиваемого элемента управления, выполните:
263263
264264
265265grid-X-in-visible-part-of-synedit := PhysicalX - SynEdit.LeftChar + 1
266266
267267grid-y-in-visible-part-of-synedit := SynEdit.RowToScreenRow(PhysicalY); // включает в себя складывание (схлопывание) текста
268268
269269используйте ScreenRowToRow для обратного процесса
270270
271271### Изменение текста из кода
272272
273-> **Warning:** Изменение текста с помощью свойства <i>SynEdit.Lines</i> <u>не работает с undo/redo.</u>
273+> **Warning:** Изменение текста с помощью свойства SynEdit.Lines не работает с undo/redo.
274274
275275Доступ к тексту можно получить через SynEdit.Lines. Это свойство на основе TStrings, предлагающее доступ на чтение/запись к каждой строке. Основано на нумерации строк с 0.
276276
277277``` pascal
278278 SynEdit.Lines[0] := 'Text'; // первая строчка
279279```
280280
281281SynEdit.Lines можно использовать для установки начальной версии текста (например, загруженного из файла). Обратите внимание, что методы SynEdit.Lines.Add/SynEdit.Lines.Append не поддерживают разрывы строк внутри добавленных строк. Вы должны добавлять строки одну за другой.
282282
283283Чтобы изменить содержимое SynEdit и позволить пользователю отменить действие, используйте следующие методы:
284284
285285``` pascal
286286 procedure InsertTextAtCaret(aText: String; aCaretMode: TSynCaretAdjustMode = scamEnd);
287287 property TextBetweenPoints[aStartPoint, aEndPoint: TPoint]: String // Логические точки
288288 read GetTextBetweenPoints write SetTextBetweenPointsSimple;
289289 property TextBetweenPointsEx[aStartPoint, aEndPoint: TPoint; CaretMode: TSynCaretAdjustMode]: String
290290 write SetTextBetweenPointsEx;
291291 procedure SetTextBetweenPoints(aStartPoint, aEndPoint: TPoint;
292292 const AValue: String;
293293 aFlags: TSynEditTextFlags = [];
294294 aCaretMode: TSynCaretAdjustMode = scamIgnore;
295295 aMarksMode: TSynMarksAdjustMode = smaMoveUp;
296296 aSelectionMode: TSynSelectionMode = smNormal );
297297```
298298
299299Примеры:
300300
301301``` pascal
302302 // Вставляем текст в позицию каретки
303303 SynEdit.InsertTextAtCaret('Text');
304304 // Заменяем текст с (x=2,y=10) на (x=4,y=20) с помощью Str
305305 SynEdit.TextBetweenPoints[Point(2,10), Point(4,20)] := Str;
306306```
307307
308308``` pascal
309309 // Удаляем/заменяем один символ в позиции каретки
310310 var p1, p2: TPoint;
311311 begin
312312 p1 := SynEdit.LogicalCaretXY;
313313 p2 := p1;
314314 // Высчитываем позицию байта следующего символа
315315 p2.x := p2.x + UTF8CharacterLength(@SynEdit.LineText[p2.x]);
316316 // p1 указывает на первый байт заменяемого символа
317317 // p2 указывает на первый байт символа после последнего заменяемого символа
318318 // Заменяем на "Text" (или используем пустую строку для удаления)
319319 SynEdit.TextBetweenPoints[p1, p2] := 'Text';
320320```
321321
322322### Сворачивание/Разворачивание текста из кода
323323
324324- Это все еще находится в стадии разработки.
325325- Это работает, только если текущий маркер подсветки поддерживает сворачивание (подробности в [[SynEdit Highlighter]]).
326326- Также обратите внимание, что некоторые маркеры подсветки поддерживают несколько независимых сворачиваемых деревьев. Например, в Паскале у вас есть сворачивание по ключевым словам (`begin`, `end`, `class`, `procedure` и т.д.), которое является основным, и сворачивание по `$ifdef` или `$region`, которое является дополнительным.
327327- Сворачивание текущего выделения также отличается от сворачивания по ключевым словам.
328328
329329Методы сворачивания:
330330
3313311\) TSynEdit.CodeFoldAction
332332
333333Сворачивание в данной строчке. Если их больше одной, сворачивается самая внутренняя (самая правая).
334334
335335> **Note:** Это не работает ни с выделением, ни с блоком сворачиваемого кода, которые уже полностью скрыт/требуется тестирование для дополнительных блоков сворачиваемого кода.
336336
3373372\) TSynEdit.FindNextUnfoldedLine
338338
3393393\) TSynEdit.FoldAll / TSynEdit.UnfoldAll
340340
341341### Закладки
342342
343343- [Топик форума о добавлении меток и цветных линий](http://forum.lazarus.freepascal.org/index.php/topic,14948.msg79794.html)
344344
345345### Дополнительная информация
346346
347347Обсуждения на форуме, которые содержат информацию о SynEdit:
348348
349349- [Search/replace; caret; position logical/physical](http://forum.lazarus.freepascal.org/index.php/topic,19520.msg111158.html#msg111158)
350350- [Diff between SynEdit/SynMemo](http://forum.lazarus.freepascal.org/index.php/topic,19645.msg111962.html#msg111962)
351351- [Mouse actions; disable paste on middle click](http://forum.lazarus.freepascal.org/index.php/topic,23997.msg144100.html#msg144100)
352352- [TSynEditMarkup info](http://forum.lazarus.freepascal.org/index.php?topic=24842)
353353
354354### Примеры приложений
355355
356356Примеры приложений можно найти в папке "lazarus/examples/synedit".
357357
358358### Добавление горячих клавиш для Cut/Copy/Paste/и т.д.
359359
360360Горячие клавиши могут быть реализованы с помощью команд SynEdit.
361361
362362``` pascal
363363uses
364364 SynEdit, SynEditKeyCmds;
365365
366366procedure TForm1.SynEdit1KeyDown(Sender: TObject; var Key: Word;
367367 Shift: TShiftState);
368368begin
369369 if (Shift = [ssCtrl]) then
370370 begin
371371 case Key of
372372 VK_C: SynEdit1.CommandProcessor(TSynEditorCommand(ecCopy), ' ', nil);
373373 VK_V: SynEdit1.CommandProcessor(TSynEditorCommand(ecPaste), ' ', nil);
374374 VK_X: SynEdit1.CommandProcessor(TSynEditorCommand(ecCut), ' ', nil);
375375 end;
376376 end;
377377end;
378378```
379379
380380## Дальнейшее развитие, обсуждение
381381
382382- RTL (справа налево): начат Mazen'ом (частично реализован в Windows)
383383- SynEdit использует только UTF8; версия ASCII/ANSI больше не существует. Шрифт предварительно выбирается в зависимости от системы. Пользователь может выбрать другой шрифт, но затем должен позаботиться о выборе моноширинного шрифта.
384384 - автоматический выбор моноширинного шрифта: в данный момент SynEdit запускается со использованием шрифта 'courier'. На данный момент TFont LCL не предоставляет свойство для фильтрации моноширинных шрифтов.
385385 - автоматический выбор шрифта UTF-8: по аналогии с выше описанным моноширинным шрифтом + также со шрифтом UTF-8, так что, например, умлауты отображаются правильно.
386386- "Немые" клавиши. Большинство клавиатур поддерживают ввод с использованием двух или более клавиш для создания одного специального символа (например, символы ударения или умлаута). (Это обрабатывается LCL widgedset)
387387- [[Redesign of the SynEdit component|Редизайн компонента SynEdit]]. Основная задача - более надежное отображение и навигация по тексту. Более модульный подход также позволяет лучше интегрировать расширения и специализированные элементы управления для использования вне Lazarus.
388388- [Перенос слов](http://bugs.freepascal.org/view.php?id=30395). Это экспериментальная реализация, следующая идее классов TextTrimmer/TabExpansion. У связанной проблемы bugtraker есть класс и объяснение изменений, требуемых в других файлах для его работы.
389389- Хуки в обработке клавиши/команды SynEdit. На форуме:<http://forum.lazarus-ide.org/index.php/topic,35592.msg243316.html#msg243316>
390390
391391## См. также
392392
393393- [[SynEdit Highlighter]]
394394- ["Изменение существующего маркера подсветки": немецкая ветка форума на "lazarusforum.de"](http://www.lazarusforum.de/viewtopic.php?f=5&t=8723)
395395- [[ATSynEdit]]
396396
397397---
398398*From the Free Pascal wiki, page "SynEdit/ru", as it stood on 2019-09-04 after a change by Zoltanleo, 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).*
399399Category: Components/ru
400400Category: Lazarus/ru
401401Category: Russian
402402Category: Russian (unfinished translation)
403403Category: SynEdit/ru

Back to history