Sign in Join
Wiki copytemporary

ATSynEdit: what changed

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

OldNewLine
11# About
22
33**ATSynEdit** is the multi-line editor control.
44
55- Homepage: <https://github.com/Alexey-T/ATSynEdit>
66- Support for EControl adapter: <https://github.com/Alexey-T/EControl>
77
88Author: Alexey Torgashin
99
1010![](/wiki-images/e/eb/Atsynedit.png)
1111
1212# License
1313
1414ATSynEdit files licensed under MPL 2.0. You can optionally use them under LGPL if your project needs it.
1515
1616EControl files licensed under special license (readme.txt), usage allowed only in open-source projects.
1717
1818# Keyboard shortcuts
1919
2020Run demo_editor and call menu item "Help - Commands'. You'll see all shortcuts in a dialog like this:
2121
2222![](/wiki-images/d/db/Atsynedit_keymap.png)
2323
2424# Mouse shortcuts
2525
2626Multi-carets:
2727
2828- Ctrl+click - add/delete caret
2929- Ctrl+drag - add caret with selection
3030- Ctrl+Shift+click - add carets column in several lines (from previous caret to clicked line)
3131
3232Select:
3333
3434- Alt+drag - select column of text (Note: it may look weird if word-wrap on, because wrap is not considered here at all. Simple rectangle of coordinates \[x1,y1\]-\[x2,y2\] is always selected, even if this gives bad looking screen)
3535- drag on gutter's line numbers - select by entire lines
3636- double-click and immediately drag - select text by words
3737
3838Clicks:
3939
4040- double-click - select clicked word
4141- triple-click - select entire line (limited by end-of-lines)
4242- middle-button click - start "Browser Scroll" mode: circle mark appears and mouse moving around this mark auto-scrolls text in 4 directions; speed of scrolling depends on distance of cursor from circle mark (any click to turn off)
4343
4444# Multi-carets
4545
4646Multi-carets are several carets at once. All carets work together for many editing commands: caret moving, text typing, deleting, selection with keyboard. See "Mouse shortcuts", how to add/remove carets.
4747
4848Animation:
4949
5050![](/wiki-images/c/cf/Atsynedit-carets.gif)
5151
5252## Multi-selections
5353
5454If you add caret with Ctrl+click, caret has no selection. If you add caret with Ctrl+drag, caret will have selection. You can add selections to carets later, by Shift+arrows, Shift+Home, Shift+End etc.
5555
5656Multi-selections are handled specially on copy/paste. If you copy selections, then move carets, then paste, paste will insert clipboard lines into carets: line-1 at caret-1, line-2 at caret-2 etc (only if carets count equals to lines count in clipboard, otherwise result is different).
5757
5858Animation shows this:
5959
6060![](/wiki-images/6/67/Atsynedit-sel.gif)
6161
6262## Clipboard commands with selections
6363
6464Clipboard-related commands work with carets, both with selections and without them. Some details about this:
6565
6666Command
6767
6868Behaviour, when there're no selections
6969
7070Behaviour, when at last one selection present
7171
7272Copy to clipboard
7373
7474Copies entire lines, containing carets.
7575
7676`                   (Ignores multiple carets on same line.)`
7777
7878Copies only selections text.
7979
8080`                   (Ignores carets without selections.)`
8181
8282Cut to clipboard
8383
8484Similarly to "Copy" w/o selections.
8585
8686Similarly to "Copy" with selections.
8787
8888Paste from clipboard
8989
9090First, selections are cleared (deleted). Then, command pastes text into each caret position. Special case is when clipboard lines count equals to carets count - in this case, first line is inserted at first caret, second line is inserted at 2nd caret, etc.
9191
9292Delete char
9393
9494Deletes one char at each caret position.
9595
9696Deletes only selections text. (Ignores carets without selections.)
9797
9898# Help topics
9999
100100## Compilation errors
101101
102102**IME error on GTK2.**
103103
104104You may get this error:
105105
106-`atsynedit_adapter_gtk2ime.pas(131,5) Error: Identifier not found "IM_Context_Set_Cursor_Pos"`
106+```
107+atsynedit_adapter_gtk2ime.pas(131,5) Error: Identifier not found "IM_Context_Set_Cursor_Pos"
108+```
107109
108110To fix it, edit the file "atsynedit/atsynedit_package.lpk" and remove this block there:
109111
110112``` xml
111113 <Other>
112114 <CustomOptions Value="-dGTK2_IME_CODE"/>
113115 <OtherDefines Count="1">
114116 <Define0 Value="GTK2_IME_CODE"/>
115117 </OtherDefines>
116118 </Other>
117119```
118120
119121Alternative solution when symbol "IM_Context_Set_Cursor_Pos" cannot be found: you need to open IDE dialog "Tools / Configure 'Build Lazarus'", and there enable the define: WITH_GTK2_IM; then recompile the IDE.
120122
121123## What limitations it has?
122124
123125- All lines have the same height
124126- Cannot set different fonts for different parts
125127- No support for right-to-left mode, only limited support for Arabic text
126128
127129## What features it has?
128130
129131- Fast editing of big texts (tested 10M log)
130132- Syntax highliting using 'adapters'
131133- Multi-carets from birth. All code carets aware.
132134- Strings object is holder of text. 2+ editors can have 1 strings obj. (Split editor.)
133135- Unicode (used UnicodeString in Strings obj)
134136- Word-wrap (wrap at control edge, wrap at column)
135137- Inter-line gaps (see #Gaps_object)
136138- Undo/redo
137139- Column blocks
138140- Gutter (line numbers, folding, colored line states)
139141- Bookmarks (with icons)
140142- Supports Win/Unix/Mac line ends
141143- Minimap like Sublime Text
142144- Micromap (owner drawn)
143145- Ruler (at top edge)
144146- Renders wrapped indent (line contains some indent, wrapped parts contain the same indent)
145147- Renders CJK chars with big width
146148- Renders some Unicode chars as "AABB" hex code
147149- Renders unprintable chars (space, tab, line end)
148150- Can highlight/activate URLs
149151- Can set color attributes for ranges (to highlight pair brackets or same words)
150152- Supports proportional fonts
151153
152154## Difference from other components
153155
154156- Adapters to support syntax highlighting. In theory, using adapters it's possible to support syntax files from any app: Sublime Text, Atom, EmEditor etc.
155157- Muti-carets, multi-selections
156158- Inter-line gaps, can insert pictures in it
157159- Minimap, Micromap (rare in others editors)
158160- Smooth per-pixel scrolling (option)
159161
160162## Does it need to be installed?
161163
162164It may be installed or not.
163165
164166- Use not installed: see below "Basic example how to use".
165167- Use installed: in Lazarus IDE, open package file "atsynedit\atsynedit_package". Install it in Package dialog. You 'll have components installed in "Misc" page of component pallette: TATSynEdit, TATEdit (single line edit), etc.
166168
167169## What parts does it have?
168170
169171### Strings object
170172
171173type TATStrings in unit atstrings. Storage of text lines. It includes managing of Undo/Redo too.
172174
173175Methods:
174176
175177- To add/delete lines: LineAdd, LineInsert, LineDelete. They automatically create/update Undo/Redo data. Methods with "Raw" word in name: ignore Undo/Redo data, usually don't use them.
176178- To insert/delete blocks of lines: LineBlockInsert, LineBlockDelete.
177179- Methods starting with "Text" support basic text operations: TextReplace, TextAppend, TextInsert etc. They operate on one caret position and get parameters AShift (shift of caret after text operation, by x/y) and APosAfter (position of caret after the operation).
178180- To load entire content into Strings object: LoadFromFile, LoadFromStream, LoadFromString (multi-line string).
179181
180182To get/set lines, use properties:
181183
182184- Lines\[i\]: text, of type UnicodeString
183185- LinesUTF8\[i\]: text, of type string (faster than Lines\[\])
184186- LinesLen\[i\]: integer: same as Length(Lines\[i\]), but faster
185187- LinesEnds\[i\]: enum: kind of end-of-line chars
186188- LinesHidden\[i\]: bool: true if line is fully hidden (inside folded block)
187189- LinesFoldFrom\[i\]: byte: 0 if line is not folded, \>0 if line is folded from this char-pos
188190- LinesState\[i\]: enum: line state, normal/changed/saved, it's shown by color on gutter
189191- LinesSeparator\[i\]: enum: kind of horizontal separator line to paint near text (rarely needed for apps).
190192
191193Auto-adjustments of other objects when lines are added/deleted:
192194
193195- Strings object updates Strings.Bookmarks, Strings.Bookmarks2 objects.
194196- Strings object updates Gaps (actually Strings.Gaps) object.
195197- If Strings.GutterDecor1 / .GutterDecor2 properties are set, Strings object updates GutterDecor object(s). Properties are not set in ATSynEdit, application must set them.
196198- Objects Attribs / Markers / HotSpots are updated not inside Strings object, but in main ATSynEdit code.
197199
198200### Strings.Bookmarks object
199201
200202type TATBookmarks in unit atsynedit_bookmarks. Holds list of bookmarks of type TATBookmarkItem. Each item has props:
201203
202204- Data.LineNum: line index (in Strings object)
203205- Data.Kind: int kind value
204206- Data.Hint: tooltip string, which is shown on mouse-over for bookmark gutter icon
205207- Data.Tag: int value, for custom application needs
206208- Data.DeleteOnDelLine: bool, enables to auto delete item, when its line is deleted
207209- Data.ShowInBookmarkList: bool, for custom application needs
208210
209211Kind specifies background color and gutter icon for bookmarks of this kind. Kind value 0 must not be used (previously value 0 meaned "no bookmark"), value 1 should be used for "usual" bookmarks, value\>1 should be used for custom application bookmarks. ATSynEdit has 2 events: to paint bookmark icon (from its kind), and to get color of bookmark (from its kind).
210212
211213Bookmarks object is always sorted by line index. Duplicate bookmarks (for the same line index) are auto removed. To change bookmarks, use methods Add, Delete, DeleteForLine, Clear. Also use method Find.
212214
213215### Strings.Bookmarks2 object
214216
215217Same type as Strings.Bookmarks object. This list holds "background bookmarks", which have lower paint priority than usual bookmarks. So if a line has usual bookmark - it is painted, and if not - background bookmark is searched for this line and painted. Bookmarks2 allows to colorize entire lines, but not to interfere with usual bookmarks - it is "passive coloring". Additionally, marks in Bookmarks2 don't have gutter icon, and mouse-over tooltip. Marks in Bookmarks/Bookmarks2 use the same Kind values space.
216218
217219### Carets object
218220
219221type TATCarets in unit atsynedit_carets. Holds list of items of type TATCaretItem. Each caret item has properties:
220222
221223- PosY: index of line in Strings object, 0-based
222224- PosX: offset of caret from line start, 0-based
223225- EndY, EndX: position for selection edge for this caret, or -1/-1 if no selection for this caret
224226- CoordY, CoordX: screen coordinates (usually you don't need these)
225227
226228For forward sel, pair (PosY, PosX) is after pair (EndY, EndX); for backward sel the order is reversed. So if you want to get pos of selection start (e.g. to delete this selection), get minimal pair.
227229
228230Carets object is sorted by text position, method Sort does this. Duplicate carets (they appear during work with multi-carets) are auto removed. If you try to add overlapping caret selections, they will be auto merged to one caret. To add/delete carets, use methods Add, Clear. Also ATSynEdit has methods DoCaretNNNNN, eg DoCaretSingle makes single caret.
229231
230232### CaretsSel object
231233
232234type TATCaretSelections in unit atsynedit_carets. It is helping object, internally it holds array of carets coordinates, sorted by text position, but only for carets with selection (carets w/o selection are not included). It is read-only, ie it's needed only to find some info about selections, not to store it. Finding some info about selections is much faster with CaretsSel object, though you can use Carets object too (slower). It uses binary search.
233235
234236Note: object is updated (from contents of Carets) in Paint method, not immediately after you add/change something in Carets.
235237
236238### Keymap object
237239
238240type TATKeymap in unit atsynedit_keymap.
239241
240242Holds list of keyboard actions of type TATKeymapItem. It's inited at start. And to init items at start, two "filling" procedures exist in code: one for TATSynEdit, and simpler one for TATEdit (single line version, less commands). And you can add more keymap items or change hotkeys for any keymap item.
241243
242244Each keymap item has 2 (yet) hotkeys, second is needed for e.g.: Copy-to-clipboard (Ctrl+C and Ctrl+Ins), Paste-from-clipbd (Ctrl+V and Shift+Ins) etc.
243245
244246When adding keymap item, you can set simple hotkeys (e.g. "Alt+Shift+F") or key combos (several simple hotkeys which must be pressed in order). Example adds commands with simple hotkey and combo:
245247
246248``` pascal
247249 var
248250 M: TATKeymap;
249251 const
250252 cmd_My1 = 3000;
251253 cmd_My2 = 3001;
252254 begin
253255 M.Add(cmd_My1, 'cmd with simple hotkey', ['Ctrl+Shift+F'], []);
254256 M.Add(cmd_My2, 'cmd with 3 keys combo', ['Ctrl+B', 'Ctrl+B', 'Ctrl+M'], []);
255257```
256258
257259After you added new keymap items, add reaction for them: use OnCommand event as usual.
258260
259261### WrapInfo object
260262
261263type TATWrapInfo in unit atsynedit_wrapinfo. Holds list of wrap items, each is info about wrapped part of line or about entire line:
262264
263265- its original line index in Strings object (0-base)
264266- its char offset in original line (0-base)
265267- its length
266268- its indent size (if feature "wrapped indent" is on)
267269- its final-state: is it first/middle part of wrapped line, or final part
268270
269271One wrap item renders on control as one short line. It is part of wrapped line or entire line. Also used for wrap-mode off, this is simple case - one wrap item per one line. Wrap items exist only for lines not hidden by folding feature (with Strings.LinesHidden\[i\]=true).
270272
271273WrapInfo has weird property VirtualMode. This prop is set if a) no fold ranges created (ie no lexer is active, or lexer didn't create fold ranges), b) word wrapping is off. VirtualMode means that WrapInfo don't store any data in internal TList, it is empty and fast, it only reads props of Strings and returns them. Indeed, when no fold ranges, and word wrapping off, all items of WrapInfo must be simple "mirror" of Strings items props (and count is the same).
272274
273275VirtualMode makes loading of huge logs (100-500Mb) ~1.5 times faster.
274276
275277### Undo object
276278
277279Holds list of actions for Undo/Redo. You must not touch it. Filled auto by changing-adding-deleting of lines in Strings object (by any API). Also holds end-of-lines markers (changed ends-of-lines can undo too).
278280
279281Items in Undo object have 'group marker'. This means that some editor commands set this marker, and items after marked item will undo as a group (if option "Group undo" on). You can set group marker (for next editor action) by method SetGroupMark of Strings object.
280282
281283### Gutter object
282284
283285type TATGutter in unit atsynedit_gutter. Holds list of gutter items. Each gutter item has properties:
284286
285287- Visible: gutter band is shown on gutter
286288- Size: width of gutter band
287289- Left/Right: calculated auto from Visible and Size, coordinates of band on control
288290
289291To know which band of gutter does what, use properties of ATSynEdit: GutterBandNum (index of band for line numbers), GutterBandFold (index of band for folding) etc. Example shows/hides gutter column:
290292
291293``` pascal
292294 ed.Gutter[ed.GutterBandNum].Visible:= checkGutterNum.Checked;
293295 ed.Gutter.Update;
294296 ed.Update;
295297```
296298
297299### GutterDecor object
298300
299301type TATGutterDecor in unit atsynedit_gutter_decor. Holds list of items, which are painted over gutter, for decoration purpose. Items can hold short text strings (e.g. normal/square/curly brackets to show pair brackets in text), or icon from TImageList. If item has not empty Text, then text is shown, otherwise icon is shown. Each item has props:
300302
301303- Data.LineNum: line index (in Strings object)
302304- Data.Tag: int value, for custom app needs
303305- Data.ImageIndex: icon index in TATSynEdit.ImagesGutterDecor image list
304306- Data.Text: short string
305307- Data.TextBold: bool, text font is bold
306308- Data.TextItalic: bool, text font is italic
307309- Data.TextColor: color of text
308310- Data.DeleteOnDelLine: bool, enables to auto delete item, when its line is deleted
309311
310312Items in this object are auto adjusted when text is edited. But note: for this to work, you must assign GutterDecor object to Strings object prop GutterDecor1 or GutterDecor2.
311313
312314Duplicate items (for the same line index) are auto removed. TATSynEdit.GutterBandDecor sets index of gutter band for decorations. If -1, then gutter band for bookmarks is used.
313315
314316### Fold object
315317
316318type TATSynRanges in unit atsynedit_ranges. Holds list of ranges which can be folded and show plus/minus on gutter. Each range is of type TATSynRange, it has properties:
317319
318320- Y: starting line of range (0-based)
319321- Y2: ending line of range (if same as Y, plus/minus not shown on gutter)
320322- X: char-offset in starting line (must be \>0, 1 means fold from 1st char)
321323- Folded: boolean, state: folded/unfolded
322324- Staple: boolean, true if range has staple shown (vertical line on text area)
323325- Hint: string, shown in rectangle when range is folded
324326
325327Example adds few ranges to text:
326328
327329``` pascal
328330 Edit1.Fold.Clear;
329331 Edit1.Fold.Add(1, 4, 15, false, ''); //line 4 to 15, range1
330332 Edit1.Fold.Add(1, 5, 9, false, ''); //line 5 to 9, nested into range1
331333 Edit1.Fold.Add(1, 7, 8, false, ''); //line 7 to 8, nested into range2
332334```
333335
334336- To fold/unfold a range, don't change Folded field, use methods of ATSynEdit: DoRangeFold, DoRangeUnfold.
335337- To fold/unfold all, use commands via DoCommand method: cCommand_FoldAll, cCommand_UnfoldAll.
336338- In Fold object, items are not sorted, but usually syntax-adapters add these ranges as sorted (by Y).
337339- Fold object has methods, which find ranges, e.g. all ranges which contain any line from N1 to N2, etc.
338340
339341### Markers object
340342
341343type TATMarkers in unit atsynedit_markers. Holds list of marker items. Each marker item has properties:
342344
343345- PosX, PosY: position of marker (like caret position).
344346- LineLen: if not 0, render horizontal line to the left (LineLen\<0) or right (LineLen\>0).
345347- CoordX, CoordY: screen coordinates.
346348- CoordX2, CoordY2: screen coordinates of LineLen end.
347349- SelX, SelY: used in CudaText: when "collect marker" gets this marker, caret will be with selection.
348350 - if SelY=0 - SelX is length of selection (single line selection)
349351 - if SelY\>0 - SelY is Y-delta of selection end, SelX is absolute X of selection-end
350352- Tag (Int64): some integer value, useful for apps: e.g. CudaText holds here tabstop-index (several markers with the same index \>0 give multi-carets, when user jumps to one of markers).
351353- Value (Int64): some integer value, attached to marker.
352354- Ptr (TObject): some application-specific object. Object is freed automatically when marker item is freed.
353355- MicromapOnly (enum): where to render the marker: on text area, on micromap, on both text/micromap.
354356
355357Markers are painted as red triangles below their positions (PosX, PosY). They are needed e.g. for making snippets, where user needs to jump over snippet's insert points and wants to see these points. Also it's good for IDE to have commands like "drop marker here", "remove last marker", "swap caret and last marker" etc (like CodeRush).
356358
357359Example code from CudaText:
358360
359361``` pascal
360362procedure EditorMarkerGotoLast(Ed: TATSynEdit; AndDelete: boolean);
361363var
362364 Caret: TATCaretItem;
363365 Mark: TATMarkerItem;
364366begin
365367 if Ed.Carets.Count<>1 then exit;
366368 if Ed.Markers.Count=0 then exit;
367369 Caret:= Ed.Carets[0];
368370 Mark:= Ed.Markers[Ed.Markers.Count-1];
369371 Caret.PosX:= Mark.PosX;
370372 Caret.PosY:= Mark.PosY;
371373 if AndDelete then
372374 Ed.Markers.Delete(Ed.Markers.Count-1);
373375 Ed.DoGotoCaret(cEdgeTop);
374376 Ed.Update;
375377end;
376378```
377379
378380### Attribs object
379381
380382type TATMarkers (same as for Markers). Holds list of additional color/font attribute items, these items are added to syntax hiliting and selection hiliting. Each item has properties:
381383
382384- PosX, PosY: see Markers object.
383385- SelX, SelY: see Markers object.
384386- Ptr (TObject): object of type TATLinePartClass, which has Data field. This Data is record, it contains all color/font/borders properties of this attr.
385387
386388Attribs object is used in CudaText: app adds attr items to hilite brackets, to hilite misspelled words, etc.
387389
388390If you add attrib item, create new object of type TATLinePartClass, fill its Data, and pass object to TATMarkers.Add. This object is freed automatically if attrib item deleted or all attribs cleared.
389391
390392### Colors object
391393
392394Contains color properties of type TColor. For ex, Colors.TextFont is text font color, Colors.TextBG is text background color.
393395
394396### Gaps object
395397
396398type TATGaps in unit atsynedit_gaps. Holds list of items TATGapItem. Each item has properties:
397399
398400- LineIndex: index in Strings object; and special value -1 is allowed: gap before the first line
399401- Size: height in pixels
400402- Tag: int value, to difference gaps from several plugins
401403- Bitmap: TBitmap which is painted on gap, when it's visible
402404- DeleteOnDelLine: bool, enables to auto delete item, when its line is deleted
403405
404406Gap item paints as rectangle (it is owner-drawn), just between lines N and N+1, not overlapping text. When user adds/deletes lines, gaps auto-shift with their lines; gap is deleted if its line is deleted.
405407
406408Use cases:
407409
408410- App wants to show picture preview, when picture is linked in HTML. It creates small preview picture e.g. 100x50, and adds gap: gap size=52, picture height and 2 pixels of border.
409411- App runs linter on JS code, for JS errors it places bookmarks, and adds gaps with size=15 for error lines: in gaps it writes errors, maybe icons.
410412
411413To add/remove gaps:
412414
413415``` pascal
414416 //to add
415417 ed.Gaps.Add(NLine, NGapHeight, FSomeBitmap, NGapTag);
416418 ed.Update;
417419 //to delete this gap
418420 ed.Gaps.DeleteForLineRange(NLine, NLine);
419421 ed.Update;
420422```
421423
422424Event OnDrawGap is used to paint gaps, it gets canvas, and rectangle on canvas. Note: if you add gap to the last line, you must turn on option OptLastLineOnTop, better don't turn it off later (to not scroll, when gap added/removed).
423425
424426### DimRanges object
425427
426428type TATDimRanges in unit atsynedit_dimranges. Holds list of ranges which shade/dim/fade text font color, ie blend font color with background color. Each range is of type TATDimRange, it has properties:
427429
428430- LineFrom: range starts from this line (0-based)
429431- LineTo: range ends on this line (can use MaxInt)
430432- DimValue: dim value from 0 to 255. 0 means "no effect", 255 means "transparent text".
431433
432434To dim all text except current paragraph, you must add 2 ranges: before/after paragraph, then correct line indexes in them.
433435
434436There is no checking for line indexes, ranges can have any indexes, but overlapping indexes not good (first found range will give dim value).
435437
436438Example adds 2 ranges and changes them later:
437439
438440``` pascal
439441 R1:= Ed.DimRanges.Add(0, 6, 100{dim value});
440442 R2:= Ed.DimRanges.Add(20, MaxInt, 100{dim value});
441443 Ed.Update;
442444 //change ranges
443445 R1.LineTo:= 10;
444446 R2.LineFrom:= 30;
445447 Ed.Update;
446448```
447449
448450### Hotspots object
449451
450452type TATHotspots in unit atsynedit_hotspots. Holds list of ranges, which need special tooltip on mouse-over. Each range is of type TATHotspotItem, it has props:
451453
452454- PosX, PosY: start of range (text position)
453455- EndX, EndY: end of range
454456- Tag: some custom int value
455457- TagString: some custom string value
456458
457459You can add hotspots via Add method, and find them later by Tag, by TagString, by text position - methods FindByPos, FindByTag, FindByTagString. To support mouse-over for these ranges, two events exist: OnHotspotEnter, OnHotspotExit.
458460
459461Example of usage: in HTML file, app can find all HTML color tokens \#rrggbb, add hotspots for them, and store color value to Tag. Then on mouse-over app can show colored tooltip.
460462
461463### Micromap object
462464
463465type TATMicromap in unit atsynedit_micromap. Holds list of micromap's columns (by default only one column is added, and CudaText adds 2nd column to paint marks from plugins). The micromap is shown by ATSynEdit property OptMicromapVisible and must be painted by the app via OnDrawMicromap event. Micromap object has Columns property, "array of TATMicromapColumn".
464466
465467Type TATMicromapColumn is record with the fields:
466468
467469- NTag: Int64 tag value, so app can find this column by tag - app can change this
468470- NWidthPercents: Width of column in percents of average char width - app can change this
469471- NWidthPixels: Width of column in pixels - auto calculated, app must not change this
470472- NLeft, NRight: Control-related coordinates of column left and right edge - auto calculated, app must not change this
471473
472474Micromap object holds Columns prop, and several methods to add/delete columns: ColumnAdd, ColumnDelete, and method ColumnFromTag to find columns by int tag. Application can paint anything on micromap, but it's recommented to paint small marks per editor lines. To get coordinates of such marks, use ATSynEdit method RectMicromapMark, it does calculations to get coords for all editor lines, to fill the entire micromap.
473475
474476## What are the basic methods/properties?
475477
476478Objects
477479
478480- property Strings
479481- property Strings.Bookmarks
480482- property Strings.Bookmarks2
481483- property Carets
482484- property Gutter
483485- property GutterDecor
484486- property Keymap
485487- property Fold
486488- property Markers
487489- property Attribs
488490- property Colors
489491- property WrapInfo
490492- property Gaps
491493- property DimRanges
492494- property Hotspots
493495- property Micromap
494496
495497Files
496498
497499- procedure LoadFromFile(const AFilename: string): load text from file (filename uses utf-8)
498500- procedure SaveToFile(const AFilename: string): save text to file
499501
500502States
501503
502504- property Modified: modified state (cleared on file loading)
503505- property ModeOverwrite: mode insert/overwrite state (Ins key toggles it)
504506- property ModeReadOnly: mode read-only state
505507
506508More
507509
508510- procedure Update(AUpdateWrapInfo: boolean = false; AUpdateCaretsCoords: boolean = true): to repaint+invalidate; 1st param must be True to recalculate WrapInfo object (usually it's auto updated, but if text change detection don't work, e.g. Strings object changed directly, pass True here)
509511- procedure DoCommand(ACmd: integer; const AText: UnicodeString = ""): command runner, pass command code to run it (see file atsynedit_commands)
510512- property Text: unicodestring which gives entire editor text with LF separator
511513
512514Caret
513515
514516- procedure DoCaretSingle(AX, AY: integer): make single caret
515517- function CaretPosToClientPos(P: TPoint): TPoint: convert caret coords to screen coords
516518- function ClientPosToCaretPos(P: TPoint; out AEndOfLinePos: boolean): TPoint: convert screen coords to caret coords
517519- function IsLineWithCaret(ALine: integer): boolean: is line index contains any caret
518520
519521Selection
520522
521523(P.Y is line index, P.X is char offset in line, 0-based)
522524
523525- property SelRect: for column selection, rectangle of column block
524526- function IsSelRectEmpty: is column selection exists
525527- procedure DoSelect_All: select all text (makes single caret)
526528- procedure DoSelect_Line(P: TPoint): select single line
527529- procedure DoSelect_Word(P: TPoint): select single word
528530- procedure DoSelect_LineRange(ALineFrom: integer; P: TPoint): select several lines from line index to given point
529531
530532View
531533
532534- property LineTop: index of line visible at the top of control (almost vertical scroll, though exact scroll pos is different, it considers WrapInfo object)
533535- property LineBottom: index of line visible at the bottom of control (because of folding you cannot simply calculate it)
534536- property ColumnLeft: index of left visible column (ie, horizontal scroll)
535537- procedure DoRangeFold(ARange: TATSynRange): fold range, which exists in the Fold object
536538- procedure DoRangeUnfold(ARange: TATSynRange): unfold range
537539- procedure DoScrollByDelta(Dx, Dy: integer): scroll editor area by Dx chars right and Dy lines down
538540- procedure DoGotoPos(APnt: TPoint; AIndentHorz, AIndentVert: integer): scroll editor to given caret pos
539541
540542Options
541543
542544I cannot post here options. See ATSynEdit properties beginning with "Opt", these are props which can change in design time in IDE. You can place on form ATSynEdit and see in IDE its "Opt" properties and see their values.
543545
544546Encodings
545547
546548- Strings.EncodingDetect: boolean
547549- Strings.Encoding: enum (cEncAnsi, cEncUTF8, cEncWideLE, cEncWideBE)
548550- Strings.EncodingCodepage: string (used for Encoding=cEncAnsi)
549551- Strings.SaveSignUtf8: boolean
550552
551553## Basic example how to use?
552554
553555- Add "uses ATSynEdit".
554556- Add variable "ed".
555557- Add OnCreate event to new form.
556558- How to load file "unit1.pas":
557559
558560``` pascal
559561 procedure TForm1.FormCreate(Sender: TObject);
560562 begin
561563 ed:= TATSynEdit.Create(Self);
562564 ed.Parent:= Self;
563565 ed.Align:= alClient;
564566 ed.Font.Name:= 'Courier New';
565567 ed.OptUnprintedVisible:= false;
566568 ed.OptRulerVisible:= false;
567569 ed.LoadFromFile(ExtractFilePath(Application.ExeName)+'unit1.pas');
568570 end;
569571```
570572
571573- How to save file: call "ed.SaveToFile()".
572574
573575## How does it manage the coordinates?
574576
575577Carets object contains list of caret items. Each caret item, e.g. Carets\[0\], has properties:
576578
577579- PosY: line index in Strings object
578580- PosX: char offset from line start
579581- EndY, EndX: selection end for caret, both -1 if no selection
580582- CoordX, CoordY: control-relative coordinates of caret
581583
582584Strings object holds UnicodeString's, where each WideChar gives offset=1, and even Tab char gives offset=1. Component auto-calculates properties CoordX/CoordY for all carets, screen coordinates. Don't touch CoordX/CoordY, change only PosX/PosY and EndX/EndY.
583585
584586### Text position to/from screen coordinates
585587
586588Methods allow to convert text position to/from control-relative coordinates (in pixels). Layout of gutter, ruler and other UI elements are already considered by methods.
587589
588590``` pascal
589591 function CaretPosToClientPos(P: TPoint): TPoint;
590592 function ClientPosToCaretPos(P: TPoint;
591593 out ADetails: TATPosDetails;
592594 AGapCoordAction: TATGapCoordAction=cGapCoordToLineEnd): TPoint;
593595```
594596
595597- Param ADetails: returned True if text pos is after real end-of-line, False if text pos is inside line.
596598- Param AGapCoordAction: you must specify here what to do if coordinates are over inter-line gap (see Gaps object).
597599
598600Functions give Result.Y\<0 if cannot calculate pos. For example, if line index is too big or line with this index is fully folded.
599601
600602Property OptCaretVirtual exists. If it's True, caret is allowed after end-of-line. Methods consider it.
601603
602604### Text posistion to/from column index
603605
604606To convert text coordinate X to/from column index (considering Tab chars), ATSynEdit has TabHelper object and methods of Strings object. Here is example, code which converts X of first caret to its column index:
605607
606608``` pascal
607609 var
608610 ed: TATSynEdit;
609611 caret: TATCaretItem;
610612 //...
611613
612614 caret:= ed.Carets[0];
613615 if ed.Strings.IsIndexValid(caret.PosY) then
614616 begin
615617 //optimized for huge lines
616618 ColumnIndex:= ed.Strings.CharPosToColumnPos(caret.PosY, caret.PosX, ed.TabHelper)+1;
617619 end;
618620```
619621
620622## How to manage the caret, the selection?
621623
622624See topic "Carets object". To change position of carets, get Carets property of editor, get each item Carets\[N\], and change caret items' properties PosX/PosY and/or EndX/EndY, then call editor's method Update. To change selection for any caret (each caret has own selection): get caret item, and change its propeties EndX/EndY (set both to -1 to remove selection), then call editor's method Update.
623625
624626Better don't do overlapping selections (when e.g. selection of caret-2 overlaps selection of caret-3), but even here you can call Carets.Sort, which should sort carets by PosX/PosY and fix them.
625627
626628You can delete and add caret items.
627629
628630``` pascal
629631 var
630632 Caret: TATCaretItem;
631633 i: integer;
632634 begin
633635 for i:= 0 to edit.Carets.Count-1 do
634636 begin
635637 Caret:= edit.Carets[i];
636638 {
637639 change here Caret.PosX and Caret.PosY
638640 }
639641 end;
640642 edit.Update;
641643 end;
642644```
643645
644646## How to modify text?
645647
646648See topic above about "Strings object". To change text, get Strings property of editor. "Strings.Count" is number of lines in object. Then access methods of Strings: LineAdd, LineInsert, LineDelete. To get/set lines by index, use properties of Strings: Strings.Lines\[i\], etc, listed above.
647649
648650To do advanced changes, use TATStrings.Text* methods:
649651
650652``` pascal
651653 procedure TextInsert(AX, AY: integer; const AText: atString; AOverwrite: boolean;
652654 out AShift, APosAfter: TPoint);
653655 procedure TextAppend(const AText: atString; out AShift, APosAfter: TPoint);
654656 procedure TextInsertColumnBlock(AX, AY: integer; ABlock: TATStrings;
655657 AOverwrite: boolean);
656658 procedure TextDeleteLeft(AX, AY: integer; ALen: integer; out AShift, APosAfter: TPoint);
657659 procedure TextDeleteRight(AX, AY: integer; ALen: integer; out AShift,
658660 APosAfter: TPoint; ACanDelEol: boolean=true);
659661 function TextDeleteRange(AFromX, AFromY, AToX, AToY: integer; out AShift, APosAfter: TPoint): boolean;
660662 procedure TextInsertEol(AX, AY: integer; AKeepCaret: boolean;
661663 const AStrIndent: atString; out AShift, APosAfter: TPoint);
662664 procedure TextDeleteLine(AX, AY: integer; out AShift, APosAfter: TPoint);
663665 procedure TextReplaceInOneLine(AY, AX1, AX2: integer; const AText: atString);
664666 procedure TextReplaceRange(AFromX, AFromY, AToX, AToY: integer;
665667 const AText: atString; out AShift, APosAfter: TPoint);
666668 function TextReplaceLines_UTF8(ALineFrom, ALineTo: integer; ANewLines: TStringList): boolean;
667669 function TextSubstring(AX1, AY1, AX2, AY2: integer; const AEolString: string = #10): atString;
668670```
669671
670672Strings.Lines\[i\] do not contain end-of-line chars. Usually not needed to change end-of-line chars. You can change them using Strings.LinesEnds\[i\].
671673
672674- After changes in Strings object, always call editor.Update(true). Update(false) only repaints editor, Update(true) invalidates WrapInfo object first (must be called after changes to Strings, or after window resize).
673675- You can read Strings from one editor1 and set it to Strings of editor2. This will make editor2 having same strings object (needed for split-tab).
674676
675677## How to highlight syntax?
676678
677679There're 2 ways:
678680
679681- OnCalcHilite event (better, if your code is small, e.g. colorize few tokens)
680682- Adapter (better, if your code is big, e.g. support for EControl lexers)
681683
682684You can set handler of OnCalcHilite event. Adapter is different way to do the same. Instead of using event, you write code in the new class which is child of TATAdapterHilite. Then you link adapter to editor:
683685
684686``` pascal
685687 Adapter.AddEditor(editor1);
686688 Adapter.AddEditor(editor2); //if 2 editors share the same text buffer
687689```
688690
689691To unlink adapter from all editors, call:
690692
691693``` pascal
692694 Adapter.AddEditor(nil);
693695```
694696
695697If adapter assigned, editor will call adapter's methods (first called adapter, next OnCalcHilite).
696698
697699See file "atsynedit_adapters.pas". It has base class for such adapters. Main method in adapter, which is called by ATSynEdit is:
698700
699701``` pascal
700702 procedure OnEditorCalcHilite(Sender: TObject;
701703 var AParts: TATLineParts;
702704 ALineIndex, ACharIndex, ALineLen: integer;
703705 var AColorAfterEol: TColor);
704706```
705707
706708Parameters here:
707709
708710- Sender: editor object.
709711- AParts: array of "parts": each part has Offset, Len, colors, font style. Adapter must create parts for entire string (1st part takes 1st chars of string, last part takes last chars of string). See code about TATLineParts.
710712- ALineIndex: index of passed line (0-based).
711713- ACharIndex: index of 1st char in line (it's not 0 if wrapped part of line is shown, 0-based).
712714- ALineLen: length of substring to hilite.
713715- AColorAfterEol: return here color for background of line after end-of-line. Return clNone if no color needed.
714716
715717Real string which you must hilite: see example project how to get it.
716718
717719## How to set same text-source to several editors?
718720
719721Several editors can have same text source, text source is ATStrings object which holds
720722
721723- same text for all editors
722724- separate folding states for each editor
723725
724726Each editor holds its own WrapInfo object so wrapped states are separate. Each editor holds its own Carets object, so carets/selections are separate.
725727
726728Tech details: items in ATStrings object have fields:
727729
728730``` pascal
729731 ItemHidden: packed array[0..cMaxStringsClients-1] of ByteBool;
730732 // this line is fully hidden
731733 ItemFoldFrom: packed array[0..cMaxStringsClients-1] of byte;
732734 // 0: line not folded
733735 // >0: line folded from this char-pos
734736```
735737
736738(constant can be changed in source). These fields allow to hold separate fold-info for each "editor client" of ATStrings. Each client must have it's own EditorIndex (0 to cMaxStringsClients-1). Example, make 4 editors ed0..ed3.
737739
738740- change cMaxStringsClients to 4
739741- set ed0.EditorIndex:=0
740742- set ed1.EditorIndex:=1
741743- set ed2.EditorIndex:=2
742744- set ed3.EditorIndex:=3
743745- set ed1.Strings:=ed0.Strings
744746- set ed2.Strings:=ed0.Strings
745747- set ed3.Strings:=ed0.Strings
746748
747749If user changes text in ed3, ed3 will update but others will not: you need to force it:
748750
749751- ed0.Update(true)
750752- ed1.Update(true)
751753- ed2.Update(true)
752754
753755## How to add/change commands?
754756
755757To change action of internal commands (file atsynedit_commands.pas) you need to use event OnCommand which can do any action for any command (and return AHandled=True to disable default code). Better use OnCommand handler for all commands, even new ones. So you can call DoCommand() and have one handler to do anything.
756758
757759Example func which adds new commands to Keymap object:
758760
759761``` pascal
760762const
761763 cmd_FileNew = 2500;
762764 ...
763765
764766procedure InitKeymapApp(M: TATKeymap);
765767begin
766768 M.Add(cmd_FileNew, 'file: new file', ['Ctrl+N'], []);
767769 M.Add(cmd_FileOpen, 'file: open file', ['Ctrl+O'], []);
768770 M.Add(cmd_FileSave, 'file: save file', ['Ctrl+S'], []);
769771 ...
770772end;
771773```
772774
773775Example handler for new commands: some close editor tabs (special case: cannot close tabs just inside OnCommand) and some commands copy something to clipboard:
774776
775777``` pascal
776778procedure TfmMain.EditorOnCommand(Sender: TObject; Cmd: integer; var Handled: boolean);
777779begin
778780 Handled:= true; //by default command marked as handled
779781 case Cmd of
780782 cmd_FileNew,
781783 cmd_FileOpen,
782784 cmd_FileClose,
783785 cmd_FileCloseAll,
784786 cmd_FileReopen:
785787 begin
786788 //these commands close tabs so cannot handle here.
787789 //we start timer which will handle them.
788790 TimerCmd.Tag:= Cmd;
789791 TimerCmd.Enabled:= true;
790792 end;
791793
792794 cmd_CopyLine: DoCopyLine;
793795 cmd_CopyFilenameFull: DoCopyFilenameFull;
794796 cmd_CopyFilenameDir: DoCopyFilenameDir;
795797 cmd_CopyFilenameName: DoCopyFilenameName;
796798
797799 else
798800 Handled:= false; //unknown command: don't mark handled
799801 end;
800802end;
801803```
802804
803805## How to emulate Edit, Combobox?
804806
805807Special child of ATSynEdit exists: ATEdit. It's single line control in which all multiline text editing is disabled. And paste can give only single line. And scrollbars are disabled. And many commands (like "Move lines up/down") are removed from Keymap object.
806808
807809Special child of ATEdit exists: ATComboEdit. It has micromap area which paints dropdown arrow to look like combobox. Click on this arrow gives popup-menu with entered variants.
808810
809811![](/wiki-images/3/3b/Atsynedit_combo.png)
810812
811813Variants must be added to history by user code, using OnCommand handler: react to command "cCommand_KeyEnter". Example of handler:
812814
813815``` pascal
814816procedure TfmCombo.ComboCommand(Sender: TObject; ACmd: integer;
815817 var AHandled: boolean);
816818var
817819 s: string;
818820 n: integer;
819821begin
820822 if ACmd=cCommand_KeyEnter then
821823 begin
822824 with ed do
823825 begin
824826 s:= UTF8Encode(Trim(Text));
825827
826828 Text:= '';
827829 DoCaretSingle(0, 0);
828830
829831 n:= Items.IndexOf(s);
830832 if n>=0 then Items.Delete(n);
831833 Items.Insert(0, s);
832834 end;
833835 AHandled:= true;
834836 end;
835837end;
836838```
837839
838840## What props are useful for statusbar?
839841
840842- number of carets: Carets.Count
841843- positions of carets: Carets.Items\[i\].PosX (column), PosY (line)
842844- text encoding: Strings.Encoding
843845 - cEncAnsi: then codepage is given by Strings.EncodingCodepage
844846 - cEncUTF8: then presence of utf8 bom is given by Strings.SaveSignUtf8
845847 - cEncWideLE, cEncWideBE: then presense of Unicode bom is given by Strings.SaveSignWide
846848- text line endings (win/unix/mac): Strings.Endings
847849- tab-char width: OptTabSize
848850- tab-char entered by spaces: OptTabSpaces
849851- index of top visible line: LineTop
850852- index of left visible column: ColumnLeft
851853- modified state: Modified
852854- read-only mode: ModeReadOnly
853855- insert/overwrite mode: ModeOverwrite
854856- word-wrap mode: OptWrapMode
855857- unprinted chars shown: OptUnprintedVisible
856858- selection: get Carets.Items\[i\].PosX/PosY/EndX/EndY, for state of column selection get IsSelRectEmpty, SelRect
857859
858860## How to customize popup menu?
859861
860862These properties allow to change all menus in control (you cannot modify default menu):
861863
862864- PopupText: for text area
863865- PopupRuler
864866- PopupMinimap
865867- PopupMicromap
866868- PopupGutterBm: for bookmarks column
867869- PopupGutterFold: for folding column
868870- PopupGutterNum: for line numbers column
869871
870872Prop OptMouse* exists, which allows to show menus on mouse-down or on mouse-up.
871873
872874## How to know indexes of changed lines in OnChange?
873875
874876You have event Strings.OnLog. It gives parameters:
875877
876878- ALine: index of line at which change occurs
877879- ALen: len of text which is added (ALen\>0) or deleted (ALen\<0) at line start
878880
879881Get the log, save it, and then parse it during OnChange.
880882
881883## How to export text to HTML?
882884
883885Unit atsynedit_export_html has the function which does HTML report. It has several parameters to customize output. See example of usual parameters in the demo_editor.
884886
885887ATSynEdit has API which allows to make report to any format. It's function DoCalcLineHiliteEx. It returns syntax highlight info for any line. Info is stored in TATLineParts struct, see HTML exporter code how to use it.
886888
887889## Short description of events?
888890
889891- OnBeforeCalcHilite: Called before OnCalcHilite for first visible line.
890892- OnCalcBookmarkColor: Called to determine color of bookmark (background color of line with bookmark).
891893- OnCalcHilite: Called to calculate syntax highlight for a line (or wrapped part of line). You need to fill TATLineParts struct for this line.
892894- OnCalcStaple: Called to determine color of block staple (vertical line which is painted near fold-ranges).
893895- OnChange: Called after any command which changes text.
894896- OnChangeCaretPos: Called after any command which changes caret(s) position(s).
895897- OnChangeState: Called after any command which changes editor state, such as read-only, insert/overwrite, word-wrap etc.
896898- OnClickDouble: Called on double-click on text area.
897899- OnClickGutter: Called on click on gutter area.
898900- OnClickMicromap: Called on click on micromap area.
899901- OnClickMiddle: Called on middle button click on text area.
900902- OnClickTriple: Called on triple-click on text area.
901903- OnClickMoveCaret: Called just before changing caret pos via mouse click (you get prev caret pos, new caret pos).
902904- OnClickEndSelect: Called just after mouse-up, if single selection made (you get selection start pos, end pos).
903905- OnCommand: Called before running any command. You can disable any command processing, or perform custom processing before/instead of command.
904906- OnCommandAfter: Called after running command.
905907- OnDrawBookmarkIcon: Called on painting gutter mark for line with bookmark.
906908- OnDrawEditor: Called after painting entire text area.
907909- OnDrawLine: Called after painting line (or wrapped part of line) on canvas. You can paint some "image" over this line.
908910- OnDrawMicromap: Called on painting micromap area.
909911- OnDrawRuler: Called after painting ruler area.
910912- OnScroll: Called after any command which scrolls text.
911913- OnPaste: Called just before pasting text. App can disable/override default pasting.
912914- OnHotspotEnter: Called when mouse moving enters one of the ranges in Hotspots object.
913915- OnHotspotExit: Called when mouse moving exits hotspot.
914916
915917## What is logic of grouped-undo?
916918
917919There're kinds of group-marks in undo-items: hard-marks, soft-marks.
918920
919921- Hard-marks are placed on undo-items if you call Strings.BeginUndoGroup, editing, Strings.EndUndoGroup. All items marked with hard-marks are undone as group, even of OptUndoGrouped=false.
920922- Soft-marks used only if OptUndoGrouped=true. Soft-marks are placed on one next undo-item, when user does mouse click (or some similar action); or in code by call Strings.SetGroupMark. All items beginning with last soft-marked item are undone as group.
921923
922924Example 1. OptUndoGrouped=true, such undo-items exist:
923925
924926- item1
925927- item2
926928- item3, soft-mark
927929- item4
928930- item5, hard-mark
929931- item6, hard-mark
930932- item7
931933- item8, soft-mark
932934- item9
933935- item10
934936
935937Undo:
936938
937939- undone: item10..8; until soft-mark.
938940- undone: item7..3; until soft-mark.
939941- undone: item2..1.
940942
941943Example 2. OptUndoGrouped=false, undo-items:
942944
943945- item1
944946- item2
945947- item3, hard-mark
946948- item4, hard-mark
947949- item5, hard-mark
948950- item6
949951- item7
950952
951953Undo:
952954
953955- Undone: item7
954956- Undone: item6
955957- Undone: item5..3
956958- Undone: item2
957959- Undone: item1
958960
959961Soft-marks also used together with hard-marks. Soft-mark is placed with first hard-mark after call Strings.BeginUndoGroup. This allows to undo N groups of edits, if many items hard-marked (w/out gaps).
960962
961963Example 3. Undo-items:
962964
963965- item1, hard-mark
964966- item2, hard-mark, soft-mark
965967- item3, hard-mark
966968- item4, hard-mark, soft-mark
967969- item5, hard-mark
968970- item6, hard-mark
969971
970972Undo:
971973
972974- undone: item6..4
973975- undone: item3..2
974976- undone: item1
975977
976978## How to record/playback macros?
977979
978980Macro support must be done on app level, component does support by event OnCommand. Handle OnCommand and you get all command codes which run. Real app adds more commands in Keymap object and it must decide which of them it wants to record (e.g. don't record commands to show dialogs, and record commands which comment/uncomment lines).
979981
980982To playback macro, call DoCommand for all codes in macro.
981983
982984Hint. CudaText also adds 3 commands to help with macros:
983985
984986- "mouse click" (command recorded in OnClick event of editor)
985987- "goto pos" (command recorded by GoTo dialog)
986988- "finder action" (command recorded when doing find/replace actions)
987989
988990## How to configure modifier-keys with click?
989991
990992You can configure some of mouse clicks with modifier keys: simple click, Ctrl+click, Shift+click, Ctrl+Shift+click, middle click, etc. Property MouseMap configures it, it's array, type TATMouseActions. Default code configures it in InitMouseActions like this:
991993
992994``` pascal
993995procedure InitMouseActions(var M: TATMouseActions);
994996//...
995997begin
996998 SetLength(M, 0);
997999 Add(cMouseActionClickSimple, [ssLeft]);
9981000 Add(cMouseActionClickRight, [ssRight]);
9991001 Add(cMouseActionClickAndSelBlock, [ssLeft, ssShift]);
10001002 Add(cMouseActionMakeCaret, [ssLeft, ssXControl]);
10011003 Add(cMouseActionMakeCaretsColumn, [ssLeft, ssXControl, ssShift]);
10021004 Add(cMouseActionNiceScrolling, [ssMiddle]);
10031005 //...
10041006```
10051007
10061008## Does it use PrimarySelection on gtk?
10071009
10081010It can use it, all methods which work with clipboard, get AClipboardObject:TClipboard, here you can pass Clipboard, PrimarySelection, SecondarySelection.
10091011
10101012Command codes for Paste: exist for Clipboard, and for PrimarySelection. This is part which reacts to command codes:
10111013
10121014``` pascal
10131015 cCommand_ClipboardCopy: Res:= DoCommand_ClipboardCopy(false, Clipboard);
10141016 cCommand_ClipboardCopyAdd: Res:= DoCommand_ClipboardCopy(true, Clipboard);
10151017 cCommand_ClipboardCut: Res:= DoCommand_ClipboardCut(Clipboard);
10161018
10171019 //use Clipboard:TClipboard
10181020 cCommand_ClipboardPaste: Res:= DoCommand_ClipboardPaste(false, false, Clipboard);
10191021 cCommand_ClipboardPaste_Select: Res:= DoCommand_ClipboardPaste(false, true, Clipboard);
10201022 cCommand_ClipboardPaste_KeepCaret: Res:= DoCommand_ClipboardPaste(true, false, Clipboard);
10211023 cCommand_ClipboardPaste_Column: Res:= DoCommand_ClipboardPasteColumnBlock(false, Clipboard);
10221024 cCommand_ClipboardPaste_ColumnKeepCaret: Res:= DoCommand_ClipboardPasteColumnBlock(true, Clipboard);
10231025
10241026 //same, but use PrimarySelection:TClipboard
10251027 cCommand_ClipboardAltPaste: Res:= DoCommand_ClipboardPaste(false, false, PrimarySelection);
10261028 cCommand_ClipboardAltPaste_Select: Res:= DoCommand_ClipboardPaste(false, true, PrimarySelection);
10271029 cCommand_ClipboardAltPaste_KeepCaret: Res:= DoCommand_ClipboardPaste(true, false, PrimarySelection);
10281030 cCommand_ClipboardAltPaste_Column: Res:= DoCommand_ClipboardPasteColumnBlock(false, PrimarySelection);
10291031 cCommand_ClipboardAltPaste_ColumnKeepCaret: Res:= DoCommand_ClipboardPasteColumnBlock(true, PrimarySelection);
10301032```
10311033
10321034Default code uses PrimarySelection in one place: on copy, it copies to Clipboard, then (under Linux/Mac) copies the same to PrimarySelection.
10331035
10341036To make middle-button-click paste from PrimarySelection, you need to handle OnClickMiddle, here's example from CudaText:
10351037
10361038``` pascal
10371039procedure TEditorFrame.EditorOnClickMiddle(Sender: TObject; var AHandled: boolean);
10381040begin
10391041 AHandled:= false;
10401042 if EditorOps.OpMouseMiddleClickPaste then
10411043 begin
10421044 AHandled:= true;
10431045 (Sender as TATSynEdit).DoCommand(cmd_MouseClickAtCursor);
10441046 (Sender as TATSynEdit).DoCommand(cCommand_ClipboardAltPaste); //uses PrimarySelection:TClipboard
10451047 exit;
10461048 end;
10471049end;
10481050```
10491051
10501052## How to handle OnCalcLineHilite event
10511053
10521054This event has type:
10531055
10541056``` pascal
10551057type
10561058 TATSynEditCalcHiliteEvent = procedure(Sender: TObject; var AParts: TATLineParts;
10571059 ALineIndex, ACharIndex, ALineLen: integer; var AColorAfterEol: TColor) of object;
10581060```
10591061
10601062Handler gets:
10611063
10621064- ALineIndex: index of line (in Strings object)
10631065- ACharIndex: offset of fragment in line (not trivial only if line is wrapped)
10641066- ALineLen: length of fragment in line (in WideChars)
10651067
10661068Handler must fill:
10671069
10681070- AParts: array of highlighted parts, one part per one "syntax token" (e.g. one symbol, one keyword, one string const, one comment, etc). Fill all other parts with zeros.
10691071- AColorAfterEol: color of background after line end (for empty area).
10701072
10711073Handler must handle the situation of line-wrapping inside long comments (or long string constants, etc), when one fragment gives part for ALineIndex=N, and next fragment gives part for ALineIndex=N+1.
10721074
10731075Example. Handler gets string with Pascal syntax like "procedure AB(name: word)". It must create such "parts" for this string:
10741076
10751077- part\[0\]: for "procedure": TATLinePart properties: offset=0, len=9, etc
10761078- part\[1\]: for "AB": offset=10, len=2
10771079- part\[2\]: for "(": offset=12, len=1
10781080- part\[3\]: for "name": offset=13, len=1
10791081- part\[4\]: for ":": offset=17, len=1
10801082- part\[5\]: for "word": offset=19, len=4
10811083- part\[6\]: for ")": offset=23, len=1
10821084- other parts must have offset=0, len=0
10831085
10841086## Details about highlighting rendering
10851087
10861088Central procedure is DoCalcLineHilite. For items of WrapInfo object, it calculates "line parts" (array TATLineParts of record TATLinePart). Each "part" here is one colored/styled fragment of string. After line parts are calculated, they pass to ATSynEdit_CanvasProc.CanvasTextOut to render.
10871089
10881090DoCalcLineHilite works like this:
10891091
10901092- Updates adapter's "dynamic hilites enabled" flag (to on/off) and calls adapter's OnCalcLineHilite. This makes initial version of line parts.
10911093- Calculated line parts are added to cache (same calculation of same WrapInfo item will not happen, only cache item is used).
10921094- Updates line parts via OnCalcHilite event (it's additional method to hilite, first is adapter, usually only adapter is used).
10931095- Calls DoPartCalc_ApplyAttribsOver to apply Attribs object to line parts. E.g. add parts for spell-checker bad words. E.g. add parts for underlined URLs.
10941096- Calls DoPartCalc_ApplySelectionOver to apply selection (for all multi-carets, or one column selection) to parts.
10951097
10961098DoPartCalc_ApplySelectionOver is complex function. It updates TATLineParts. How it works:
10971099
10981100- It tests entire TATLineParts - is it all selected (optimization for selected-all), or all unselected (optimization for selected-none), or partly selected.
10991101- If all selected, it just marks all parts (already calc'ed) with selection color. If partly selected, it finds parts, which are all/partly selected.
11001102- For parts, which are all selected, it marks them with selection color.
11011103- For parts, which are partly selected, it makes slow loop over offsets in parts. This slow loop finds chars which are selected and inserts new parts (with selection color) for them.
11021104
11031105To find/insert parts to TATLineParts, funcs DoPartFind/ DoPartInsert are used.
11041106
11051107## How to control vert/horz scrolling?
11061108
11071109Property LineTop is index of top visible line, it is not precise vert scroll position, if long wrapped lines present.
11081110
11091111Public prop: WrapInfo, it's list of wrapinfo items. You can read it to get all info about wrapped lines, at which offsets they are wrapped. This allows to make smart jump of caret on wrapped lines.
11101112
11111113Public props: ScrollVert, ScrollHorz. They are records, NPos is scroll pos. ScrollVert.NPos is index in WrapInfo list, change it to make precise scrolling (call Update() then). ScrollHorz.NPos is horz scroll pos, now it's the same as prop ColumnLeft.
11121114
11131115Method DoScrollByDelta(Dx, Dy) allows to increment/decrement horz (Dx) and vert (Dy) scroll positions.
11141116
11151117## When Update call is needed?
11161118
11171119First param of Update() method is boolean: force updating the WrapInfo object.
11181120
11191121- Update(true): needed if you changed Strings contents - directly via Strings object; or changed Fold ranges - directly via Fold object. Ie, if WrapInfo object needs update (and component cannot detect this automatically).
11201122- Update(false): needed if you only changed look, ie carets, scroll position, bookmarks, markers, etc.
11211123- no Update() call is needed, if you only called DoCommand(). DoCommand does it automatically.
11221124
11231125## Behaviour of column selection
11241126
11251127ATSynEdit gives two modes of column selection, which have differences when you select over wrapped lines, or lines with full-width characters. This is controlled by property OptCaretsPrimitiveColumnSelection.
11261128
11271129- Value True: "pritimive mode" which behaves much like Sublime Text. In this mode editor places multi-selections over visual rectangle of characters. In this mode, one line can have 6 chars selected, and another line can have 8 chars selected. This depends on visual positions of chars in those lines.
11281130
11291131- Value False: in this mode, all affected lines have the same number of selected chars. But when full-width chars (e.g. CJK) are present in text, selection may look weird. Here is an example picture where starting lines are ASCII and ending lines have full-width chars.
11301132
11311133![](/wiki-images/5/5b/Cudatext-column-sel-cjk.png)
11321134
11331135It is not a bug. In this example, user selected column block from column 7 (at line 1) until column 20 (at line 6), so column block takes columns 7...20 from all lines. On first ASCII lines, columns 7...20 take different visual area, than columns on last lines. When you copy/paste that block to another program, block may look differently. But that block contains equal number of chars on each line.
11341136
11351137Even more weird look happens when user selects column block over word-wrapped lines.
11361138
11371139![](/wiki-images/b/ba/Cudatext-column-sel-weird.png)
11381140
11391141Here is the code's logic in all these cases (with full-width characters and with word-wrapped lines). Code calculates (line1, column1) text position of column block left-top edge. Then code calculates (line2, column2) text position of column block right-bottom edge. Then code selects characters in range column1...column2 in all those affected lines line1...line2. And this code logic produces so weird look in word-wrapped mode.
11401142
11411143## Horizontal scrollbar only increases but never shrinks?
11421144
11431145Horizontal scrollbar has unusual behaviour: its width only increases (when long lines appear in the visible area). It never shrinks when we scroll to shorter lines. It was made as a workaround to GTK2 widgetset freezes - it freezes when scrollbar shows/hides/shows/hides/etc on scrolling.
11441146
11451147You can try to disable this workaround in file atsynedit_defines.inc:
11461148
11471149``` pascal
11481150{$define fix_horzscroll} //workaround for gtk2 widgetset unstable: it freezes app
11491151 //when horz-scroll hides/shows/hides/...
11501152 //ok also for win32
11511153```
11521154
11531155## more
11541156
11551157# Auto-completion lists
11561158
11571159## General auto-completion API
11581160
11591161You need to install package ATSynEdit_Cmp, from repo <https://github.com/Alexey-T/ATSynEdit_Cmp> .
11601162
11611163Unit atsynedit_cmp_form (from ATSynEdit_Cmp package) has the function to show completion listbox in the editor. This listbox is not modal, it only emulates modality of some degree. It keeps editor caret blinking. While completion listbox is shown, editor doesn't get keyboard input, but listbox passes typing letters/Backspace/Left/Right to the editor, so it looks like editor gets some part of keyboard input. Listbox performs insertion of chosen item on Enter/Tab keys, and it hides on Esc-key or clicking outside of the listbox.
11621164
11631165``` pascal
11641166type
11651167 TATCompletionPropEvent = procedure (Sender: TObject;
11661168 AContent: TStringList; out ACharsLeft, ACharsRight: integer) of object;
11671169 TATCompletionResultEvent = procedure (Sender: TObject;
11681170 const ASnippetId: string; ASnippetIndex: integer) of object;
11691171
11701172procedure EditorShowCompletionListbox(AEd: TATSynEdit;
11711173 AOnGetProp: TATCompletionPropEvent;
11721174 AOnResult: TATCompletionResultEvent = nil;
11731175 AOnChoose: TATCompletionResultEvent = nil;
11741176 const ASnippetId: string = '';
11751177 ASelectedIndex: integer = 0;
11761178 AAllowCarets: boolean = false);
11771179```
11781180
11791181Callback AOnGetProp params:
11801182
11811183- AContent: list of lines, each line is S_id+'\|'+S_text+'\|'+S_desc. S_id is a prefix before actual text (good to pass here short texts: "var", "func"). S_text (it is usually second item) is text which is inserted into editor on closing listbox. After id/text several items may exist, all '\|'-separated, they will show in additional listbox columns. For example, this TStringList line makes the listbox line of 3 columns:
11821184
11831185``` pascal
11841186 'func|FuncName|(param1, param2)'#9'Func description';
11851187```
11861188
11871189- - If you need to insert not only S_text but also additional substring (showing in the listbox only S_text), use such S_text: S_text+#1+S_before_caret+#1+S_after_caret (also substrings will be added before and after caret). This is used by HTML autocompletion: here S_before_caret is "\>" and S_after_caret is "\</tag\>".
11881190 - At the end of lines, you may add Chr(9)+S_tooltip: string S_tooltip will show outside of listbox, in a tooltip, when user selects its line. To show multi-line tooltip, separate it with Chr(2).
11891191
11901192- ACharsLeft, ACharsRight: count of chars, to the left and right of the caret, which will be replaced by selected listbox item. These counts must be detected by app. Some app may need to count only word chars, some may need spaces/brackets.
11911193
11921194Notes:
11931195
11941196- Function EditorShowCompletionListbox doesn't work for a) read-only editor, b) multi-carets.
11951197- You can change colors/sizes/font of listbox: see unit source, it gives the global variable (record with many fields).
11961198
11971199## Auto-completion using acp-files
11981200
11991201Unit atsynedit_cmp_acpfiles has the function to show auto-completion listbox, from CudaText/SynWrite .acp files. Acp file must be in the format described in the SynWrite help file. You may copy acp files from CudaText distro, or from additional lexers, ie from CudaText lexers on CudaText.SF.net.
12001202
12011203![](/wiki-images/a/a3/Cudatext-php-complete.png)
12021204
12031205## Auto-completion for CSS
12041206
12051207Unit atsynedit_cmp_css has the function to show auto-completion listbox, for CSS syntax. You must pass path of the file "data/autocompletespec/css_list.ini" from CudaText distro. CSS completion supports several modes:
12061208
12071209- caret is on css attrib before ":" char - then list of css attribs is shown (which match the substring under caret),
12081210- caret is after css attrib and ":" char (before closing ";") - then list of values for this attrib is shown.
12091211- and more
12101212
12111213![](/wiki-images/5/55/Cudatext-css-complete.png)
12121214
12131215## Auto-completion for HTML
12141216
12151217Unit atsynedit_cmp_html has the function to show auto-completion listbox, for HTML syntax. You must pass path of the file "data/autocompletespec/html_list.ini" from CudaText distro. HTML completion supports several modes:
12161218
12171219- caret on opening/closing tag name: list of tags shown
12181220- caret after tag, on attribute place before "=": list of attribs for found tag shown
12191221- caret after tag, after attribute, after "=": list of values of found tag+attrib shown
12201222- and more
12211223
12221224![](/wiki-images/7/7b/Cudatext-html-complete.png)
12231225
12241226# Finder
12251227
12261228Finder class TATEditorFinder is in unit atsynedit_finder. To use it, create Finder object and set its props:
12271229
12281230- Editor: editor object (text will be read automatically)
12291231- StrFind: search-string (simple string or regex)
12301232- StrReplace: replace-string (simple string or some regex, eg with "\$0", "\$1")
12311233- boolean search flags:
12321234 - OptRegex: treat StrFind/StrReplace as regex
12331235 - OptCase: case-sensitive (for normal and regex modes)
12341236 - OptWords: whole-words search (for non-regex mode, for regex you must use "\b" specifier in search-string)
12351237 - OptBack: backward search (for non-regex mode)
12361238 - OptWrapped: continue search from top, if bottom reached (for back-search: continue from bottom, if top reached)
12371239 - OptInSelection: do search/replace in selection only (limitation exists: only 1st selection used)
12381240 - OptFromCaret: search goes from position of first caret (else: from start/end of text)
12391241 - OptConfirmReplace: each replace will occur after event OnConfirmReplace
12401242
12411243Dialog of demo:
12421244
12431245![](/wiki-images/b/b3/Atsynedit_finder.png)
12441246
12451247Methods to find/replace text (they will place selection on found match, and scroll editor to caret, except method CountAll):
12461248
12471249``` pascal
12481250function DoAction_FindSimple(const APosStart: TPoint): boolean;
12491251function DoAction_FindOrReplace(AReplace, AForMany: boolean; out AChanged: boolean;
12501252 AUpdateCaret: boolean): boolean;
12511253function DoAction_ReplaceSelected(AUpdateCaret: boolean): boolean;
12521254procedure DoAction_FindAll(AResults: TATFinderResults; AWithEvent: boolean);
12531255function DoAction_CountAll(AWithEvent: boolean): integer;
12541256procedure DoAction_ExtractAll(AWithEvent: boolean; AMatches: TStringList; ASorted: boolean;
12551257 ADuplicates: TDuplicates);
12561258function DoAction_ReplaceAll: integer;
12571259```
12581260
12591261Found position and len are saved in props: MatchPos, MatchLen. Internally Finder object uses ATStringBuffer to read editor lines into buffer and search inside buffer. Then ATStringBuffer methods used to calculate caret position (from buffer offset) and place caret/selection. Note for regex search: buffer contains only "\n" line ends, other ends don't happen (original file may have any ends).
12601262
12611263Finder has events:
12621264
12631265- OnProgress: allows to show progressbar during search
12641266- OnFound: called when result found
12651267- OnConfirmReplace: called before replacing text (to show confirmation) if OptConfirmReplace set
12661268
12671269Finder can handle multi-selections, by option OptInSelection. Selections are handled by CountAll, ReplaceAll. For other actions, selections don't make sense, because find-next makes new smaller selection (for found fragment) so prev big selection is lost. Tech note for replace-all: selections are looked from top to bottom, if they don't have common lines, and looked from bottom to top, if they have. This is done to not break lines, which are touched by 2+ selections. Count-all handles selections from top to bottom.
12681270
12691271# Adapters
12701272
12711273## Adapters description
12721274
12731275To support syntax-highlighting in some way, you need
12741276
12751277- Add event OnCalcHilite handler, which must fill the TATLineParts array with needed highlighting, or
12761278- Create the unit with adapter class, child of TATAdapterHilite (unit atsynedit_adapters), which must fill the TATLineParts array, again. Partial code of the adapter class:
12771279
12781280``` pascal
12791281type
12801282 TATAdapterHilite = class(TComponent)
12811283 ...
12821284 public
12831285 constructor Create(AOwner: TComponent); override;
12841286 //
12851287 procedure OnEditorChange(Sender: TObject); virtual;
12861288 //called when editor's text changes.
12871289
12881290 procedure OnEditorChangeEx(Sender: TObject; AChange: TATLineChangeKind; ALine, AItemCount: integer); virtual;
12891291 //detailed version of OnEditorChange
12901292
12911293 procedure OnEditorIdle(Sender: TObject); virtual;
12921294 //called after text is changed, and pause passed (OptIdleInterval)
12931295 //fast changes (faster than OptIdleInterval): called only after last change
12941296
12951297 procedure OnEditorCalcHilite(Sender: TObject;
12961298 var AParts: TATLineParts;
12971299 ALineIndex, ACharIndex, ALineLen: integer;
12981300 var AColorAfterEol: TColor;
12991301 AMainText: boolean); virtual;
13001302 //called to calculate hilite of entire line.
13011303 //ACharIndex is starting offset in this line, >0 if editor scrolled horizontally.
13021304 //ALineLen is len of line part, starting from ACharIndex.
13031305 ...
13041306```
13051307
13061308You need your custom adapter class, child of TATAdapterHilite, which must implement some of methods. You don't have to implement all of them, if your adapter doesn't need that. Then you must create an object of your adapter class, and assign this object to editor's AdapterForHilite property.
13071309
13081310The package ATSynEdit_Ex contains 2 ready adapter classes: for complex EControl .lcf lexers, and for CudaText simplified "lite" lexers. The lexer files are distributed in the CudaText repos on SourceForge.
13091311
13101312## Adapter for EControl lexers
13111313
13121314See [[ATSynEdit EControl adapter]]
13131315
13141316# How to adapt TRegExpr upstream for ATSynEdit
13151317
13161318TRegExpr upstream is <https://github.com/andgineer/TRegExpr> . How to convert it to atsynedit_regexpr unit.
13171319
13181320- rename unit
13191321- change "uses regexpr_unicodedata" to "uses ATSynEdit_UnicodeData"
13201322- comment line {\$I regexpr_compilers.inc}
13211323- set define on: UniCode
13221324- set define on: FastUnicodeData
13231325- set defines off: UseSpaceChars, UseWordChars
13241326- fix vars:
13251327
13261328``` pascal
13271329 RegExprModifierI: boolean = False; // default value for ModifierI
13281330 RegExprModifierR: boolean = True; // default value for ModifierR
13291331 RegExprModifierS: boolean = False; // default value for ModifierS
13301332 RegExprModifierG: boolean = True; // default value for ModifierG
13311333 RegExprModifierM: boolean = True; // default value for ModifierM
13321334 RegExprModifierX: boolean = False; // default value for ModifierX
13331335
13341336 RegExprLineSeparators: RegExprString = #$a#$b#$c
13351337 {$IFDEF UniCode}
13361338 + #$2028#$2029#$85
13371339 {$ENDIF};
13381340 RegExprLinePairedSeparator: RegExprString = ''; //#$d#$a;
13391341
13401342 FUseOsLineEndOnReplace := False;
13411343 FReplaceLineEnd := #10; //not sLineBreak, it is CR LF on Windows
13421344```
13431345
13441346---
13451347*From the Free Pascal wiki, page "ATSynEdit", as it stood on 2024-04-04 after a change by Alextp, 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).*
13461348Category: ATSynEdit
13471349Category: Components

Back to history