Sign in Join
Wiki copytemporary

SynEdit: what changed

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

OldNewLine
1-**SynEdit** is a [[Syntax highlighting|syntax highlighting]] edit/memo package available on the [[SynEdit tab]] with support for many languages/syntaxes.
1+**SynEdit** is a [[Syntax highlighting|syntax highlighting]] edit/memo package available on the [[SynEdit tab]] with support for many languages/syntaxes.
22
3-The SynEdit contained in Lazarus was forked from [SynEdit 1.0.3](http://synedit.sourceforge.net/), and was adapted and extended quite a lot. Changes are listed below.
3+The SynEdit contained in Lazarus was forked from [SynEdit 1.0.3](<http://synedit.sourceforge.net/>), and was adapted and extended quite a lot. Changes are listed below.
44
5-Lazarus package contains a source editor component named [[TSynEdit]], several syntax highlighters and other components used for source editing.
5+Lazarus package contains a source editor component named [[TSynEdit]], several syntax highlighters and other components used for source editing.
66
7-Licensed under the same terms as the original SynEdit (MPL or GPL).
7+Licensed under the same terms as the original SynEdit (MPL or GPL).
88
99## Original vs Lazarus version
1010
11-Lazarus version is maintained mostly by Martin Friebe. Martin wrote at forum, what has been added to Lazarus version since fork appeared:
11+Lazarus version is maintained mostly by [Martin Friebe](</User:Martin> "User:Martin"). Martin wrote at forum, what has been added to Lazarus version since fork appeared:
1212
13-Big things added to the Lazarus version:
13+Big things added to the Lazarus version:
1414
15-- folding
16-- configurable gutter / gutter-parts
17-- shared text between several editors
18-- utf-8 support
19-- sync-editing plugin
20-- basic RTL/LTR support
21-- mouse config via MouseActions
22-- rewrite of various highlight/markup modules
15+ * folding
16+ * configurable gutter / gutter-parts
17+ * shared text between several editors
18+ * utf-8 support
19+ * sync-editing plugin
20+ * basic RTL/LTR support
21+ * mouse config via MouseActions
22+ * rewrite of various highlight/markup modules
2323
24-Codebases of Delphi/Lazarus versions were independently refactored. There is very few overlap left.
24+Codebases of Delphi/Lazarus versions were independently refactored. There is very few overlap left.
2525
2626## SynEdit 2.0 port
2727
28-An alternative port of the 2.0.x version of the original SynEdit exists. It's not actively maintained, last commit (now is Jun 2014) was at 2011.
28+An alternative port of the 2.0.x version of the original SynEdit exists. It's not actively maintained, last commit (now is Jun 2014) was at 2011.
2929
30-- [[SynEdit/port]]
31-- [Github page](https://github.com/rnapoles/)
30+ * [[SynEdit/port]]
31+ * [Github page](<https://github.com/rnapoles/>)
3232
3333## SynEdit in the IDE
3434
35-The SynEdit in Lazarus is a built-in package, because the IDE uses it itself. Therefore the package can not be removed from the installation list. To remove the entries from the component palette, the SynEditDsgn package can be removed from installation.
35+The SynEdit in Lazarus is a built-in package, because the IDE uses it itself. Therefore the package can not be removed from the installation list. To remove the entries from the component palette, the SynEditDsgn package can be removed from installation.
3636
3737## Using SynEdit
3838
3939### Highlighters
4040
41-- There are several standard highlighters (see [[SynEdit tab]] in the [[Component Palette]])
42-- There are scriptable highlighters, which can adapt to many other file formats:
43- - [[TSynAnySyn]] (standard, on component palette by default)
44- - [[TSynPositionHighlighter]] (standard, **not** on component palette)
45- - [[TSynUniHighlighter]] (standard, **not** on component palette)
46- - SynFacilSyn ([Github](https://github.com/t-edson/SynFacilSyn))
47-- More 3rd-party highlighters exist: SynCacheSyn, SynGeneralSyn, SynRCSyn, SynRubySyn, SynSDDSyn, SynSMLSyn, SynSTSyn, SynTclTkSyn, SynUnrealSyn, SynURISyn, SynVBScriptSyn, SynVrml97Syn, [see here](http://bugs.freepascal.org/view.php?id=18248).
48-- You can write new highlighter, see info at [[SynEdit Highlighter]].
41+ * There are several standard highlighters (see [[SynEdit tab]] in the [[Component Palette]])
42+ * There are scriptable highlighters, which can adapt to many other file formats:
43+ * [[TSynAnySyn]] (standard, on component palette by default)
44+ * [[TSynPositionHighlighter]] (standard, **not** on component palette)
45+ * [[TSynUniHighlighter]] (standard, **not** on component palette)
46+ * SynFacilSyn ([Github](<https://github.com/t-edson/SynFacilSyn>))
47+ * More 3rd-party highlighters exist: SynCacheSyn, SynGeneralSyn, SynRCSyn, SynRubySyn, SynSDDSyn, SynSMLSyn, SynSTSyn, SynTclTkSyn, SynUnrealSyn, SynURISyn, SynVBScriptSyn, SynVrml97Syn, [see here](<http://bugs.freepascal.org/view.php?id=18248>).
48+ * You can write new highlighter, see info at [[SynEdit Highlighter]].
4949
5050### Markup
5151
5252Markup provides additional coloring [[SynEdit Markup]]
5353
5454### Edit an existing highlighter
5555
56-Sometimes you might want to edit existing highlighters (just like I wanted a few days ago) that already exist. In this example we're going to edit the highlighter for pascal-like code (classname: [[TSynPasSyn]]; package: SynEdit V1.0; unit: SynHighlighterPas.pas).
57-
58-Say, what we want to reach is, that our application (lazarus in this case) differs between the three types of comments, which exist in Pascal:
56+Sometimes you might want to edit existing highlighters (just like I wanted a few days ago) that already exist. In this example we're going to edit the highlighter for pascal-like code (classname: [[TSynPasSyn]]; package: SynEdit V1.0; unit: SynHighlighterPas.pas).
5957
60-``` pascal
61- (* ansi *)
62- { bor }
63- // Slash
58+Say, what we want to reach is, that our application (lazarus in this case) differs between the three types of comments, which exist in Pascal:
6459```
65-
66-This may be helpful, if you want to differ between different types of your comments (e.g. "Description", "Note", "Reference", etc.) and want them to be e.g. colored in different ways.
60+(* ansi *)
61+ { bor }
62+ // Slash
63+```
6764
68-> **Note:** Just in case you break something, I suggest to make some "NEW" and "/NEW"-comments, but you don't have to
65+This may be helpful, if you want to differ between different types of your comments (e.g. "Description", "Note", "Reference", etc.) and want them to be e.g. colored in different ways.
6966
70-- First, open the unit "SynHighlighterPas" which should be located in your SynEdit-directory.
71-- As we don't want to cause incompatibilities, we're creating a new type of enumerator which helps us to identify our comment later:
67+![Light bulb](https://upload.wikimedia.org/wikipedia/commons/d/d8/Nuvola_apps_ktip.png) **Note:** Just in case you break something, I suggest to make some "NEW" and "/NEW"-comments, but you don't have to
7268
73-E.g. under the declaration of "tkTokenKind", write this:
69+ * First, open the unit "SynHighlighterPas" which should be located in your SynEdit-directory.
70+ * As we don't want to cause incompatibilities, we're creating a new type of enumerator which helps us to identify our comment later:
7471
75-``` pascal
76- {NEW}
77- TtckCommentKind = (tckAnsi, tckBor, tckSlash);
78- {/NEW}
72+E.g. under the declaration of "tkTokenKind", write this:
7973```
74+{NEW}
75+ TtckCommentKind = (tckAnsi, tckBor, tckSlash);
76+ {/NEW}
77+```
8078
81-- In the declaration of "TSynPasSyn" search for "FTokenID" and add the following between "FTokenID" and the next field
79+ * In the declaration of "TSynPasSyn" search for "FTokenID" and add the following between "FTokenID" and the next field
8280
83-``` pascal
84- {NEW}
85- FCommentID: TtckCommentKind;
86- {/NEW}
87- //This creates a new field, where we can store the information, what kind of comment we have
8881```
82+{NEW}
83+ FCommentID: TtckCommentKind;
84+ {/NEW}
85+ //This creates a new field, where we can store the information, what kind of comment we have
86+```
8987
90-- In the declaration of "TSynPasSyn" search for "fCommentAttri" and add the following between "fCommentAttri" and the next field
88+ * In the declaration of "TSynPasSyn" search for "fCommentAttri" and add the following between "fCommentAttri" and the next field
9189
92-``` pascal
93- {NEW}
94- fCommentAttri_Ansi: TSynHighlighterAttributes;
95- fCommentAttri_Bor: TSynHighlighterAttributes;
96- fCommentAttri_Slash: TSynHighlighterAttributes;
97- {/NEW}
98- //This allows us, to return different Attributes, per type of comment
9990```
91+{NEW}
92+ fCommentAttri_Ansi: TSynHighlighterAttributes;
93+ fCommentAttri_Bor: TSynHighlighterAttributes;
94+ fCommentAttri_Slash: TSynHighlighterAttributes;
95+ {/NEW}
96+ //This allows us, to return different Attributes, per type of comment
97+```
10098
101-- Next, search for the constructor-definition of "TSynPasSyn", which should be "constructor TSynPasSyn.Create(AOwner: TComponent);"
102-- We need to Create our new Attributes, thus we add our Attributes somewhere in the constructor (I suggest, after the default "fCommentAttri")
99+ * Next, search for the constructor-definition of "TSynPasSyn", which should be "constructor TSynPasSyn.Create(AOwner: TComponent);"
100+ * We need to Create our new Attributes, thus we add our Attributes somewhere in the constructor (I suggest, after the default "fCommentAttri")
103101
104-``` pascal
105- (...)
106- AddAttribute(fCommentAttri);
107- {NEW}
108- fCommentAttri_Ansi := TSynHighlighterAttributes.Create(SYNS_AttrComment+'_Ansi', SYNS_XML_AttrComment+'_Ansi'); //The last two strings are the Caption and the stored name
109- //If you want to have default settings for your attribute, you can e.g. add this:
110- //fCommentAttri_Ansi.Background := clBlack; //Would set "Background" to "clBlack" as default
111- AddAttribute(fCommentAttri_Ansi);
112- fCommentAttri_Bor := TSynHighlighterAttributes.Create(SYNS_AttrComment+'_Bor', SYNS_XML_AttrComment+'_Bor');
113- AddAttribute(fCommentAttri_Bor);
114- fCommentAttri_Slash := TSynHighlighterAttributes.Create(SYNS_AttrComment+'_Slash', SYNS_XML_AttrComment+'_Slash');
115- AddAttribute(fCommentAttri_Slash);
116- {/NEW}
117- (...)
118102```
103+(...)
104+ AddAttribute(fCommentAttri);
105+ {NEW}
106+ fCommentAttri_Ansi := TSynHighlighterAttributes.Create(SYNS_AttrComment+'_Ansi', SYNS_XML_AttrComment+'_Ansi'); //The last two strings are the Caption and the stored name
107+ //If you want to have default settings for your attribute, you can e.g. add this:
108+ //fCommentAttri_Ansi.Background := clBlack; //Would set "Background" to "clBlack" as default
109+ AddAttribute(fCommentAttri_Ansi);
110+ fCommentAttri_Bor := TSynHighlighterAttributes.Create(SYNS_AttrComment+'_Bor', SYNS_XML_AttrComment+'_Bor');
111+ AddAttribute(fCommentAttri_Bor);
112+ fCommentAttri_Slash := TSynHighlighterAttributes.Create(SYNS_AttrComment+'_Slash', SYNS_XML_AttrComment+'_Slash');
113+ AddAttribute(fCommentAttri_Slash);
114+ {/NEW}
115+ (...)
116+```
119117
120-- The "complex" part now is, to search for the points, where "FTokenID" is set to "tkComment" and to set our "subtype", equally (of course, I've already searched them:)
118+ * The "complex" part now is, to search for the points, where "FTokenID" is set to "tkComment" and to set our "subtype", equally (of course, I've already searched them:)
121119
122-``` pascal
120+```
123121procedure TSynPasSyn.BorProc;
124-(...)
125- fTokenID := tkComment;
126- {NEW}
127- FCommentID:=tckBor;
128- {/NEW}
129- if rsIDEDirective in fRange then
130-(...)
122+ (...)
123+ fTokenID := tkComment;
124+ {NEW}
125+ FCommentID:=tckBor;
126+ {/NEW}
127+ if rsIDEDirective in fRange then
128+ (...)
131129```
132-
133-``` pascal
130+```
134131procedure TSynPasSyn.AnsiProc;
135-begin
136- fTokenID := tkComment;
137- {NEW}
138- FCommentID:=tckAnsi;
139- {/NEW}
140-(...)
132+ begin
133+ fTokenID := tkComment;
134+ {NEW}
135+ FCommentID:=tckAnsi;
136+ {/NEW}
137+ (...)
141138```
142-
143-``` pascal
139+```
144140procedure TSynPasSyn.RoundOpenProc;
145-(...)
141+ (...)
142+ fTokenID := tkComment;
143+ {NEW}
144+ FCommentID:=tckAnsi;
145+ {/NEW}
146+ fStringLen := 2; // length of "(*"
147+ (...)
148+```
149+```
150+procedure TSynPasSyn.SlashProc;
151+ begin
152+ if fLine[Run+1] = '/' then begin
146153 fTokenID := tkComment;
147154 {NEW}
148- FCommentID:=tckAnsi;
155+ FCommentID:=tckSlash;
149156 {/NEW}
150- fStringLen := 2; // length of "(*"
151-(...)
157+ if FAtLineStart then begin
158+ (...)
152159```
153-
154-``` pascal
155-procedure TSynPasSyn.SlashProc;
156-begin
157- if fLine[Run+1] = '/' then begin
158- fTokenID := tkComment;
159- {NEW}
160- FCommentID:=tckSlash;
161- {/NEW}
162- if FAtLineStart then begin
163-(...)
164160```
165-
166-``` pascal
167161procedure TSynPasSyn.SlashContinueProc;
168-(...)
169- fTokenID := tkComment;
170- {NEW}
171- FCommentID:=tckSlash;
172- {/NEW}
173- while not(fLine[Run] in [#0, #10, #13]) do
174-(...)
162+ (...)
163+ fTokenID := tkComment;
164+ {NEW}
165+ FCommentID:=tckSlash;
166+ {/NEW}
167+ while not(fLine[Run] in [#0, #10, #13]) do
168+ (...)
175169```
176170
177-- Now, we just have to retreve the information when "GetTokenAttribute" is called and return the right Attribute, therefore we edit "GetTokenAttribute" as follows:
171+ * Now, we just have to retreve the information when "GetTokenAttribute" is called and return the right Attribute, therefore we edit "GetTokenAttribute" as follows:
178172
179-``` pascal
173+```
180174function TSynPasSyn.GetTokenAttribute: TSynHighlighterAttributes;
181-begin
182- case GetTokenID of
183- tkAsm: Result := fAsmAttri;
184- {OLD
185- tkComment: Result := fCommentAttri; //This is commented and just backup, so it'll be ignored
186- /OLD}
187- {NEW}
188- tkComment: begin
189- if (FCommentID = tckAnsi) then
190- Result := fCommentAttri_Ansi //Type is AnsiComment
191- else
192- if (FCommentID = tckBor) then
193- Result := fCommentAttri_Bor //Type is BorComment
194- else
195- if (FCommentID = tckSlash) then
196- Result := fCommentAttri_Slash //Type is SlashComment
175+ begin
176+ case GetTokenID of
177+ tkAsm: Result := fAsmAttri;
178+ {OLD
179+ tkComment: Result := fCommentAttri; //This is commented and just backup, so it'll be ignored
180+ /OLD}
181+ {NEW}
182+ tkComment: begin
183+ if (FCommentID = tckAnsi) then
184+ Result := fCommentAttri_Ansi //Type is AnsiComment
197185 else
198- Result := fCommentAttri //If our code failed somehow, fallback to default
199- end;
200- {/NEW}
201- tkIDEDirective: begin
202-(...)
186+ if (FCommentID = tckBor) then
187+ Result := fCommentAttri_Bor //Type is BorComment
188+ else
189+ if (FCommentID = tckSlash) then
190+ Result := fCommentAttri_Slash //Type is SlashComment
191+ else
192+ Result := fCommentAttri //If our code failed somehow, fallback to default
193+ end;
194+ {/NEW}
195+ tkIDEDirective: begin
196+ (...)
203197```
204198
205-If you do use lazarus, just reinstall the SynEdit-Package, if not, recompile your project/the package/\<similar\>.
199+If you do use lazarus, just reinstall the SynEdit-Package, if not, recompile your project/the package/<similar>.
206200
207201**DONE ! No seriously, you are now ready to differ between the different types of comments.**
208202
209-The lazarus-IDE does automatically detect, what attributes exist and shows them in the options, such as saves them, if you change them. If your application/IDE doesn't do this, you will have to set Color/Font/etc. of the new Attributes somewhere manually (e.g. in the constructor of TSynPasSyn)
203+The lazarus-IDE does automatically detect, what attributes exist and shows them in the options, such as saves them, if you change them. If your application/IDE doesn't do this, you will have to set Color/Font/etc. of the new Attributes somewhere manually (e.g. in the constructor of TSynPasSyn)
210204
211205### Completion plugins
212206
213-There are 3 completion plug-ins for SynEdit:
214-
215-[[TSynCompletion]]
207+There are 3 completion plug-ins for SynEdit:
216208
217-- Offers a list of words in a drop-down via a shortcut key combination (default: Ctrl-Space).
218-- Used in the IDE for identifier completion.
219-- Included in examples.
220-- Available on the component palette (since 0.9.3x).
209+**[[TSynCompletion]]**
221210
222-Example code to invoke the completion pop up programmatically (i.e. without pressing the keyboard shortcut):
211+ * Offers a list of words in a drop-down via a shortcut key combination (default: Ctrl-Space).
212+ * Used in the IDE for identifier completion.
213+ * Included in examples.
214+ * Available on the component palette (since 0.9.3x).
223215
224-``` pascal
216+Example code to invoke the completion pop up programmatically (i.e. without pressing the keyboard shortcut):
217+```
225218YourSynEdit.CommandProcessor(YourSynCompletion.ExecCommandID, '', nil)
226219```
227220
228-[[TSynAutoComplete]]
229-
230-- Replaces the current token with a piece of text. **Not** interactive. **No** drop-down.
231-- Included in examples.
232-- Available on the component palette.
233-
234-[[TSynEditAutoComplete]]
221+**[[TSynAutoComplete]]**
235222
236-- Basic template module. **No** drop-down.
237-- Used by IDE for code-templates. IDE contains additional code extending the feature (drop-down and syncro macros are added by IDE).
238-- **Not** included in examples.
223+ * Replaces the current token with a piece of text. **Not** interactive. **No** drop-down.
224+ * Included in examples.
225+ * Available on the component palette.
239226
240-Todo: Differences between 2nd and 3rd need to be documented. Maybe they can be merged.
227+**[[TSynEditAutoComplete]]**
241228
242-### Logical/Physical caret position
229+ * Basic template module. **No** drop-down.
230+ * Used by IDE for code-templates. IDE contains additional code extending the feature (drop-down and syncro macros are added by IDE).
231+ * **Not** included in examples.
243232
244-SynEdit offers position of the caret (text blinking cursor) in 2 different forms:
233+Todo: Differences between 2nd and 3rd need to be documented. Maybe they can be merged.
245234
246-- Physical X/Y: Corresponds to visual (canvas) position,
247-- Logical X/Y: Corresponds to byte offset of the text.
235+### Logical, Physical or Viewed caret position
248236
249-Both are 1-based. Currently Y coordinates are always the same. This may change in future.
237+SynEdit offers position of the caret (text blinking cursor) in different forms:
250238
251-The Physical coordinate
252-is the position in the display grid (ignoring any scrolling). That is:
239+ * Logical X/Y: Corresponds to byte offset of the text.
240+ * Physical X/Y: Corresponds to monospaced grid position. **Not** taking any folding or Wrapping into account.
241+ * Viewed X/Y: Corresponds to visual (canvas) position. Or grid after folding and wrapping.
253242
254-the letter "a" and "â" take both ONE cell on the grid, increasing physical x by 1. Even though in utf8 encoding "a" takes one byte, and "â" takes several bytes.
243+All are 1-based.
255244
256-however the tab char (#9), besides being just one byte and one char, can take several cells in the grid, increasing the physical x by more than one. There are also some chars in Chinese and eastern languages, that take 2 grid positions (google full-width vs half-width char)
245+**The Logical coordinate**
257246
258-The Logical coordinate
259-is the byte offset in the string holding the line.
247+ * **X** is the byte offset in the string holding the line.
260248
261249the letter "a" has 1 byte and increases by 1
262250
263251the letter "â" has 2 (or 3) bytes, and increases by that
264252
265253tab has 1 byte and increases by that.
266254
267-Neither of the 2 give the position in UTF8 chars/code-points (e.g. for Utf8Copy or Utf8Length).
255+ * **Y** is the line in the text-buffer.
268256
269-The physical X is always counted from the left of the text, even if this is scrolled out. To get the grid-x of the currently scrolled control do:
257+each and all lines count as one. Lines on/off screen count, Hidden/Folded lines count, wrapped lines count as one single line.
270258
271-
259+**The Physical coordinate**
260+
261+ * **X** is the position in the display grid (ignoring any scrolling). That is:
262+
263+the letter "a" and "â" take both ONE cell on the grid, increasing physical x by 1. Even though in utf8 encoding "a" takes one byte, and "â" takes several bytes.
264+
265+however the tab char (#9), besides being just one byte and one char, can take several cells in the grid, increasing the physical x by more than one. There are also some chars in Chinese and eastern languages, that take 2 grid positions (google full-width vs half-width char)
266+
267+ * **Y** is the line in the text-buffer.
268+
269+each and all lines count as one. Lines on/off screen count, Hidden/Folded lines count, wrapped lines count as one single line.
270+
271+same as Logical
272+
273+**The Viewed coordinate**
274+
275+is the position in the display grid (ignoring any scrolling). That is:
276+
277+ * EXPERIMENTAL
278+
279+ * **X**
280+
281+cell coordinate, same as Physical. But wrapped.
282+
283+ * **Y**
284+
285+paintable lines: includes on/off screen lines
286+
287+excludes folded lines
288+
289+counts a wrapped line as multiple lines
290+
291+Neither of them give the position in UTF8 chars/code-points (e.g. for Utf8Copy or Utf8Length).
292+
293+The physical X is always counted from the left of the text, even if this is scrolled out. To get the grid-x of the currently scrolled control do:
294+
272295grid-X-in-visible-part-of-synedit := PhysicalX - SynEdit.LeftChar + 1
273296
274297grid-y-in-visible-part-of-synedit := SynEdit.RowToScreenRow(PhysicalY); // includes folding
275298
276299use ScreenRowToRow for reverse
277300
278301### Change text from code
279302
280-> **Warning:** Changing text via SynEdit.Lines property does not work with undo/redo.
303+[![Warning-icon.png](/wiki-images/b/b2/Warning-icon.png)](</File:Warning-icon.png>)
281304
282-Text can be accessed via SynEdit.Lines. This is a TStrings based property offering read/write access to each line. It is 0 based.
305+**Warning:** Changing text via _SynEdit.Lines_ property does _not work with undo/redo._
283306
284-``` pascal
285- SynEdit.Lines[0] := 'Text'; // first line
307+Text can be accessed via SynEdit.Lines. This is a TStrings based property offering read/write access to each line. It is 0 based.
286308```
287-
288-SynEdit.Lines can be used to set the initial version of the text (e.g. loaded from file). Note that SynEdit.Lines.Add/SynEdit.Lines.Append does not support line breaks inside the added strings. You should add lines one by one.
289-
290-To modify the content of a SynEdit, and allow the user to undo the action use the following methods:
291-
292-``` pascal
293- procedure InsertTextAtCaret(aText: String; aCaretMode: TSynCaretAdjustMode = scamEnd);
294- property TextBetweenPoints[aStartPoint, aEndPoint: TPoint]: String // Logical Points
295- read GetTextBetweenPoints write SetTextBetweenPointsSimple;
296- property TextBetweenPointsEx[aStartPoint, aEndPoint: TPoint; CaretMode: TSynCaretAdjustMode]: String
297- write SetTextBetweenPointsEx;
298- procedure SetTextBetweenPoints(aStartPoint, aEndPoint: TPoint;
299- const AValue: String;
300- aFlags: TSynEditTextFlags = [];
301- aCaretMode: TSynCaretAdjustMode = scamIgnore;
302- aMarksMode: TSynMarksAdjustMode = smaMoveUp;
303- aSelectionMode: TSynSelectionMode = smNormal );
309+SynEdit.Lines[0] := 'Text'; // first line
304310```
305311
306-Examples:
312+SynEdit.Lines can be used to set the initial version of the text (e.g. loaded from file). Note that SynEdit.Lines.Add/SynEdit.Lines.Append does not support line breaks inside the added strings. You should add lines one by one.
307313
308-``` pascal
309- // Insert text at caret
310- SynEdit.InsertTextAtCaret('Text');
311- // Replace text from (x=2,y=10) to (x=4,y=20) with Str
312- SynEdit.TextBetweenPoints[Point(2,10), Point(4,20)] := Str;
314+To modify the content of a SynEdit, and allow the user to undo the action use the following methods:
313315```
316+procedure InsertTextAtCaret(aText: String; aCaretMode: TSynCaretAdjustMode = scamEnd);
317+ property TextBetweenPoints[aStartPoint, aEndPoint: TPoint]: String // Logical Points
318+ read GetTextBetweenPoints write SetTextBetweenPointsSimple;
319+ property TextBetweenPointsEx[aStartPoint, aEndPoint: TPoint; CaretMode: TSynCaretAdjustMode]: String
320+ write SetTextBetweenPointsEx;
321+ procedure SetTextBetweenPoints(aStartPoint, aEndPoint: TPoint;
322+ const AValue: String;
323+ aFlags: TSynEditTextFlags = [];
324+ aCaretMode: TSynCaretAdjustMode = scamIgnore;
325+ aMarksMode: TSynMarksAdjustMode = smaMoveUp;
326+ aSelectionMode: TSynSelectionMode = smNormal );
327+```
314328
315-``` pascal
316- // Delete/replace single char at caret pos
317- var
318- p1, p2: TPoint;
319- begin
320- p1 := SynEdit.LogicalCaretXY;
321- p2 := p1;
322- // Calculate the byte pos of the next char
323- p2.x := p2.x + UTF8CharacterLength(@SynEdit.LineText[p2.x]);
324- // p1 points to the first byte of char to be replaced
325- // p2 points to the first byte of the char after the last replaceable char
326- // Replace with "Text" (or use empty string to delete)
327- SynEdit.TextBetweenPoints[p1, p2] := 'Text';
329+Examples:
328330```
331+// Insert text at caret
332+ SynEdit.InsertTextAtCaret('Text');
333+ // Replace text from (x=2,y=10) to (x=4,y=20) with Str
334+ SynEdit.TextBetweenPoints[Point(2,10), Point(4,20)] := Str;
335+```
336+```
337+// Delete/replace single char at caret pos
338+ var
339+ p1, p2: TPoint;
340+ begin
341+ p1 := SynEdit.LogicalCaretXY;
342+ p2 := p1;
343+ // Calculate the byte pos of the next char
344+ p2.x := p2.x + UTF8CharacterLength(@SynEdit.LineText[p2.x]);
345+ // p1 points to the first byte of char to be replaced
346+ // p2 points to the first byte of the char after the last replaceable char
347+ // Replace with "Text" (or use empty string to delete)
348+ SynEdit.TextBetweenPoints[p1, p2] := 'Text';
349+```
329350
330351### Fold/Unfold from code
331352
332-- This is still under construction.
333-- This only works if current highlighter supports folding (details at [[SynEdit Highlighter]]).
334-- Also note that some highlighters support several independent fold-trees. E.g. in Pascal you have folding on keywords (begin, end, class, procedure, etc) which is the primary fold, and folding on \$ifdef or \$region which is secondary.
335-- Folding of current selection is also different from folding on keywords.
353+ * This is still under construction.
354+ * This only works if current highlighter supports folding (details at [[SynEdit Highlighter]]).
355+ * Also note that some highlighters support several independent fold-trees. E.g. in Pascal you have folding on keywords (begin, end, class, procedure, etc) which is the primary fold, and folding on $ifdef or $region which is secondary.
356+ * Folding of current selection is also different from folding on keywords.
336357
337-Methods for folding:
358+Methods for folding:
338359
339-1\) TSynEdit.CodeFoldAction
360+1) TSynEdit.CodeFoldAction
340361
341-Folds at the given Line. If there are more than one, folds the inner most (right most). Note: This does not work with selection, nor with Folds that hide entirely / Need testing for 2ndary folds.
362+Folds at the given Line. If there are more than one, folds the inner most (right most). Note: This does not work with selection, nor with Folds that hide entirely / Need testing for 2ndary folds.
342363
343-2\) TSynEdit.FindNextUnfoldedLine
364+2) TSynEdit.FindNextUnfoldedLine
344365
345-3\) TSynEdit.FoldAll / TSynEdit.UnfoldAll
366+3) TSynEdit.FoldAll / TSynEdit.UnfoldAll
346367
347368### Bookmarks
348369
349-- [Forum topic about adding gutter-marks and colored lines](http://forum.lazarus.freepascal.org/index.php/topic,14948.msg79794.html)
370+ * [Forum topic about adding gutter-marks and colored lines](<http://forum.lazarus.freepascal.org/index.php/topic,14948.msg79794.html>)
350371
351372### More info
352373
353-Discussions on the forum, which contain info about SynEdit:
374+Discussions on the forum, which contain info about SynEdit:
354375
355-- [Search/replace; caret; position logical/physical](http://forum.lazarus.freepascal.org/index.php/topic,19520.msg111158.html#msg111158)
356-- [Diff between SynEdit/SynMemo](http://forum.lazarus.freepascal.org/index.php/topic,19645.msg111962.html#msg111962)
357-- [Mouse actions; disable paste on middle click](http://forum.lazarus.freepascal.org/index.php/topic,23997.msg144100.html#msg144100)
358-- [TSynEditMarkup info](http://forum.lazarus.freepascal.org/index.php?topic=24842)
376+ * [Search/replace; caret; position logical/physical](<http://forum.lazarus.freepascal.org/index.php/topic,19520.msg111158.html#msg111158>)
377+ * [Diff between SynEdit/SynMemo](<http://forum.lazarus.freepascal.org/index.php/topic,19645.msg111962.html#msg111962>)
378+ * [Mouse actions; disable paste on middle click](<http://forum.lazarus.freepascal.org/index.php/topic,23997.msg144100.html#msg144100>)
379+ * [TSynEditMarkup info](<http://forum.lazarus.freepascal.org/index.php?topic=24842>)
359380
360381### Example apps
361382
362-Example applications can be found in the folder "lazarus/examples/synedit".
383+Example applications can be found in the folder "lazarus/examples/synedit".
363384
364385### Adding hotkeys for Cut/Copy/Paste/etc
365386
366-Hotkeys can be implemented by using SynEdit commands.
367-
368-``` pascal
387+Hotkeys can be implemented by using SynEdit commands.
388+```
369389uses
370- SynEdit, SynEditKeyCmds;
371-
372-procedure TForm1.SynEdit1KeyDown(Sender: TObject; var Key: Word;
373- Shift: TShiftState);
374-begin
375- if (Shift = [ssCtrl]) then
376- case Key of
377- VK_C: SynEdit1.CommandProcessor(TSynEditorCommand(ecCopy), ' ', nil);
378- VK_V: SynEdit1.CommandProcessor(TSynEditorCommand(ecPaste), ' ', nil);
379- VK_X: SynEdit1.CommandProcessor(TSynEditorCommand(ecCut), ' ', nil);
390+ SynEdit, SynEditKeyCmds;
391+
392+ procedure TForm1.SynEdit1KeyDown(Sender: TObject; var Key: Word;
393+ Shift: TShiftState);
394+ begin
395+ if (Shift = [ssCtrl]) then
396+ case Key of
397+ VK_C: SynEdit1.CommandProcessor(TSynEditorCommand(ecCopy), ' ', nil);
398+ VK_V: SynEdit1.CommandProcessor(TSynEditorCommand(ecPaste), ' ', nil);
399+ VK_X: SynEdit1.CommandProcessor(TSynEditorCommand(ecCut), ' ', nil);
400+ end;
380401 end;
381-end;
382402```
383403
384404## Further development, discussions
385405
386-- RTL (right-to-left): started by Mazen (partly implemented on Windows)
387-- SynEdit only uses UTF8; an ASCII/ANSI version no longer exists. A font is pre-selected depending on the system. The user can choose another font, but must then take care to choose a monospaced font.
388- - automatic monospace font selection: At the moment SynEdit starts with a font 'courier'. At the moment the LCL TFont does not provide a property to filter monospaced fonts.
389- - automatic UTF-8 font selection: Same as above monospace, but also with an UTF-8 font, so that for example umlauts are shown correctly.
390-- Dead keys. Most keyboards support typing two or more keys to create one special character (like accented or umlaut characters). (This is handled by LCL widgedset)
391-- [[Redesign of the SynEdit component]]. The primary goal is more reliable display and navigation in the text. A more modular approach also allows for better integration of extensions, and for specialized controls, for use outside of Lazarus.
392-- [Word Wrapping](http://bugs.freepascal.org/view.php?id=30395). This is an experimental implementation following the idea of the TextTrimmer/TabExpansion classes. The linked bugtraker issue has the class and the explanation of changes required in other files for it to work.
393-- Hooks in SynEdit key/command processing. On the forum: <http://forum.lazarus-ide.org/index.php/topic,35592.msg243316.html#msg243316>
406+ * RTL (right-to-left): started by Mazen (partly implemented on Windows)
407+ * SynEdit only uses UTF8; an ASCII/ANSI version no longer exists. A font is pre-selected depending on the system. The user can choose another font, but must then take care to choose a monospaced font.
408+ * automatic monospace font selection: At the moment SynEdit starts with a font 'courier'. At the moment the LCL TFont does not provide a property to filter monospaced fonts.
409+ * automatic UTF-8 font selection: Same as above monospace, but also with an UTF-8 font, so that for example umlauts are shown correctly.
410+ * Dead keys. Most keyboards support typing two or more keys to create one special character (like accented or umlaut characters). (This is handled by LCL widgedset)
411+ * [[Redesign of the SynEdit component]]. The primary goal is more reliable display and navigation in the text. A more modular approach also allows for better integration of extensions, and for specialized controls, for use outside of Lazarus.
412+ * [Word Wrapping](<http://bugs.freepascal.org/view.php?id=30395>). This is an experimental implementation following the idea of the TextTrimmer/TabExpansion classes. The linked bugtraker issue has the class and the explanation of changes required in other files for it to work.
413+ * Hooks in SynEdit key/command processing. On the forum: <http://forum.lazarus-ide.org/index.php/topic,35592.msg243316.html#msg243316>
394414
395415## See also
396416
397-- [[SynEdit Highlighter]]
398-- ["Edit an existing highlighter": German forum thread at "lazarusforum.de"](http://www.lazarusforum.de/viewtopic.php?f=5&t=8723)
399-- [[ATSynEdit]]
417+ * [[SynEdit Highlighter]]
418+ * ["Edit an existing highlighter": German forum thread at "lazarusforum.de"](<http://www.lazarusforum.de/viewtopic.php?f=5&t=8723>)
419+ * [[ATSynEdit]]
400420
401421---
402-*From the Free Pascal wiki, page "SynEdit", as it stood on 2024-03-27 after a change by Wennerer, 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).*
403-Category: Components
404-Category: Lazarus
405-Category: SynEdit
422+*From the Free Pascal wiki, page "SynEdit", as the Internet Archive kept it on 2025-06-16, last changed on 2025-02-06. 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).*

Back to history