Subversion Repositories Kolibri OS

Rev

Rev 9913 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
8728 leency 1
(*
9891 akron1 2
    Copyright 2021-2023 Anton Krotov
8728 leency 3
 
4
    This file is part of CEdit.
5
 
6
    CEdit is free software: you can redistribute it and/or modify
7
    it under the terms of the GNU General Public License as published by
8
    the Free Software Foundation, either version 3 of the License, or
9
    (at your option) any later version.
10
 
11
    CEdit is distributed in the hope that it will be useful,
12
    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
    GNU General Public License for more details.
15
 
16
    You should have received a copy of the GNU General Public License
17
    along with CEdit. If not, see .
18
*)
19
 
20
MODULE Text;
21
 
22
IMPORT
23
    List, Lines,
24
    G := Graph,
25
    U := Utils,
26
    RW, Search,
27
    E := Encodings,
28
    CB := Clipboard,
9073 leency 29
    ChangeLog, File,
8728 leency 30
    Lang := Languages;
31
 
32
 
33
CONST
34
 
9174 akron1 35
    SPACE = Lines.SPACE;
36
    TAB = Lines.TAB;
37
    TAB1 = Lines.TAB1;
8728 leency 38
    lenEOL = CB.lenEOL;
39
 
40
    mark_width = 2;
41
    pad_left = mark_width + 3;
9892 akron1 42
    pad_top = 1;
9915 akron1 43
    LineSpacing* = 2;
8728 leency 44
 
45
 
46
TYPE
47
 
9210 akron1 48
    tPoint* = RECORD
49
        X*, Y*: INTEGER
8728 leency 50
    END;
51
 
52
    pPoint = POINTER TO tPoint;
53
 
54
    tString* = ARRAY 1000 OF WCHAR;
55
 
56
    tLine = Lines.tLine;
57
 
58
    tGuard = POINTER TO RECORD (ChangeLog.tGuard)
59
        selected: BOOLEAN;
60
        cursor, select2, scroll: tPoint;
61
        CurX: INTEGER
62
    END;
63
 
64
    tText* = POINTER TO RECORD (List.tList)
65
        cursor, select, select2: pPoint;
66
        scroll: tPoint;
67
        CurX: INTEGER;
9668 akron1 68
        smallChange: INTEGER;
9671 akron1 69
        modified*, smallMove,
9674 akron1 70
        comments, guard, fasm*,
9904 akron1 71
        search, cs, whole, wordSel: BOOLEAN;
8728 leency 72
        edition*: tGuard;
73
        curLine: tLine;
74
        lang*: INTEGER;
9336 akron1 75
        enc, eol: INTEGER;
8728 leency 76
        foundList: List.tList;
9915 akron1 77
        foundSel*, foundCur*, foundCnt*: INTEGER;
9050 leency 78
        searchText: tString;
9668 akron1 79
        LinesVector: Lines.tVector;
9050 leency 80
        chLog*: ChangeLog.tLog;
9210 akron1 81
        maxLength*: INTEGER;
82
        fileName*: RW.tFileName
8728 leency 83
    END;
84
 
85
    tProcedure = PROCEDURE;
86
 
87
 
88
VAR
89
 
90
    pdelete: PROCEDURE (text: tText);
91
    ShowCursor: PROCEDURE;
92
 
9671 akron1 93
    colors: RECORD
8762 leency 94
                text, back, seltext, selback, modified, saved, curline, numtext, numback: INTEGER;
9413 akron1 95
                comment, string, escape, num, delim, key1, key2, key3: INTEGER
8728 leency 96
             END;
97
    canvas: G.tCanvas;
9174 akron1 98
    drawCursor: BOOLEAN;
8728 leency 99
    padding: RECORD left, top: INTEGER END;
100
    size, textsize: tPoint;
101
    charWidth, charHeight: INTEGER;
9671 akron1 102
    autoIndents*, lineNumbers*, autoBrackets*, trimSpace*: BOOLEAN;
8728 leency 103
 
104
 
9210 akron1 105
PROCEDURE setLang* (text: tText; lang: INTEGER);
106
BEGIN
9674 akron1 107
	IF text.lang # lang THEN
108
		text.fasm := lang = Lang.langFasm;
109
		text.lang := lang
110
	END;
9210 akron1 111
    text.comments := TRUE;
112
    Lang.setCurLang(text.lang)
113
END setLang;
114
 
115
 
8728 leency 116
PROCEDURE setName* (text: tText; name: RW.tFileName);
117
VAR
118
    ext: RW.tFileName;
119
BEGIN
120
    text.fileName := name;
9210 akron1 121
    U.getFileName(name, ext, ".");
9903 akron1 122
    U.lowcase8(ext);
9210 akron1 123
    setLang(text, Lang.getLang(ext))
8728 leency 124
END setName;
125
 
126
 
127
PROCEDURE getPos* (text: tText; VAR x, y: INTEGER);
128
BEGIN
129
    x := text.cursor.X + 1;
130
    y := text.cursor.Y + 1
131
END getPos;
132
 
133
 
134
PROCEDURE getScroll* (text: tText; VAR x, y: INTEGER);
135
BEGIN
136
    x := text.scroll.X;
137
    y := text.scroll.Y
138
END getScroll;
139
 
140
 
141
PROCEDURE getTextSize* (VAR x, y: INTEGER);
142
BEGIN
143
    x := textsize.X;
144
    y := textsize.Y
145
END getTextSize;
146
 
147
 
148
PROCEDURE getTextRect* (VAR left, top, rigth, bottom: INTEGER);
149
BEGIN
150
    left := padding.left - 1;
151
    top := padding.top - 1;
152
    rigth := size.X - 1;
153
    bottom := top + size.Y - 1;
154
END getTextRect;
155
 
156
 
9671 akron1 157
PROCEDURE toggleNumbers*;
8728 leency 158
BEGIN
9671 akron1 159
    lineNumbers := ~lineNumbers
8728 leency 160
END toggleNumbers;
161
 
162
 
9671 akron1 163
PROCEDURE toggleIndents*;
164
BEGIN
165
    autoIndents := ~autoIndents
166
END toggleIndents;
167
 
168
 
169
PROCEDURE toggleBrackets*;
170
BEGIN
171
    autoBrackets := ~autoBrackets
172
END toggleBrackets;
173
 
174
 
175
PROCEDURE toggleTrimSpace*;
176
BEGIN
177
    trimSpace := ~trimSpace
178
END toggleTrimSpace;
179
 
180
 
9174 akron1 181
PROCEDURE showCursor*;
182
BEGIN
183
	drawCursor := TRUE
184
END showCursor;
185
 
186
 
187
PROCEDURE hideCursor*;
188
BEGIN
189
	drawCursor := FALSE
190
END hideCursor;
191
 
192
 
8728 leency 193
PROCEDURE getString (src: tLine; pos, cnt: INTEGER; VAR dst: ARRAY OF WCHAR): INTEGER;
194
VAR
195
    i: INTEGER;
196
BEGIN
197
    i := 0;
198
    WHILE (pos < src.length) & (cnt > 0) DO
199
        IF i < LEN(dst) - 1 THEN
9659 akron1 200
            dst[i] := Lines.getChar(src, pos);
8728 leency 201
            INC(i)
202
        END;
203
        INC(pos);
204
        DEC(cnt)
205
    END;
206
    dst[i] := 0X
207
    RETURN i
208
END getString;
209
 
210
 
211
PROCEDURE NextLine (VAR line: tLine);
212
BEGIN
213
    line := line.next(tLine)
214
END NextLine;
215
 
216
 
217
PROCEDURE PrevLine (VAR line: tLine);
218
BEGIN
219
    line := line.prev(tLine)
220
END PrevLine;
221
 
222
 
223
PROCEDURE SetColor (textColor, backColor: INTEGER);
224
BEGIN
225
    G.SetTextColor(canvas, textColor);
226
    G.SetBkColor(canvas, backColor)
227
END SetColor;
228
 
229
 
230
PROCEDURE ProcessComments (line: tLine; VAR depth, pos: INTEGER; minDepth, n: INTEGER; lang: INTEGER);
231
VAR
232
    cond: INTEGER;
233
BEGIN
234
    cond := 0;
235
    WHILE (pos <= n) & (depth > minDepth) DO
236
        Lang.comments(line, depth, cond, pos, n, lang);
237
        INC(pos)
238
    END;
239
    DEC(pos)
240
END ProcessComments;
241
 
242
 
9668 akron1 243
PROCEDURE getLine2 (text: tText; n: INTEGER): tLine;
244
VAR
245
	item: tLine;
246
BEGIN
247
	IF (0 <= n) & (n < text.count) THEN
248
		item := Lines.getVectorItem(text.LinesVector, n)
249
	ELSE
250
		item := NIL
251
	END
252
	RETURN item
253
END getLine2;
254
 
255
 
8728 leency 256
PROCEDURE Comments (text: tText);
257
VAR
9668 akron1 258
	line: tLine;
259
	i, k, cout: INTEGER;
8728 leency 260
BEGIN
9668 akron1 261
	IF text.smallChange = 1 THEN
262
		line := getLine2(text, text.cursor.Y);
263
		IF line.prev # NIL THEN
264
			line.cin := line.prev(tLine).cout
265
		ELSE
266
			line.cin := 0
267
		END;
268
		cout := line.cout;
269
		line.cout := line.cin;
270
		i := 0;
271
		ProcessComments(line, line.cout, i, -1, line.length - 1, text.lang);
272
		IF line.cout # cout THEN
273
			text.smallChange := 0;
274
			Comments(text)
275
		END
276
	ELSE
277
		Lines.destroyVector(text.LinesVector);
278
		text.LinesVector := Lines.createVector(text.count);
279
		k := 0;
280
		line := text.first(tLine);
281
		Lines.setVectorItem(text.LinesVector, k, line);
282
		INC(k);
283
		line.cin := 0;
284
		line.cout := 0;
285
		i := 0;
286
		ProcessComments(line, line.cout, i, -1, line.length - 1, text.lang);
287
		NextLine(line);
288
		WHILE line # NIL DO
289
			Lines.setVectorItem(text.LinesVector, k, line);
290
			INC(k);
291
			line.cin := line.prev(tLine).cout;
292
			line.cout := line.cin;
293
			i := 0;
294
			ProcessComments(line, line.cout, i, -1, line.length - 1, text.lang);
295
			NextLine(line)
296
		END
297
	END;
298
	text.smallChange := 0;
299
	text.comments := FALSE
8728 leency 300
END Comments;
301
 
302
 
9674 akron1 303
PROCEDURE leadingSpaces (line: tLine): INTEGER;
304
VAR
305
    i: INTEGER;
306
BEGIN
307
    i := 0;
308
    WHILE Lines.isSpace(Lines.getChar(line, i)) DO
309
        INC(i)
310
    END
311
    RETURN i
312
END leadingSpaces;
313
 
314
 
8728 leency 315
PROCEDURE parse (text: tText; line: tLine; y: INTEGER; backColor: INTEGER; lang: INTEGER);
316
VAR
317
    c: WCHAR;
318
    i, n, k: INTEGER;
319
    cond, depth: INTEGER;
320
    color: INTEGER;
321
    hex: BOOLEAN;
322
    isDgt: PROCEDURE (c: WCHAR): BOOLEAN;
323
 
324
 
325
    PROCEDURE PrintLex (text: tText; line: tLine; lexStart, lexEnd: INTEGER; y: INTEGER; color, backColor: INTEGER);
326
    VAR
327
        lexLen: INTEGER;
328
    BEGIN
329
        SetColor(color, backColor);
330
        lexLen := MAX(MIN(line.length - lexStart, lexEnd - lexStart + 1), 0);
9193 akron1 331
        G.TextOut(canvas, padding.left + (lexStart - text.scroll.X) * charWidth, y, Lines.getPChar(line, lexStart), lexLen, color)
8728 leency 332
    END PrintLex;
333
 
334
 
9193 akron1 335
    PROCEDURE PrintComment (text: tText; line: tLine; VAR depth, i: INTEGER; w, y: INTEGER; backColor: INTEGER);
8728 leency 336
    VAR
337
        lexStart: INTEGER;
338
        color: INTEGER;
339
    BEGIN
340
        IF (text.lang = Lang.langLua) & ~ODD(depth) THEN
341
            color := colors.string
342
        ELSIF (text.lang = Lang.langIni) & (depth = 1) THEN
343
            color := colors.key2
344
        ELSIF (text.lang = Lang.langPascal) & (depth = 3) THEN
345
            color := colors.key3
346
        ELSE
347
            color := colors.comment
348
        END;
9193 akron1 349
        lexStart := MAX(i - w, 0);
8728 leency 350
        ProcessComments(line, depth, i, 0, line.length - 1, text.lang);
351
        PrintLex(text, line, lexStart, i, y, color, backColor)
352
    END PrintComment;
353
 
354
 
9903 akron1 355
    PROCEDURE upper (c: WCHAR): WCHAR;
8728 leency 356
    BEGIN
9903 akron1 357
        IF U.upper(c) THEN END
8728 leency 358
        RETURN c
9903 akron1 359
    END upper;
8728 leency 360
 
361
 
362
    PROCEDURE UL (c: WCHAR): BOOLEAN;
9903 akron1 363
        RETURN (upper(c) = "U") OR (upper(c) = "L")
8728 leency 364
    END UL;
365
 
366
 
367
    PROCEDURE FL (c: WCHAR): BOOLEAN;
9903 akron1 368
        RETURN (upper(c) = "F") OR (upper(c) = "L")
8728 leency 369
    END FL;
370
 
371
 
372
    PROCEDURE ident (text: tText; VAR i: INTEGER; first, y: INTEGER; line: tLine; backColor: INTEGER; cs: BOOLEAN);
373
    VAR
374
        c: WCHAR;
375
        lexLen: INTEGER;
376
        s: ARRAY 32 OF WCHAR;
377
        color: INTEGER;
378
    BEGIN
9659 akron1 379
        c := Lines.getChar(line, i);
8728 leency 380
        WHILE U.isLetter(c) OR (c = "_") OR U.isDigit(c) DO
381
            INC(i);
9659 akron1 382
            c := Lines.getChar(line, i);
8728 leency 383
        END;
384
        DEC(i);
385
        lexLen := getString(line, first, i - first + 1, s);
386
        IF ~cs THEN
9903 akron1 387
            U.lowcase(s)
8728 leency 388
        END;
389
        IF Lang.isKey(s, text.lang, 1) THEN
390
            color := colors.key1
391
        ELSIF Lang.isKey(s, text.lang, 2) THEN
392
            color := colors.key2
393
        ELSIF Lang.isKey(s, text.lang, 3) THEN
394
            color := colors.key3
395
        ELSE
396
            color := colors.text
397
        END;
398
        IF color # colors.text THEN
399
            PrintLex(text, line, first, i, y, color, backColor)
400
        END
401
    END ident;
402
 
403
 
404
    PROCEDURE String (text: tText; line: tLine; VAR i: INTEGER; y: INTEGER; backColor: INTEGER);
405
    VAR
9413 akron1 406
        k, j, Start, End: INTEGER;
407
        c: WCHAR;
8728 leency 408
    BEGIN
409
        k := i;
9413 akron1 410
        Lang.SkipString(line, i, line.length - 1, text.lang);
411
        PrintLex(text, line, k, i, y, colors.string, backColor);
412
        IF text.lang IN Lang.escLang THEN
413
	        Start := k + 1;
414
	        End := i - 1;
415
	        k := Start;
416
	        WHILE k <= End DO
9659 akron1 417
	        	c := Lines.getChar(line, k);
9413 akron1 418
	        	IF c = "\" THEN
419
	        		j := k;
420
	        		Lang.SkipEsc(line, k, line.length - 1, text.lang);
421
	        		PrintLex(text, line, j, k, y, colors.escape, backColor)
422
	        	END;
423
	        	INC(k)
424
	        END
425
        END
8728 leency 426
    END String;
427
 
428
 
429
BEGIN
430
    depth := line.cin;
431
    n := line.length - 1;
432
    i := 0;
433
    IF (depth > 0) & (n >= 0) THEN
9193 akron1 434
        PrintComment(text, line, depth, i, 2, y, backColor)
8728 leency 435
    END;
436
    cond := 0;
437
    WHILE i <= n DO
9659 akron1 438
        c := Lines.getChar(line, i);
8728 leency 439
 
440
        IF lang = Lang.langFasm THEN
441
 
442
            IF c = ";" THEN
443
                PrintLex(text, line, i, n, y, colors.comment, backColor);
444
                i := n
445
            ELSIF (c = "'") OR (c = '"') THEN
446
                String(text, line, i, y, backColor)
447
            ELSIF (U.isLetter(c) OR (c = "_")) THEN
9050 leency 448
                ident(text, i, i, y, line, backColor, Lang.isCS(lang))
8728 leency 449
            ELSIF U.isDigit(c) THEN
450
                hex := FALSE;
451
                k := i;
452
                INC(i);
9659 akron1 453
                c := Lines.getChar(line, i);
9903 akron1 454
                IF (upper(c) = "X") & (Lines.getChar(line, i - 1) = "0") THEN
8728 leency 455
                    INC(i);
456
                    hex := TRUE
457
                END;
458
 
9903 akron1 459
                WHILE U.isHex(upper(Lines.getChar(line, i))) DO
8728 leency 460
                    INC(i)
461
                END;
462
 
9903 akron1 463
                IF (upper(Lines.getChar(line, i)) = "H") & ~hex THEN
8728 leency 464
                    INC(i)
465
                END;
466
 
467
                DEC(i);
468
                PrintLex(text, line, k, i, y, colors.num, backColor)
469
            END
470
 
9174 akron1 471
        ELSIF (lang = Lang.langC) OR (lang = Lang.langJSON) THEN
8728 leency 472
 
9210 akron1 473
	        IF depth = 0 THEN
474
	            IF c = "/" THEN
475
	                IF cond = 0 THEN
476
	                    cond := 1
477
	                ELSE
478
	                    PrintLex(text, line, i - 1, n, y, colors.comment, backColor);
479
	                    cond := 0;
480
	                    i := n
481
	                END
482
	            ELSIF (c = "*") & (cond = 1) THEN
483
	                depth := 1;
484
	                INC(i);
485
	                PrintComment(text, line, depth, i, 2, y, backColor);
486
	                cond := 0
487
	            ELSIF U.isLetter(c) OR (c = "_") OR (c = "'") OR (c = '"') THEN
488
	            	k := i;
489
	            	IF (c = "'") OR (c = '"') THEN
490
	            		String(text, line, i, y, backColor);
491
	            	ELSE
9659 akron1 492
	            		ident(text, i, i - ORD((lang = Lang.langC) & (i > 0) & (Lines.getChar(line, i - 1) = "#")), y, line, backColor, Lang.isCS(lang))
9210 akron1 493
	            	END;
494
	                IF lang = Lang.langJSON THEN
9659 akron1 495
		                WHILE Lines.isSpace(Lines.getChar(line, i + 1)) DO
9210 akron1 496
		                	INC(i)
497
		                END;
9659 akron1 498
		                IF Lines.getChar(line, i + 1) = ":" THEN
9210 akron1 499
		                	PrintLex(text, line, k, i, y, colors.key1, backColor)
500
		                END
9174 akron1 501
	                END;
9210 akron1 502
	                cond := 0
503
	            ELSIF U.isDigit(c) THEN
504
	                k := i;
505
	                INC(i);
9659 akron1 506
	                c := Lines.getChar(line, i);
9210 akron1 507
	                IF c = "." THEN
508
	                    DEC(i);
9659 akron1 509
	                    c := Lines.getChar(line, i)
9210 akron1 510
	                END;
9903 akron1 511
	                IF (upper(c) = "X") & (Lines.getChar(line, i - 1) = "0") THEN
9210 akron1 512
	                    REPEAT
513
	                        INC(i);
9659 akron1 514
	                        c := Lines.getChar(line, i)
9903 akron1 515
	                    UNTIL ~U.isHex(upper(c));
9210 akron1 516
	                    IF UL(c) THEN
517
	                        INC(i)
518
	                    END
519
	                ELSIF UL(c) THEN
520
	                    INC(i)
521
	                ELSIF U.isDigit(c) THEN
522
	                    REPEAT
523
	                        INC(i)
9659 akron1 524
	                    UNTIL ~U.isDigit(Lines.getChar(line, i));
525
	                    c := Lines.getChar(line, i);
9210 akron1 526
	                    IF UL(c) THEN
527
	                        INC(i)
528
	                    ELSIF c = "." THEN
529
	                        INC(i);
9659 akron1 530
	                        WHILE U.isDigit(Lines.getChar(line, i)) DO
9210 akron1 531
	                            INC(i)
532
	                        END;
9659 akron1 533
	                        c := Lines.getChar(line, i);
9903 akron1 534
	                        IF upper(c) = "E" THEN
9210 akron1 535
	                            INC(i);
9659 akron1 536
	                            c := Lines.getChar(line, i);
9210 akron1 537
	                            IF (c = "+") OR (c = "-") THEN
538
	                                INC(i)
539
	                            END;
9659 akron1 540
	                            IF U.isDigit(Lines.getChar(line, i)) THEN
541
	                                WHILE U.isDigit(Lines.getChar(line, i)) DO
9210 akron1 542
	                                    INC(i)
543
	                                END;
9659 akron1 544
	                                c := Lines.getChar(line, i);
9210 akron1 545
	                                IF FL(c) THEN
546
	                                    INC(i)
547
	                                END
548
	                            END
549
	                        ELSIF FL(c) THEN
550
	                            INC(i)
551
	                        END
552
	                    END
553
	                END;
554
	                DEC(i);
555
	                PrintLex(text, line, k, i, y, colors.num, backColor);
556
	                cond := 0
557
	            ELSE
558
	                cond := 0
559
	            END
560
	        ELSIF depth = 1 THEN
561
	            IF c = "*" THEN
562
	                cond := 1
563
	            ELSIF (c = "/") & (cond = 1) THEN
564
	                cond := 0;
565
	                depth := 0
566
	            ELSE
567
	                cond := 0
568
	            END
569
	        END
8728 leency 570
 
571
        ELSIF lang = Lang.langOberon THEN
572
 
9210 akron1 573
	        IF (depth = 0) & (c = "/") THEN
574
	            IF cond = 3 THEN
575
	                PrintLex(text, line, i - 1, n, y, colors.comment, backColor);
576
	                cond := 0;
577
	                i := n
578
	            ELSE
579
	                cond := 3
580
	            END
581
	        ELSIF (depth = 0) & ((c = "'") OR (c = '"')) THEN
582
	            String(text, line, i, y, backColor);
583
	            cond := 0
584
	        ELSIF (depth = 0) & U.isDigit(c) THEN
585
	            color := colors.num;
586
	            k := i;
587
	            INC(i);
9659 akron1 588
	            WHILE U.isHex(Lines.getChar(line, i)) DO
9210 akron1 589
	                INC(i)
590
	            END;
591
	            IF i <= n THEN
9659 akron1 592
	                IF Lines.getChar(line, i) = "." THEN
9210 akron1 593
	                    INC(i);
9659 akron1 594
	                    IF Lines.getChar(line, i) = "." THEN
9210 akron1 595
	                        DEC(i)
596
	                    END;
9659 akron1 597
	                    WHILE U.isDigit(Lines.getChar(line, i)) DO
9210 akron1 598
	                        INC(i)
599
	                    END;
9906 akron1 600
	                    IF upper(Lines.getChar(line, i)) = "E" THEN
9210 akron1 601
	                        INC(i);
9659 akron1 602
	                        IF (Lines.getChar(line, i) = "+") OR (Lines.getChar(line, i) = "-") THEN
9210 akron1 603
	                            INC(i)
604
	                        END;
9659 akron1 605
	                        WHILE U.isDigit(Lines.getChar(line, i)) DO
9210 akron1 606
	                            INC(i)
607
	                        END
608
	                    END
9906 akron1 609
	                ELSIF upper(Lines.getChar(line, i)) = "H" THEN
9210 akron1 610
	                    INC(i)
9906 akron1 611
	                ELSIF upper(Lines.getChar(line, i)) = "X" THEN
9210 akron1 612
	                    color := colors.string;
613
	                    INC(i)
614
	                END
615
	            END;
616
	            DEC(i);
617
	            PrintLex(text, line, k, i, y, color, backColor);
618
	            cond := 0
619
	        ELSIF (depth = 0) & (U.isLetter(c) OR (c = "_")) THEN
620
	            ident(text, i, i, y, line, backColor, Lang.isCS(lang));
621
	            cond := 0
622
	        ELSIF c = "(" THEN
623
	            cond := 1
624
	        ELSIF c = "*" THEN
625
	            IF cond = 1 THEN
626
	                INC(depth);
627
	                INC(i);
628
	                PrintComment(text, line, depth, i, 2, y, backColor);
629
	                cond := 0
630
	            ELSE
631
	                cond := 2
632
	            END
633
	        ELSIF c = ")" THEN
634
	            IF cond = 2 THEN
635
	                IF depth > 0 THEN
636
	                    DEC(depth)
637
	                END
638
	            END;
639
	            cond := 0
640
	        ELSE
641
	            cond := 0
642
	        END
8728 leency 643
 
644
        ELSIF lang = Lang.langLua THEN
645
 
9210 akron1 646
	        IF depth = 0 THEN
647
	            IF c = "-" THEN
648
	                IF cond = 1 THEN
649
	                    IF Lang.LuaLong(line, i + 1) >= 0 THEN
650
	                        depth := Lang.LuaLong(line, i + 1)*2 + 1;
651
	                        INC(i);
652
	                        PrintComment(text, line, depth, i, 2, y, backColor)
653
	                    ELSE
654
	                        PrintLex(text, line, i - 1, n, y, colors.comment, backColor);
655
	                        i := n
656
	                    END;
657
	                    cond := 0
658
	                ELSE
659
	                    cond := 1
660
	                END
661
	            ELSIF c = "[" THEN
662
	                cond := 0;
663
	                k := Lang.LuaLong(line, i);
664
	                IF k >= 0 THEN
665
	                    depth := (k + 1)*2;
666
	                    INC(i, 2);
667
	                    PrintComment(text, line, depth, i, 2, y, backColor);
668
	                    cond := 0
669
	                END
670
	            ELSIF (c = "'") OR (c = '"') THEN
671
	                String(text, line, i, y, backColor);
672
	                cond := 0
673
	            ELSIF U.isDigit(c) THEN
674
	                k := i;
9903 akron1 675
	                IF (c = "0") & (upper(Lines.getChar(line, i + 1)) = "X") THEN
9210 akron1 676
	                    isDgt := U.isHex;
677
	                    hex := TRUE;
678
	                    INC(i, 2)
679
	                ELSE
680
	                    isDgt := U.isDigit;
681
	                    hex := FALSE
682
	                END;
9903 akron1 683
	                WHILE isDgt(upper(Lines.getChar(line, i))) DO
9210 akron1 684
	                    INC(i)
685
	                END;
9659 akron1 686
	                IF Lines.getChar(line, i) = "." THEN
9210 akron1 687
	                    INC(i);
9659 akron1 688
	                    IF Lines.getChar(line, i) = "." THEN
9210 akron1 689
	                        DEC(i)
690
	                    END;
9903 akron1 691
	                    WHILE isDgt(upper(Lines.getChar(line, i))) DO
9210 akron1 692
	                        INC(i)
693
	                    END
694
	                END;
9903 akron1 695
	                IF (upper(Lines.getChar(line, i)) = "E") OR hex & (upper(Lines.getChar(line, i)) = "P") THEN
9210 akron1 696
	                    INC(i);
9659 akron1 697
	                    IF (Lines.getChar(line, i) = "-") OR (Lines.getChar(line, i) = "+") THEN
9210 akron1 698
	                        INC(i)
699
	                    END;
9903 akron1 700
	                    WHILE isDgt(upper(Lines.getChar(line, i))) DO
9210 akron1 701
	                        INC(i)
702
	                    END
703
	                END;
704
	                DEC(i);
705
	                PrintLex(text, line, k, i, y, colors.num, backColor);
706
	                cond := 0
707
	            ELSIF U.isLetter(c) OR (c = "_") THEN
708
	                ident(text, i, i, y, line, backColor, Lang.isCS(lang));
709
	                cond := 0
710
	            ELSE
711
	                cond := 0
712
	            END
8728 leency 713
 
9210 akron1 714
	        ELSIF depth > 0 THEN
715
	            IF (cond = 0) & (c = "]") THEN
716
	                cond := 1
717
	            ELSIF (cond >= 1) & (c = "=") THEN
718
	                INC(cond)
719
	            ELSIF (cond >= 1) & (c = "]") & (cond * 2 - depth MOD 2 = depth) THEN
720
	                depth := 0;
721
	                cond := 0
722
	            ELSE
723
	                cond := 0
724
	            END
725
	        END
8728 leency 726
 
727
        ELSIF lang = Lang.langPascal THEN
728
 
9210 akron1 729
	        IF depth = 0 THEN
730
	            IF c = "(" THEN
731
	                cond := 1
732
	            ELSIF (c = "*") & (cond = 1) THEN
733
	                depth := 2;
734
	                INC(i);
735
	                PrintComment(text, line, depth, i, 2, y, backColor);
736
	                cond := 0
737
	            ELSIF c = "/" THEN
738
	                IF cond = 2 THEN
739
	                    PrintLex(text, line, i - 1, n, y, colors.comment, backColor);
740
	                    cond := 0;
741
	                    i := n
742
	                ELSE
743
	                    cond := 2
744
	                END
745
	            ELSIF c = "'" THEN
746
	                String(text, line, i, y, backColor);
747
	                cond := 0
748
	            ELSIF c = "{" THEN
9659 akron1 749
	                IF Lines.getChar(line, i + 1) = "$" THEN
9210 akron1 750
	                    depth := 3
751
	                ELSE
752
	                    depth := 1
753
	                END;
754
	                INC(i);
755
	                PrintComment(text, line, depth, i, 1, y, backColor);
756
	                cond := 0
757
	            ELSIF c = "#" THEN
758
	                k := i;
759
	                INC(i);
9659 akron1 760
	                WHILE U.isDigit(Lines.getChar(line, i)) DO
9210 akron1 761
	                    INC(i)
762
	                END;
763
	                DEC(i);
764
	                PrintLex(text, line, k, i, y, colors.string, backColor);
765
	                cond := 0
766
	            ELSIF c = "$" THEN
9659 akron1 767
	                IF (i > 0 ) & (Lines.getChar(line, i - 1) = "#") THEN
9210 akron1 768
	                    color := colors.string
769
	                ELSE
770
	                    color := colors.num
771
	                END;
772
	                k := i;
773
	                INC(i);
9903 akron1 774
	                WHILE U.isHex(upper(Lines.getChar(line, i))) DO
9210 akron1 775
	                    INC(i)
776
	                END;
777
	                DEC(i);
778
	                PrintLex(text, line, k, i, y, color, backColor);
779
	                cond := 0
780
	            ELSIF U.isDigit(c) THEN
781
	                k := i;
9659 akron1 782
	                WHILE U.isDigit(Lines.getChar(line, i)) DO
9210 akron1 783
	                    INC(i)
784
	                END;
9659 akron1 785
	                IF Lines.getChar(line, i) = "." THEN
9210 akron1 786
	                    INC(i);
9659 akron1 787
	                    IF Lines.getChar(line, i) = "." THEN
9210 akron1 788
	                        DEC(i)
789
	                    END;
9659 akron1 790
	                    WHILE U.isDigit(Lines.getChar(line, i)) DO
9210 akron1 791
	                        INC(i)
792
	                    END;
9903 akron1 793
	                    IF upper(Lines.getChar(line, i)) = "E" THEN
9210 akron1 794
	                        INC(i);
9659 akron1 795
	                        IF (Lines.getChar(line, i) = "-") OR (Lines.getChar(line, i) = "+") THEN
9210 akron1 796
	                            INC(i)
797
	                        END;
9659 akron1 798
	                        WHILE U.isDigit(Lines.getChar(line, i)) DO
9210 akron1 799
	                            INC(i)
800
	                        END
801
	                    END
802
	                END;
803
	                DEC(i);
804
	                PrintLex(text, line, k, i, y, colors.num, backColor);
805
	                cond := 0
806
	            ELSIF (U.isLetter(c) OR (c = "_")) THEN
807
	                ident(text, i, i, y, line, backColor, Lang.isCS(lang));
808
	                cond := 0
809
	            ELSE
810
	                cond := 0
811
	            END
812
	        ELSIF depth IN {1, 3} THEN
813
	            IF c = "}" THEN
814
	                depth := 0
815
	            END
816
	        ELSIF depth = 2 THEN
817
	            IF c = "*" THEN
818
	                cond := 1
819
	            ELSIF (c = ")") & (cond = 1) THEN
820
	                depth := 0;
821
	                cond := 0
822
	            ELSE
823
	                cond := 0
824
	            END
825
	        END
8728 leency 826
 
827
        ELSIF lang = Lang.langIni THEN
828
 
9210 akron1 829
	        IF depth = 0 THEN
9674 akron1 830
	            IF ((c = ";") OR (c = "#")) & (leadingSpaces(line) = i) THEN
9210 akron1 831
	                PrintLex(text, line, i, n, y, colors.comment, backColor);
832
	                i := n
833
	            ELSIF c = '"' THEN
834
	                String(text, line, i, y, backColor)
835
	            ELSIF c = "[" THEN
836
	                depth := 1;
837
	                INC(i);
838
	                PrintComment(text, line, depth, i, 1, y, backColor)
839
	            ELSIF U.isDigit(c) THEN
840
	                k := i;
9659 akron1 841
	                WHILE U.isDigit(Lines.getChar(line, i)) DO
9210 akron1 842
	                    INC(i)
843
	                END;
844
	                DEC(i);
845
	                PrintLex(text, line, k, i, y, colors.num, backColor)
846
	            ELSIF (U.isLetter(c) OR (c = "_")) THEN
847
	                ident(text, i, i, y, line, backColor, Lang.isCS(lang))
848
	            END
849
	        ELSIF depth = 1 THEN
850
	            IF c = "]" THEN
851
	                depth := 0
852
	            END
853
	        END
8728 leency 854
 
855
        END;
856
        INC(i)
857
    END
858
END parse;
859
 
860
 
9907 akron1 861
PROCEDURE plain (text: tText; textStart, textEnd: tPoint; _copy: BOOLEAN): CB.tBuffer;
8728 leency 862
VAR
9907 akron1 863
	first, line: tLine;
864
	cnt, n: INTEGER;
865
	buffer: CB.tBuffer;
866
 
867
 
868
	PROCEDURE append (buffer: CB.tBuffer; line: tLine; first, last: INTEGER; _copy: BOOLEAN);
869
	BEGIN
870
		IF first <= last THEN
871
			CB.append(buffer, line, first, last)
872
		ELSE
873
			IF (U.OS = "KOS") & _copy THEN
874
				CB.appends(buffer, SPACE, 0, 0)
875
			END
876
		END
877
	END append;
878
 
879
 
8728 leency 880
BEGIN
9907 akron1 881
	first := getLine2(text, textStart.Y);
882
	line := first;
883
 
884
	n := textEnd.Y - textStart.Y;
885
	cnt := 0;
886
	WHILE n >= 0 DO
887
		INC(cnt, line.length + lenEOL);
888
		IF (U.OS = "KOS") & _copy & (line.length = 0) THEN
889
			INC(cnt)
890
		END;
891
		NextLine(line);
892
		DEC(n)
893
	END;
894
 
895
	buffer := CB.create(cnt + 2); (* +2 wchars EOT *)
896
 
897
	n := textEnd.Y - textStart.Y;
898
	line := first;
899
	IF n = 0 THEN
900
		append(buffer, line, textStart.X, textEnd.X - 1, _copy)
901
	ELSE
902
		append(buffer, line, textStart.X, line.length - 1, _copy);
903
		REPEAT
904
			DEC(n);
905
			CB.eol(buffer);
906
			NextLine(line);
907
			IF n > 0 THEN
908
				append(buffer, line, 0, line.length - 1, _copy)
909
			END
910
		UNTIL n = 0;
911
		append(buffer, line, 0, textEnd.X - 1, _copy)
912
	END
913
 
914
	RETURN buffer
8728 leency 915
END plain;
916
 
917
 
9909 akron1 918
PROCEDURE ClearSearch (text: tText);
919
VAR
920
	pos: List.tItem;
921
	line: tLine;
922
	cnt: INTEGER;
923
BEGIN
924
	cnt := -lenEOL;
925
	line := text.first(tLine);
926
	WHILE line # NIL DO
927
		INC(cnt, lenEOL);
928
		line.pos := cnt;
929
		INC(cnt, line.length);
930
		NextLine(line)
931
	END;
932
 
933
	WHILE text.foundList.count # 0 DO
934
		pos := List.pop(text.foundList);
935
		DISPOSE(pos)
936
	END
937
END ClearSearch;
938
 
939
 
9907 akron1 940
PROCEDURE _search (text: tText; s: ARRAY OF WCHAR; cs, whole: BOOLEAN; textStart, textEnd: tPoint): BOOLEAN;
8728 leency 941
VAR
9599 akron1 942
	res: BOOLEAN;
9907 akron1 943
	plainText, idxData: CB.tBuffer;
944
	first: tLine;
945
 
8728 leency 946
BEGIN
9599 akron1 947
	res := TRUE;
948
	plainText := NIL;
949
	idxData := NIL;
950
	text.whole := whole;
951
	text.cs := cs;
952
	text.searchText := s;
953
	IF ~cs THEN
9903 akron1 954
		U.lowcase(text.searchText)
9599 akron1 955
	END;
956
	IF text.searchText # "" THEN
9907 akron1 957
		first := getLine2(text, textStart.Y);
958
		plainText := plain(text, textStart, textEnd, FALSE);
959
		CB.appends(plainText, 0X, 0, 0);
960
		CB.appends(plainText, 0X, 0, 0);
9902 akron1 961
		idxData := Search.index(plainText, cs);
9907 akron1 962
		Search.find(plainText, text.searchText, whole, text.foundList, first.pos + textStart.X);
9599 akron1 963
		res := text.foundList.count > 0
9902 akron1 964
	ELSE
965
		Search.close
9599 akron1 966
	END;
967
	CB.destroy(plainText);
968
	CB.destroy(idxData);
969
	text.search := FALSE;
970
	text.foundSel := 0
971
	RETURN res
9907 akron1 972
END _search;
973
 
974
 
975
PROCEDURE search* (text: tText; s: ARRAY OF WCHAR; cs, whole: BOOLEAN): BOOLEAN;
976
VAR
977
	textStart, textEnd: tPoint;
978
BEGIN
979
	textStart.Y := 0; textStart.X := 0;
980
	textEnd.Y := text.count - 1; textEnd.X := text.last(tLine).length;
9909 akron1 981
	ClearSearch(text)
9907 akron1 982
	RETURN _search(text, s, cs, whole, textStart, textEnd)
8728 leency 983
END search;
984
 
985
 
9909 akron1 986
PROCEDURE fasm_anon (text: tText);
987
VAR
988
	textStart, textEnd: tPoint;
989
	res, frw, back, label, anon_label: BOOLEAN;
990
	Y1, Y2, i, k, j: INTEGER;
991
	line, Label: tLine;
992
	str: ARRAY 8 OF WCHAR;
993
 
994
 
995
	PROCEDURE anon (line: tLine): BOOLEAN;
996
	VAR
997
		i: INTEGER;
998
	BEGIN
999
		i := leadingSpaces(line)
1000
		RETURN (Lines.getChar(line, i) = "@") &
1001
				(Lines.getChar(line, i + 1) = "@") &
1002
				(Lines.getChar(line, i + 2) = ":")
1003
	END anon;
1004
 
1005
 
1006
BEGIN
1007
	frw := FALSE;
1008
	back := FALSE;
1009
	label := FALSE;
1010
	line := text.curLine;
1011
 
1012
	i := text.cursor.X;
1013
	j := 0;
1014
	FOR k := i - 3 TO i + 2 DO
1015
		str[j] := U.lcase(Lines.getChar(line, k));
1016
		INC(j)
1017
	END;
1018
	j := 3;
1019
 
1020
	anon_label := anon(line);
1021
 
1022
	IF str[j] = "@" THEN
1023
		IF str[j + 1] = "f" THEN
1024
			frw := TRUE
1025
		ELSIF (str[j + 1] = "b") OR (str[j + 1] = "r") THEN
1026
			back := TRUE
1027
		ELSIF anon_label & (((str[j + 1] = "@") & (str[j + 2] = ":")) OR
1028
				((str[j - 1] = "@") & (str[j + 1] = ":"))) THEN
1029
			label := TRUE
1030
		END
1031
	ELSIF str[j - 1] = "@" THEN
1032
		IF str[j] = "f" THEN
1033
			frw := TRUE
1034
		ELSIF (str[j] = "b") OR (str[j] = "r") THEN
1035
			back := TRUE
1036
		ELSIF anon_label & (str[j] = ":") & (str[j - 2] = "@") THEN
1037
			label := TRUE
1038
		END
1039
	ELSIF anon_label & (str[j] = ":") & (str[j - 1] = "@") & (str[j - 2] = "@") THEN
1040
		label := TRUE
1041
	ELSIF (str[j - 1] = "f") & (str[j - 2] = "@") THEN
1042
		frw := TRUE
1043
	ELSIF ((str[j - 1] = "b") OR (str[j - 1] = "r")) & (str[j - 2] = "@") THEN
1044
		back := TRUE
1045
	ELSIF anon_label & (str[j - 1] = ":") & (str[j - 2] = "@") & (str[j - 3] = "@") THEN
1046
		label := TRUE
1047
	END;
1048
 
1049
	IF back OR frw OR label THEN
1050
		Y1 := text.cursor.Y;
1051
		Y2 := Y1;
1052
 
1053
		IF label THEN
1054
			Label := line;
1055
			DEC(Y1)
1056
		ELSE
1057
			Label := NIL
1058
		END;
1059
 
1060
		line := getLine2(text, Y1);
1061
		WHILE (Y1 > 0) & ~anon(line) DO
1062
			PrevLine(line);
1063
			DEC(Y1)
1064
		END;
1065
 
1066
		line := getLine2(text, Y2);
1067
		IF anon(line) THEN
1068
			NextLine(line);
1069
			INC(Y2)
1070
		END;
1071
 
1072
		WHILE (Y2 < text.count) & ~anon(line) DO
1073
			NextLine(line);
1074
			INC(Y2)
1075
		END;
1076
 
1077
		IF Y1 < 0 THEN
1078
			Y1 := 0
1079
		ELSIF back THEN
1080
			Label := getLine2(text, Y1)
1081
		END;
1082
		textStart.Y := Y1; textStart.X := 0;
1083
		IF Y2 = text.count THEN
1084
			DEC(Y2);
1085
			textEnd.X := text.last(tLine).length
1086
		ELSIF frw THEN
1087
			Label := getLine2(text, Y2);
1088
			textEnd.X := 0
1089
		END;
1090
		textEnd.Y := Y2;
1091
		ClearSearch(text);
1092
		text.smallMove := FALSE;
1093
		IF (Label # NIL) & ~anon(Label) THEN
1094
			Label := NIL
1095
		END
1096
	END;
1097
 
1098
	IF frw THEN
1099
		res := _search(text, "@f", FALSE, FALSE, textStart, textEnd);
1100
		IF Label # NIL THEN
1101
			Search.add(text.foundList, Label.pos + leadingSpaces(Label))
1102
		END
1103
	ELSIF back THEN
1104
		IF Label # NIL THEN
1105
			Search.add(text.foundList, Label.pos + leadingSpaces(Label))
1106
		END;
1107
		res := _search(text, "@b", FALSE, FALSE, textStart, textEnd);
1108
		res := _search(text, "@r", FALSE, FALSE, textStart, textEnd)
1109
	ELSIF label THEN
1110
		res := _search(text, "@f", FALSE, FALSE, textStart, text.cursor^);
1111
		IF Label # NIL THEN
1112
			Search.add(text.foundList, Label.pos + leadingSpaces(Label))
1113
		END;
1114
		res := _search(text, "@b", FALSE, FALSE, text.cursor^, textEnd);
1115
		res := _search(text, "@r", FALSE, FALSE, text.cursor^, textEnd)
1116
	END
1117
END fasm_anon;
1118
 
1119
 
8728 leency 1120
PROCEDURE modify (text: tText);
1121
BEGIN
9907 akron1 1122
	text.modified := TRUE;
1123
	text.comments := TRUE;
1124
	text.search := TRUE;
1125
	text.guard := TRUE;
1126
	text.wordSel := TRUE
8728 leency 1127
END modify;
1128
 
1129
 
9336 akron1 1130
PROCEDURE setEnc* (text: tText; enc: INTEGER);
1131
BEGIN
1132
	IF text.enc # enc THEN
1133
		ChangeLog.changeInt(text.enc, enc);
1134
		text.enc := enc;
1135
		modify(text)
1136
	END
1137
END setEnc;
1138
 
1139
 
1140
PROCEDURE setEol* (text: tText; eol: INTEGER);
1141
BEGIN
1142
	IF text.eol # eol THEN
1143
		ChangeLog.changeInt(text.eol, eol);
1144
		text.eol := eol;
1145
		modify(text)
1146
	END
1147
END setEol;
1148
 
1149
 
1150
PROCEDURE getEnc* (text: tText): INTEGER;
1151
	RETURN text.enc
1152
END getEnc;
1153
 
1154
 
1155
PROCEDURE getEol* (text: tText): INTEGER;
1156
	RETURN text.eol
1157
END getEol;
1158
 
1159
 
8728 leency 1160
PROCEDURE DelLine (text: tText; line: tLine);
1161
BEGIN
9907 akron1 1162
	List._delete(text, line);
1163
	Lines.destroy(line);
1164
	modify(text)
8728 leency 1165
END DelLine;
1166
 
1167
 
1168
PROCEDURE setSelect (text: tText);
1169
BEGIN
9907 akron1 1170
	IF text.select = text.cursor THEN
1171
		text.select2^ := text.cursor^;
1172
		text.select := text.select2
1173
	END
8728 leency 1174
END setSelect;
1175
 
1176
 
1177
PROCEDURE resetSelect* (text: tText);
1178
BEGIN
9907 akron1 1179
	text.select := text.cursor
8728 leency 1180
END resetSelect;
1181
 
1182
 
1183
PROCEDURE getLine (text: tText; n: INTEGER): tLine;
1184
VAR
9668 akron1 1185
	item: List.tItem;
8728 leency 1186
BEGIN
9668 akron1 1187
	item := List.getItem(text, n)
1188
	RETURN item(tLine)
8728 leency 1189
END getLine;
1190
 
1191
 
1192
PROCEDURE SetPos* (text: tText; x, y: INTEGER);
1193
VAR
9174 akron1 1194
    deltaY, n, L, R: INTEGER;
8728 leency 1195
    cursor: pPoint;
9174 akron1 1196
    c: WCHAR;
8728 leency 1197
   (* trimLength: INTEGER; *)
1198
BEGIN
1199
    cursor := text.cursor;
1200
    y := MIN(MAX(y, 0), text.count - 1);
1201
    deltaY := y - cursor.Y;
1202
    IF deltaY # 0 THEN
1203
        cursor.Y := y;
1204
(*        trimLength := Lines.trimLength(text.curLine);
1205
        IF text.curLine.length # trimLength THEN
1206
            Lines.setChar(text.curLine, trimLength, 0X);
1207
            text.curLine.length := trimLength
1208
        END;*)
1209
        IF deltaY = 1 THEN
1210
            NextLine(text.curLine)
1211
        ELSIF deltaY = -1 THEN
1212
            PrevLine(text.curLine)
1213
        ELSE
1214
            text.curLine := getLine(text, y)
1215
        END
1216
    END;
1217
    cursor.X := MIN(MAX(x, 0), text.curLine.length);
9659 akron1 1218
    c := Lines.getChar(text.curLine, cursor.X);
9174 akron1 1219
    IF c = TAB1 THEN
1220
        n := cursor.X;
9659 akron1 1221
        WHILE Lines.getChar(text.curLine, n) = TAB1 DO
9174 akron1 1222
            INC(n)
1223
        END;
1224
        R := n - cursor.X;
1225
        n := cursor.X;
9659 akron1 1226
        WHILE Lines.getChar(text.curLine, n) # TAB DO
9174 akron1 1227
            DEC(n)
1228
        END;
1229
        L := cursor.X - n;
1230
        IF L < R THEN
1231
            DEC(cursor.X, L)
1232
        ELSE
1233
            INC(cursor.X, R)
1234
        END
1235
    END;
8728 leency 1236
    IF text.scroll.Y > cursor.Y THEN
1237
        text.scroll.Y := cursor.Y
1238
    ELSIF text.scroll.Y + textsize.Y <= cursor.Y THEN
1239
        text.scroll.Y := cursor.Y - textsize.Y + 1
1240
    END;
1241
    IF text.scroll.X > cursor.X THEN
1242
        text.scroll.X := cursor.X
1243
    ELSIF text.scroll.X + textsize.X <= cursor.X THEN
1244
        text.scroll.X := cursor.X - textsize.X + 1
1245
    END;
1246
    IF (text.select.Y = cursor.Y) & (text.select.X > text.curLine.length) THEN
1247
        text.select.X := text.curLine.length
1248
    END;
1249
    setSelect(text);
1250
    text.foundSel := 0;
1251
    ShowCursor;
9904 akron1 1252
    text.CurX := -1;
1253
    text.wordSel := TRUE
8728 leency 1254
END SetPos;
1255
 
1256
 
1257
PROCEDURE getSelect (text: tText; VAR selBeg, selEnd: tPoint);
1258
BEGIN
1259
    selBeg := text.cursor^;
1260
    selEnd := text.select^;
1261
    IF (selBeg.Y > selEnd.Y) OR (selBeg.Y = selEnd.Y) & (selBeg.X > selEnd.X) THEN
1262
        selBeg := text.select^;
1263
        selEnd := text.cursor^
1264
    END
1265
END getSelect;
1266
 
1267
 
1268
PROCEDURE selected* (text: tText): BOOLEAN;
1269
    RETURN (text.cursor.X # text.select.X) OR (text.cursor.Y # text.select.Y)
1270
END selected;
1271
 
1272
 
1273
PROCEDURE delSelect (text: tText);
1274
VAR
1275
    selBeg, selEnd: tPoint;
1276
    line, last, cur: tLine;
1277
BEGIN
1278
    getSelect(text, selBeg, selEnd);
1279
    IF (selBeg.Y = selEnd.Y) & (selBeg.X < selEnd.X) THEN
1280
        line := text.curLine;
1281
        Lines.delCharN(line, selBeg.X, selEnd.X - selBeg.X);
1282
        Lines.modify(line);
1283
        text.cursor^ := selBeg;
1284
        resetSelect(text);
1285
        SetPos(text, text.cursor.X, text.cursor.Y);
1286
        modify(text)
1287
    ELSIF selBeg.Y < selEnd.Y THEN
1288
        SetPos(text, selBeg.X, selBeg.Y);
1289
        line := text.curLine;
1290
        Lines.delCharN(line, selBeg.X, line.length - selBeg.X);
1291
        last := getLine(text, selEnd.Y);
1292
        Lines.delCharN(last, 0, selEnd.X);
1293
        cur := line.next(tLine);
1294
        WHILE cur # last DO
1295
            DelLine(text, cur);
1296
            cur := line.next(tLine)
1297
        END;
1298
        resetSelect(text);
1299
        SetPos(text, text.cursor.X, text.cursor.Y);
1300
        pdelete(text);
1301
        modify(text)
1302
    END;
1303
    resetSelect(text)
1304
END delSelect;
1305
 
1306
 
1307
PROCEDURE delete (text: tText);
1308
VAR
9174 akron1 1309
    i, n: INTEGER;
8728 leency 1310
    nextLine, curLine: tLine;
1311
BEGIN
1312
    IF selected(text) THEN
1313
        delSelect(text)
1314
    ELSE
1315
        i := text.cursor.X;
1316
        curLine := text.curLine;
1317
        IF i < curLine.length THEN
9174 akron1 1318
            n := i;
1319
            INC(i);
9659 akron1 1320
            IF Lines.getChar(curLine, i - 1) = TAB THEN
1321
                WHILE Lines.getChar(curLine, i) = TAB1 DO
9174 akron1 1322
                    INC(i)
1323
                END
1324
            END;
1325
            Lines.delCharN(curLine, n, i - n);
8728 leency 1326
            Lines.modify(curLine);
1327
            modify(text)
1328
        ELSE
1329
            nextLine := curLine.next(tLine);
1330
            IF nextLine # NIL THEN
9174 akron1 1331
                Lines.insert2(curLine, i, nextLine);
1332
                DelLine(text, nextLine);
8728 leency 1333
                Lines.modify(curLine);
9174 akron1 1334
                modify(text)
8728 leency 1335
            END
1336
        END
1337
    END;
1338
    setSelect(text)
1339
END delete;
1340
 
1341
 
9174 akron1 1342
PROCEDURE move (text: tText; d: INTEGER);
1343
VAR
1344
    pos: INTEGER;
1345
BEGIN
1346
    pos := text.cursor.X + d;
9659 akron1 1347
    WHILE Lines.getChar(text.curLine, pos) = TAB1 DO
9174 akron1 1348
        INC(pos, d)
1349
    END;
1350
    SetPos(text, pos, text.cursor.Y)
1351
END move;
1352
 
1353
 
8728 leency 1354
PROCEDURE BkSpace (text: tText);
1355
VAR
9174 akron1 1356
    i, k, n: INTEGER;
1357
    curLine, line, line2: tLine;
8728 leency 1358
BEGIN
1359
    IF selected(text) THEN
1360
        delSelect(text)
1361
    ELSE
1362
        resetSelect(text);
1363
        curLine := text.curLine;
9174 akron1 1364
        IF text.cursor.X > 0 THEN
9668 akron1 1365
        	INC(text.smallChange);
9174 akron1 1366
            i := text.cursor.X;
9671 akron1 1367
            IF autoIndents THEN
1368
	            n := leadingSpaces(curLine)
1369
            ELSE
1370
    	        n := 0
1371
            END;
9175 akron1 1372
            modify(text);
8728 leency 1373
            IF n < i THEN
9174 akron1 1374
                move(text, -1);
1375
                delete(text)
8728 leency 1376
            ELSE
1377
                n := i;
1378
                line := curLine.prev(tLine);
9174 akron1 1379
                line2 := line;
8728 leency 1380
                k := n;
1381
                WHILE (line # NIL) & (k >= n) DO
1382
                    IF Lines.trimLength(line) # 0 THEN
9174 akron1 1383
                        k := leadingSpaces(line);
1384
                        line2 := line;
8728 leency 1385
                    END;
1386
                    PrevLine(line)
1387
                END;
1388
                IF k >= n THEN
1389
                    k := 0
1390
                END;
9174 akron1 1391
                n := k;
1392
                Lines.delCharN(curLine, 0, i);
1393
                Lines.insert3(curLine, 0, k);
1394
                WHILE k > 0 DO
9659 akron1 1395
                    Lines.setChar(curLine, k - 1, Lines.getChar(line2, k - 1));
9174 akron1 1396
                    DEC(k)
1397
                END;
8728 leency 1398
                Lines.modify(curLine);
9174 akron1 1399
                SetPos(text, n, text.cursor.Y)
1400
            END
8728 leency 1401
        ELSE
1402
            PrevLine(curLine);
1403
            IF curLine # NIL THEN
1404
                SetPos(text, curLine.length, text.cursor.Y - 1);
1405
                delete(text)
1406
            END
1407
        END
1408
    END;
1409
    setSelect(text)
1410
END BkSpace;
1411
 
1412
 
1413
PROCEDURE enter (text: tText);
1414
VAR
1415
    n: INTEGER;
9174 akron1 1416
    curLine, newLine, line, line2: tLine;
8728 leency 1417
BEGIN
1418
    delSelect(text);
1419
    newLine := Lines.create(FALSE);
1420
    modify(text);
1421
    curLine := text.curLine;
1422
    IF text.cursor.X < curLine.length THEN
9174 akron1 1423
        Lines.wrap(curLine, newLine, text.cursor.X);
1424
        Lines.modify(curLine)
8728 leency 1425
    END;
1426
    List._insert(text, curLine, newLine);
1427
    SetPos(text, 0, text.cursor.Y + 1);
1428
    line := text.curLine.prev(tLine);
1429
    n := -1;
9671 akron1 1430
    WHILE (line # NIL) & (n = -1) & autoIndents DO
8728 leency 1431
        IF (*line.length*)Lines.trimLength(line) # 0 THEN
9174 akron1 1432
            n := leadingSpaces(line);
1433
            line2 := line
8728 leency 1434
        END;
1435
        PrevLine(line)
1436
    END;
1437
    IF n = -1 THEN
1438
        n := 0
1439
    END;
1440
    Lines.insert3(text.curLine, 0, n);
1441
    SetPos(text, n, text.cursor.Y);
1442
    resetSelect(text);
1443
    WHILE n > 0 DO
9659 akron1 1444
        Lines.setChar(text.curLine, n - 1, Lines.getChar(line2, n - 1));
8728 leency 1445
        DEC(n)
9174 akron1 1446
    END;
9835 akron1 1447
    Lines.modify(newLine);
1448
    SetPos(text, text.cursor.X, text.cursor.Y)
8728 leency 1449
END enter;
1450
 
1451
 
9174 akron1 1452
PROCEDURE incIndent (line: tLine);
1453
VAR
1454
	c: WCHAR;
1455
	i: INTEGER;
1456
BEGIN
1457
	Lines.modify(line);
1458
	Lines.insert3(line, 0, Lines.tab);
1459
	IF Lines.tabs THEN
1460
		c := TAB1
1461
	ELSE
1462
		c := SPACE
1463
	END;
1464
	i := Lines.tab - 1;
1465
	WHILE i >= 0 DO
1466
		Lines.setChar(line, i, c);
1467
		DEC(i)
1468
	END;
1469
	IF Lines.tabs THEN
1470
		Lines.setChar(line, 0, TAB)
1471
	END
1472
END incIndent;
1473
 
1474
 
1475
PROCEDURE decIndent (line: tLine): BOOLEAN;
1476
VAR
1477
	n: INTEGER;
1478
BEGIN
1479
	n := leadingSpaces(line);
1480
	IF n > 0 THEN
1481
		Lines.delCharN(line, 0, MIN(Lines.tab, n));
1482
		Lines.modify(line)
1483
	END
1484
	RETURN n > 0
1485
END decIndent;
1486
 
1487
 
1488
PROCEDURE Indent* (text: tText; incr: BOOLEAN);
1489
VAR
1490
    i: INTEGER;
1491
    line: tLine;
1492
    selBeg, selEnd: tPoint;
1493
    modified: BOOLEAN;
1494
BEGIN
1495
	getSelect(text, selBeg, selEnd);
1496
	i := selEnd.Y - selBeg.Y + 1;
9668 akron1 1497
	line := getLine2(text, selBeg.Y);
9174 akron1 1498
	modified := incr;
1499
	WHILE i > 0 DO
1500
		IF incr THEN
1501
			incIndent(line)
1502
		ELSE
1503
    		modified := decIndent(line) OR modified
1504
		END;
1505
		NextLine(line);
1506
		DEC(i)
1507
	END;
9668 akron1 1508
	line := getLine2(text, selEnd.Y);
9174 akron1 1509
	text.select^ := selBeg;
1510
	text.select.X := 0;
1511
	SetPos(text, line.length, selEnd.Y);
1512
	IF modified THEN
9668 akron1 1513
		INC(text.smallChange);
9174 akron1 1514
   		modify(text)
1515
	END
1516
END Indent;
1517
 
1518
 
8728 leency 1519
PROCEDURE input* (text: tText; code: INTEGER);
1520
VAR
1521
    curLine: tLine;
1522
 
9174 akron1 1523
 
8728 leency 1524
    PROCEDURE tab (text: tText);
1525
    VAR
1526
        i, x: INTEGER;
1527
        curLine: tLine;
9174 akron1 1528
        c: WCHAR;
8728 leency 1529
    BEGIN
9174 akron1 1530
		delSelect(text);
1531
		curLine := text.curLine;
1532
		x := text.cursor.X;
1533
		i := Lines.tab - x MOD Lines.tab;
1534
		Lines.insert3(curLine, x, i);
1535
		SetPos(text, x + i, text.cursor.Y);
1536
		IF Lines.tabs THEN
1537
			c := TAB1
1538
		ELSE
1539
			c := SPACE
1540
		END;
1541
		WHILE i > 0 DO
1542
			Lines.setChar(curLine, x + i - 1, c);
1543
			DEC(i)
1544
		END;
1545
		IF Lines.tabs THEN
1546
			Lines.setChar(curLine, x + i, TAB)
1547
		END;
1548
		Lines.modify(curLine);
1549
		modify(text)
8728 leency 1550
    END tab;
1551
 
9174 akron1 1552
 
8728 leency 1553
BEGIN
1554
    IF (code >= ORD(SPACE)) & (code # 127) THEN
9668 akron1 1555
    	IF ~selected(text) THEN
1556
    		INC(text.smallChange)
1557
    	END;
8728 leency 1558
        delSelect(text);
1559
        curLine := text.curLine;
1560
        Lines.insert(curLine, text.cursor.X, WCHR(code));
9671 akron1 1561
        IF autoBrackets THEN
1562
        	IF code = ORD("(") THEN
1563
        		code := ORD(")")
1564
        	ELSIF code = ORD("[") THEN
1565
        		code := ORD("]")
1566
        	ELSIF code = ORD("{") THEN
1567
        		code := ORD("}")
1568
        	ELSE
1569
        		code := -1
1570
        	END;
1571
        	IF code # -1 THEN
1572
        		Lines.insert(curLine, text.cursor.X + 1, WCHR(code))
1573
        	END
1574
        END;
8728 leency 1575
        Lines.modify(curLine);
1576
        modify(text);
1577
        SetPos(text, text.cursor.X + 1, text.cursor.Y)
1578
    ELSIF code = 8 THEN
9174 akron1 1579
		BkSpace(text)
1580
    ELSIF code = -8 THEN
1581
    	IF selected(text) THEN
1582
    		Indent(text, FALSE)
1583
        END
8728 leency 1584
    ELSIF code = 9 THEN
9174 akron1 1585
    	IF selected(text) THEN
1586
    		Indent(text, TRUE)
1587
    	ELSE
9668 akron1 1588
    		INC(text.smallChange);
9174 akron1 1589
	        tab(text)
1590
        END
8728 leency 1591
    ELSIF code = 13 THEN
1592
        enter(text)
1593
    END
1594
END input;
1595
 
1596
 
1597
PROCEDURE scroll* (text: tText; h, v: INTEGER);
1598
BEGIN
1599
    INC(text.scroll.X, h);
1600
    INC(text.scroll.Y, v);
9050 leency 1601
    text.scroll.X := MIN(MAX(text.scroll.X, 0), text.maxLength);
8728 leency 1602
    text.scroll.Y := MIN(MAX(text.scroll.Y, 0), text.count - 1)
1603
END scroll;
1604
 
1605
 
9180 akron1 1606
PROCEDURE save* (text: tText; name: RW.tFileName): BOOLEAN;
9073 leency 1607
CONST
1608
    tempFile = "/tmp0/1/cedit~.tmp";
8728 leency 1609
VAR
1610
    line: tLine;
1611
    file: RW.tOutput;
1612
    res: BOOLEAN;
9671 akron1 1613
    Len: INTEGER;
8728 leency 1614
BEGIN
9073 leency 1615
    ChangeLog.setGuard(text.edition);
9180 akron1 1616
    file := RW.create(tempFile, text.enc, text.eol);
8728 leency 1617
    IF file # NIL THEN
9073 leency 1618
        ChangeLog.delSaved;
8728 leency 1619
        line := text.first(tLine);
9522 akron1 1620
        WHILE line # NIL DO
9671 akron1 1621
        	IF trimSpace THEN
1622
        		Len := Lines.trimLength(line)
1623
        	ELSE
1624
        		Len := line.length
1625
        	END;
1626
            RW.putString(file, line, Len);
8728 leency 1627
            NextLine(line);
1628
            IF line # NIL THEN
9522 akron1 1629
                RW.newLine(file)
8728 leency 1630
            END
1631
        END;
9522 akron1 1632
        res := RW.close(file)
8728 leency 1633
    ELSE
1634
        res := FALSE
1635
    END;
9073 leency 1636
    IF res THEN
1637
        res := File.Copy(tempFile, name);
1638
        IF res THEN
1639
            text.modified := FALSE;
1640
            ChangeLog.save(text.edition);
9452 akron1 1641
 
1642
	        line := text.first(tLine);
1643
	        WHILE line # NIL DO
1644
	            IF line.modified THEN
1645
	                Lines.save(line)
1646
	            END;
1647
	            NextLine(line)
9522 akron1 1648
	        END
9073 leency 1649
        END
1650
    END;
9522 akron1 1651
    IF File.Delete(tempFile) THEN END;
9073 leency 1652
    IF ~res THEN
1653
        ChangeLog.delCurSaved
1654
    END
8728 leency 1655
    RETURN res
1656
END save;
1657
 
1658
 
1659
PROCEDURE redoGuard (text: tText; guard: tGuard);
1660
BEGIN
1661
    text.edition := guard;
1662
    text.cursor^ := guard.cursor;
1663
    text.select2^ := guard.select2;
1664
    text.scroll := guard.scroll;
1665
    text.CurX := guard.CurX;
1666
    IF guard.selected THEN
1667
        text.select := text.select2
1668
    ELSE
1669
        text.select := text.cursor
1670
    END;
1671
    text.curLine := getLine(text, text.cursor.Y);
1672
    text.comments := TRUE;
1673
    text.search := TRUE
1674
END redoGuard;
1675
 
1676
 
1677
PROCEDURE undo* (text: tText);
1678
VAR
1679
    item: List.tItem;
1680
    guard: tGuard;
1681
BEGIN
1682
    guard := text.edition;
1683
    item := guard.prev;
1684
    WHILE (item # NIL) & ~(item IS tGuard) DO
1685
        item := item.prev
1686
    END;
1687
 
1688
    IF item # NIL THEN
1689
        guard := item(tGuard);
9073 leency 1690
        text.edition := guard
8728 leency 1691
    END;
1692
 
9050 leency 1693
    item := ChangeLog.CL.Log.first;
8728 leency 1694
    WHILE item # guard DO
1695
        ChangeLog.redo(item);
1696
        item := item.next
1697
    END;
1698
    redoGuard(text, guard);
9073 leency 1699
    ChangeLog.setGuard(guard);
9174 akron1 1700
    text.modified := ~guard.saved;
1701
    ShowCursor
8728 leency 1702
END undo;
1703
 
1704
 
1705
PROCEDURE redo* (text: tText);
1706
VAR
1707
    item: List.tItem;
1708
    guard: tGuard;
1709
BEGIN
1710
    guard := text.edition;
1711
    item := guard.next;
1712
    WHILE (item # NIL) & ~(item IS tGuard) DO
1713
        ChangeLog.redo(item);
1714
        item := item.next
1715
    END;
1716
    IF item # NIL THEN
1717
        guard := item(tGuard);
1718
        redoGuard(text, guard)
1719
    END;
9073 leency 1720
    ChangeLog.setGuard(guard);
9174 akron1 1721
    text.modified := ~guard.saved;
1722
    ShowCursor
8728 leency 1723
END redo;
1724
 
1725
 
9462 akron1 1726
PROCEDURE getSelCnt* (text: tText; VAR chars, lines: INTEGER);
1727
VAR
1728
	selBeg, selEnd: tPoint;
1729
	first, last, line: tLine;
1730
 
1731
	PROCEDURE charCnt (line: tLine; first, last: INTEGER): INTEGER;
1732
	VAR
1733
		i, res: INTEGER;
1734
	BEGIN
1735
		res := 0;
1736
		FOR i := first TO last DO
9659 akron1 1737
			IF Lines.getChar(line, i) # TAB1 THEN
9462 akron1 1738
				INC(res)
1739
			END
1740
		END
1741
		RETURN res
1742
	END charCnt;
1743
 
1744
BEGIN
1745
	IF selected(text) THEN
1746
		getSelect(text, selBeg, selEnd);
9668 akron1 1747
		first := getLine2(text, selBeg.Y);
1748
		last  := getLine2(text, selEnd.Y);
9462 akron1 1749
		lines := selEnd.Y - selBeg.Y + 1;
1750
 
1751
		IF lines > 1 THEN
1752
			chars := charCnt(first, selBeg.X, first.length - 1) + charCnt(last, 0, selEnd.X - 1) + lenEOL;
9659 akron1 1753
			line := first.next(tLine);
1754
			WHILE line # last DO
1755
				INC(chars, charCnt(line, 0, line.length - 1) + lenEOL);
1756
				NextLine(line)
1757
			END
9462 akron1 1758
		ELSE
9659 akron1 1759
			chars := charCnt(first, selBeg.X, selEnd.X - 1)
9462 akron1 1760
		END
1761
	ELSE
1762
		chars := 0;
1763
		lines := 0
1764
	END
1765
END getSelCnt;
1766
 
1767
 
9907 akron1 1768
PROCEDURE Copy (text: tText);
8728 leency 1769
VAR
9907 akron1 1770
	selStart, selEnd: tPoint;
1771
	buffer: CB.tBuffer;
8728 leency 1772
BEGIN
9907 akron1 1773
	getSelect(text, selStart, selEnd);
1774
	buffer := plain(text, selStart, selEnd, TRUE);
8728 leency 1775
    CB.eot(buffer);
1776
    CB.put(buffer);
1777
    CB.destroy(buffer)
9907 akron1 1778
END Copy;
8728 leency 1779
 
1780
 
1781
PROCEDURE paste (text: tText);
1782
VAR
1783
    line, newLine, curLine: tLine;
9174 akron1 1784
    w: INTEGER;
8728 leency 1785
    cliptext: RW.tInput;
1786
    eol: BOOLEAN;
1787
    cursor: pPoint;
9174 akron1 1788
 
1789
 
1790
    PROCEDURE lineWidth (line: tLine; pos: INTEGER): INTEGER;
1791
    VAR
1792
    	i, res: INTEGER;
1793
    	c: WCHAR;
1794
    BEGIN
1795
    	res := pos;
1796
    	i := 0;
1797
    	REPEAT
9659 akron1 1798
	    	c := Lines.getChar(line, i);
9174 akron1 1799
	    	IF c = TAB THEN
1800
	    		INC(res, Lines.tab - res MOD Lines.tab)
1801
	    	ELSIF c # TAB1 THEN
1802
	    		INC(res)
1803
	    	END;
1804
	    	INC(i)
1805
    	UNTIL c = 0X
1806
    	RETURN res - pos - 1
1807
    END lineWidth;
1808
 
1809
 
8728 leency 1810
BEGIN
1811
    line := Lines.create(TRUE);
1812
    cliptext := RW.clipboard();
1813
    delSelect(text);
1814
    cursor := text.cursor;
9174 akron1 1815
    WHILE (cliptext # NIL) & (RW.getString(cliptext, line, Lines.tabs, eol) >= 0) DO
1816
        IF line.length > 0 THEN
1817
        	w := lineWidth(line, cursor.X);
8728 leency 1818
            Lines.insert2(text.curLine, cursor.X, line);
1819
            Lines.modify(text.curLine);
1820
            modify(text);
9174 akron1 1821
            SetPos(text, cursor.X + w, cursor.Y);
8728 leency 1822
            resetSelect(text)
1823
        END;
1824
        IF eol THEN
1825
            newLine := Lines.create(FALSE);
1826
            modify(text);
1827
            curLine := text.curLine;
1828
            IF cursor.X < curLine.length THEN
9174 akron1 1829
                Lines.wrap(curLine, newLine, cursor.X);
1830
                Lines.modify(curLine)
8728 leency 1831
            END;
1832
            List._insert(text, curLine, newLine);
9174 akron1 1833
            Lines.modify(newLine);
8728 leency 1834
            SetPos(text, 0, cursor.Y + 1);
1835
            resetSelect(text)
1836
        END;
1837
        Lines.destroy(line);
1838
        line := Lines.create(TRUE)
1839
    END;
9818 akron1 1840
    SetPos(text, cursor.X, cursor.Y);
8728 leency 1841
    Lines.destroy(line);
1842
    RW.destroy(cliptext)
1843
END paste;
1844
 
1845
 
1846
PROCEDURE searchScroll (text: tText; n: INTEGER);
1847
BEGIN
1848
    IF n - text.scroll.Y > textsize.Y - 1 THEN
1849
        text.scroll.Y := MAX(n - 2 * textsize.Y DIV 3, 0)
1850
    ELSIF n < text.scroll.Y THEN
1851
        text.scroll.Y := MAX(n - textsize.Y DIV 3, 0)
1852
    END
1853
END searchScroll;
1854
 
1855
 
1856
PROCEDURE goto* (text: tText; n: INTEGER): BOOLEAN;
1857
VAR
1858
    res: BOOLEAN;
1859
BEGIN
1860
    DEC(n);
1861
    IF (0 <= n) & (n < text.count) THEN
1862
        resetSelect(text);
1863
        searchScroll(text, n);
1864
        SetPos(text, 0, n);
1865
        res := TRUE
1866
    ELSE
1867
        res := FALSE
1868
    END
1869
    RETURN res
1870
END goto;
1871
 
1872
 
9060 leency 1873
PROCEDURE toggleLabel* (text: tText);
1874
BEGIN
1875
    text.curLine.label := ~text.curLine.label
1876
END toggleLabel;
1877
 
1878
 
1879
PROCEDURE gotoLabel* (text: tText; frw: BOOLEAN);
1880
VAR
1881
    line: tLine;
1882
    n: INTEGER;
9073 leency 1883
 
1884
    PROCEDURE search (VAR line: tLine; VAR n: INTEGER; frw: BOOLEAN);
1885
    BEGIN
1886
        IF frw THEN
1887
            WHILE (line # NIL) & ~line.label DO
1888
                NextLine(line);
1889
                INC(n)
1890
            END
1891
        ELSE
1892
            WHILE (line # NIL) & ~line.label DO
1893
                PrevLine(line);
1894
                DEC(n)
1895
            END
1896
        END
1897
    END search;
1898
 
9060 leency 1899
BEGIN
1900
    n := text.cursor.Y;
1901
    line := text.curLine;
1902
    IF frw THEN
9073 leency 1903
        NextLine(line);
1904
        INC(n)
9060 leency 1905
    ELSE
9073 leency 1906
        PrevLine(line);
1907
        DEC(n)
9060 leency 1908
    END;
9073 leency 1909
    search(line, n, frw);
1910
    IF line = NIL THEN
1911
        IF frw THEN
1912
            n := 0;
1913
            line := text.first(tLine)
1914
        ELSE
1915
            n := text.count - 1;
1916
            line := text.last(tLine)
1917
        END;
1918
        search(line, n, frw)
1919
    END;
9060 leency 1920
    IF line # NIL THEN
1921
        IF goto(text, n + 1) THEN END
1922
    END
1923
END gotoLabel;
1924
 
1925
 
8728 leency 1926
PROCEDURE changeCase (text: tText; upper: BOOLEAN);
1927
VAR
1928
    i: INTEGER;
1929
    line: tLine;
9674 akron1 1930
    func: Lines.fConvert;
8728 leency 1931
BEGIN
1932
    line := text.curLine;
1933
    i := text.cursor.X - 1;
1934
 
9659 akron1 1935
    WHILE (i >= 0) & U.isLetter(Lines.getChar(line, i)) DO
8728 leency 1936
        DEC(i)
1937
    END;
1938
 
9674 akron1 1939
    IF upper THEN
9903 akron1 1940
    	func := U.upper
9674 akron1 1941
    ELSE
9903 akron1 1942
    	func := U.lower
9674 akron1 1943
    END;
1944
 
1945
    IF Lines.convert(line, i + 1, text.cursor.X - 1, func) THEN
9668 akron1 1946
    	INC(text.smallChange);
8728 leency 1947
        modify(text)
1948
    END
1949
END changeCase;
1950
 
1951
 
1952
PROCEDURE chCase* (text: tText; upper: BOOLEAN);
1953
VAR
1954
    selBeg, selEnd: tPoint;
1955
    first, line: Lines.tLine;
1956
    cnt: INTEGER;
9674 akron1 1957
    func: Lines.fConvert;
8728 leency 1958
    modified: BOOLEAN;
1959
BEGIN
1960
    modified := FALSE;
1961
    IF selected(text) THEN
1962
        getSelect(text, selBeg, selEnd);
9668 akron1 1963
        first := getLine2(text, selBeg.Y);
8728 leency 1964
        line := first;
1965
        cnt := selEnd.Y - selBeg.Y;
9674 akron1 1966
 
1967
	    IF upper THEN
9903 akron1 1968
	    	func := U.upper
9674 akron1 1969
	    ELSE
9903 akron1 1970
	    	func := U.lower
9674 akron1 1971
	    END;
1972
 
8728 leency 1973
        IF cnt = 0 THEN
9674 akron1 1974
            IF Lines.convert(line, selBeg.X, selEnd.X - 1, func) THEN
8728 leency 1975
                modified := TRUE
1976
            END
1977
        ELSE
9674 akron1 1978
            IF Lines.convert(line, selBeg.X, line.length - 1, func) THEN
8728 leency 1979
                modified := TRUE
1980
            END;
1981
            WHILE cnt > 1 DO
1982
                NextLine(line);
9674 akron1 1983
                IF Lines.convert(line, 0, line.length - 1, func) THEN
8728 leency 1984
                    modified := TRUE
1985
                END;
1986
                DEC(cnt)
1987
            END;
1988
            NextLine(line);
9674 akron1 1989
            IF Lines.convert(line, 0, selEnd.X - 1, func) THEN
8728 leency 1990
                modified := TRUE
1991
            END
1992
        END
1993
    END;
1994
    IF modified THEN
9668 akron1 1995
    	INC(text.smallChange);
8728 leency 1996
        modify(text)
1997
    END
1998
END chCase;
1999
 
2000
 
2001
PROCEDURE UpDown (text: tText; step: INTEGER);
2002
VAR
2003
    temp: INTEGER;
2004
BEGIN
2005
    IF text.CurX = -1 THEN
2006
        text.CurX := text.cursor.X
2007
    END;
2008
    temp := text.CurX;
2009
    SetPos(text, temp, text.cursor.Y + step);
2010
    text.CurX := temp
2011
END UpDown;
2012
 
2013
 
2014
PROCEDURE delLine* (text: tText);
2015
BEGIN
9668 akron1 2016
	text.smallChange := 2;
8728 leency 2017
    resetSelect(text);
2018
    IF text.curLine.length > 0 THEN
2019
        Lines.delCharN(text.curLine, 0, text.curLine.length)
2020
    END;
2021
    SetPos(text, 0, text.cursor.Y);
2022
    IF text.cursor.Y = text.count - 1 THEN
2023
        BkSpace(text)
2024
    ELSE
2025
        delete(text)
2026
    END
2027
END delLine;
2028
 
2029
 
9174 akron1 2030
PROCEDURE dupLine* (text: tText);
9010 leency 2031
VAR
2032
    newLine, curLine: tLine;
2033
BEGIN
2034
    curLine := text.curLine;
2035
    newLine := Lines.create(FALSE);
2036
    modify(text);
2037
    Lines.insert3(newLine, 0, curLine.length);
2038
    List._insert(text, curLine, newLine);
9174 akron1 2039
    Lines.move(curLine, newLine);
2040
    Lines.modify(newLine)
9010 leency 2041
END dupLine;
2042
 
2043
 
9413 akron1 2044
PROCEDURE MoveLines* (text: tText; down: BOOLEAN);
2045
VAR
9560 akron1 2046
	last, first, line: tLine;
9413 akron1 2047
	selBeg, selEnd, temp: tPoint;
9560 akron1 2048
	step: INTEGER;
9413 akron1 2049
	frw: BOOLEAN;
2050
BEGIN
2051
	getSelect(text, selBeg, selEnd);
9560 akron1 2052
	IF ((selBeg.Y > 0) & ~down OR (selEnd.Y < text.count - 1) & down) THEN
2053
		modify(text);
2054
		step := ORD(down)*2 - 1;
2055
		IF selBeg.Y # selEnd.Y THEN
2056
			frw := (text.cursor.X = selEnd.X) & (text.cursor.Y = selEnd.Y);
2057
 
9413 akron1 2058
			IF down # frw THEN
2059
				temp := text.cursor^;
2060
				SetPos(text, 0, text.select.Y);
2061
				setSelect(text);
2062
				text.select^ := temp
2063
			END;
9560 akron1 2064
 
2065
			ASSERT(selBeg.Y < selEnd.Y);
2066
 
2067
			first := getLine(text, selBeg.Y);
9413 akron1 2068
			last := getLine(text, selEnd.Y);
9560 akron1 2069
 
2070
			line := first;
2071
			Lines.modify(line);
2072
			REPEAT
2073
				NextLine(line);
2074
				Lines.modify(line)
2075
			UNTIL line = last;
2076
 
2077
			IF down THEN
2078
				text.curLine := last.prev(tLine)
2079
			ELSE
2080
				text.curLine := first.next(tLine)
2081
			END;
9413 akron1 2082
			selBeg.X := 0;
2083
			selEnd.X := last.length;
9560 akron1 2084
			IF down THEN
2085
				last := last.next(tLine);
2086
				List._delete(text, last);
2087
				List._insert(text, first.prev, last)
2088
			ELSE
2089
				first := first.prev(tLine);
2090
				List._delete(text, first);
2091
				List._insert(text, last, first)
2092
			END;
2093
			IF down THEN
2094
				temp := selBeg;
2095
				selBeg := selEnd;
2096
				selEnd := temp;
2097
			END;
2098
			SetPos(text, selBeg.X, selBeg.Y + step);
2099
			setSelect(text);
2100
			text.select.X := selEnd.X;
2101
			text.select.Y := selEnd.Y + step
9413 akron1 2102
		ELSE
9560 akron1 2103
			first := getLine(text, selBeg.Y);
2104
			Lines.modify(first);
2105
			IF down THEN
2106
				last := first.next(tLine)
2107
			ELSE
2108
				last := first.prev.prev(tLine)
2109
			END;
2110
			List._delete(text, first);
2111
			List._insert(text, last, first);
2112
			INC(text.cursor.Y, step);
2113
			INC(text.select.Y, step);
2114
			SetPos(text, text.cursor.X, text.cursor.Y)
2115
		END
9413 akron1 2116
	END
2117
END MoveLines;
2118
 
2119
 
9197 akron1 2120
PROCEDURE getSelectedText* (text: tText; VAR s: ARRAY OF WCHAR);
2121
VAR
2122
    n: INTEGER;
2123
    selBeg, selEnd: tPoint;
2124
BEGIN
2125
	s[0] := 0X;
2126
    IF selected(text) & (text.cursor.Y = text.select.Y) THEN
2127
        getSelect(text, selBeg, selEnd);
2128
        n := getString(text.curLine, selBeg.X, selEnd.X - selBeg.X, s)
2129
    END
2130
END getSelectedText;
2131
 
2132
 
9010 leency 2133
PROCEDURE wordSel* (text: tText);
2134
VAR
2135
    n, i, x1, x2: INTEGER;
2136
    selBeg, selEnd: tPoint;
2137
    str: tString;
2138
    curLine: tLine;
2139
BEGIN
9904 akron1 2140
	IF text.wordSel THEN
2141
	    curLine := text.curLine;
2142
	    IF selected(text) & (text.cursor.Y = text.select.Y) THEN
2143
	        getSelect(text, selBeg, selEnd);
2144
	        x1 := selBeg.X;
2145
	        x2 := selEnd.X;
2146
	        n := getString(curLine, x1, x2 - x1, str);
2147
	    ELSE
2148
	        str := ""
2149
	    END;
2150
	    IF str # "" THEN
2151
	        i := 0;
9907 akron1 2152
	        WHILE (i < n) & U.isWordChar(str[i]) DO
9904 akron1 2153
	            INC(i)
2154
	        END;
2155
	        IF (i # n) OR
9907 akron1 2156
	            ((x1 > 0) & U.isWordChar(Lines.getChar(curLine, x1 - 1))) OR
2157
	            ((x2 < curLine.length) & U.isWordChar(Lines.getChar(curLine, x2))) THEN
9904 akron1 2158
	            str := ""
2159
	        END
2160
	    END;
2161
	    IF text.searchText # str THEN
2162
	    	text.smallMove := FALSE
2163
	    END;
2164
	    IF search(text, str, Lang.isCS(text.lang), TRUE) THEN END;
2165
	    text.wordSel := FALSE
9909 akron1 2166
    END;
2167
    IF (text.lang = Lang.langFasm) & ~selected(text) THEN
2168
    	fasm_anon(text)
9904 akron1 2169
    END
9010 leency 2170
END wordSel;
2171
 
2172
 
9336 akron1 2173
PROCEDURE getWordPos (line: tLine; pos: INTEGER): INTEGER;
2174
VAR
2175
	c: WCHAR;
2176
BEGIN
9659 akron1 2177
	c := Lines.getChar(line, pos);
9907 akron1 2178
	IF U.isWordChar(c) THEN
2179
		WHILE (pos < line.length) & U.isWordChar(Lines.getChar(line, pos)) DO
9336 akron1 2180
			INC(pos)
2181
		END
2182
	ELSIF Lines.isSpace(c) THEN
9659 akron1 2183
		WHILE (pos < line.length) & Lines.isSpace(Lines.getChar(line, pos)) DO
9336 akron1 2184
			INC(pos)
2185
		END
2186
	ELSE
9907 akron1 2187
		WHILE (pos < line.length) & ~Lines.isSpace(Lines.getChar(line, pos)) & ~U.isWordChar(Lines.getChar(line, pos)) DO
9336 akron1 2188
			INC(pos)
2189
		END
2190
	END
2191
	RETURN pos
2192
END getWordPos;
2193
 
2194
 
9073 leency 2195
PROCEDURE key* (text: tText; code: INTEGER; shift, ctrl: BOOLEAN);
9174 akron1 2196
VAR
9336 akron1 2197
	n, wPos: INTEGER;
9668 akron1 2198
	scrX, scrY: INTEGER;
2199
	resSel: BOOLEAN;
8728 leency 2200
BEGIN
9668 akron1 2201
	resSel := FALSE;
9073 leency 2202
    IF shift THEN
8728 leency 2203
        setSelect(text)
2204
    ELSE
2205
        IF (33 <= code) & (code <= 40) THEN
9413 akron1 2206
        	IF ~(((code = 38) OR (code = 40)) & ctrl) THEN
9668 akron1 2207
        		resSel := selected(text);
9413 akron1 2208
	            resetSelect(text)
2209
            END
8728 leency 2210
        END
2211
    END;
2212
 
2213
    CASE code OF
2214
    |33:
9073 leency 2215
        IF ctrl THEN
8728 leency 2216
            UpDown(text, text.scroll.Y - text.cursor.Y)
2217
        ELSE
2218
            text.scroll.Y := MAX(text.scroll.Y - textsize.Y, 0);
2219
            UpDown(text, -textsize.Y)
2220
        END
2221
    |34:
9073 leency 2222
        IF ctrl THEN
8728 leency 2223
            UpDown(text, MIN(text.scroll.Y + textsize.Y - 1, text.count - 1) - text.cursor.Y)
2224
        ELSE
2225
            text.scroll.Y := MIN(text.scroll.Y + textsize.Y, text.count - 1);
2226
            UpDown(text, textsize.Y)
2227
        END
2228
    |35:
9073 leency 2229
        IF ctrl THEN
8728 leency 2230
            SetPos(text, text.last(tLine).length, text.count - 1)
2231
        ELSE
2232
            SetPos(text, text.curLine.length, text.cursor.Y)
2233
        END
2234
    |36:
9073 leency 2235
        IF ctrl THEN
8728 leency 2236
            SetPos(text, 0, 0)
2237
        ELSE
9174 akron1 2238
        	n := leadingSpaces(text.curLine);
9659 akron1 2239
        	IF text.cursor.X <= n THEN
2240
	            n := 0
2241
        	END;
2242
        	SetPos(text, n, text.cursor.Y)
8728 leency 2243
        END
2244
    |37:
2245
        IF (text.cursor.X = 0) & (text.curLine.prev # NIL) THEN
2246
            SetPos(text, text.curLine.prev(tLine).length, text.cursor.Y - 1)
2247
        ELSE
9668 akron1 2248
        	scrX := text.scroll.X;
2249
        	scrY := text.scroll.Y;
9336 akron1 2250
        	IF ctrl THEN
2251
        		wPos := 0;
2252
        		REPEAT
2253
        			n := wPos;
2254
        			wPos := getWordPos(text.curLine, wPos)
2255
        		UNTIL wPos >= text.cursor.X;
2256
				move(text, n - text.cursor.X)
2257
        	ELSE
2258
            	move(text, -1)
9668 akron1 2259
            END;
2260
            text.smallMove := (scrX = text.scroll.X) & (scrY = text.scroll.Y) & ~resSel
8728 leency 2261
        END
2262
    |38:
9073 leency 2263
        IF ctrl THEN
9413 akron1 2264
            MoveLines(text, FALSE)
9010 leency 2265
        ELSE
2266
            UpDown(text, -1)
2267
        END
8728 leency 2268
    |39:
2269
        IF (text.cursor.X = text.curLine.length) & (text.curLine.next # NIL) THEN
2270
            SetPos(text, 0, text.cursor.Y + 1)
2271
        ELSE
9668 akron1 2272
        	scrX := text.scroll.X;
2273
        	scrY := text.scroll.Y;
9336 akron1 2274
        	IF ctrl THEN
2275
				move(text, getWordPos(text.curLine, text.cursor.X) - text.cursor.X)
2276
        	ELSE
2277
            	move(text, 1)
9668 akron1 2278
        	END;
2279
        	text.smallMove := (scrX = text.scroll.X) & (scrY = text.scroll.Y) & ~resSel
8728 leency 2280
        END
2281
    |40:
9073 leency 2282
        IF ctrl THEN
9413 akron1 2283
            MoveLines(text, TRUE)
9010 leency 2284
        ELSE
2285
            UpDown(text, 1)
2286
        END
2287
    |46:
9073 leency 2288
        IF ctrl THEN
9010 leency 2289
            delLine(text)
2290
        ELSE
9668 akron1 2291
        	IF ~selected(text) & (text.cursor.X < text.curLine.length) THEN
2292
        		INC(text.smallChange)
2293
        	END;
9174 akron1 2294
            delete(text);
2295
            ShowCursor
9010 leency 2296
        END
9659 akron1 2297
    |ORD("C"), ORD("X"):
9073 leency 2298
        IF ctrl THEN
8728 leency 2299
            IF selected(text) THEN
9907 akron1 2300
                Copy(text);
9659 akron1 2301
                IF code = ORD("X") THEN
2302
                	delSelect(text)
2303
                END
8728 leency 2304
            END
2305
        END
2306
    |ORD("V"):
9073 leency 2307
        IF ctrl THEN
8728 leency 2308
            IF CB.available() THEN
2309
                paste(text)
2310
            END
2311
        END
2312
    |ORD("A"):
9073 leency 2313
        IF ctrl THEN
8728 leency 2314
            text.select2.X := 0;
2315
            text.select2.Y := 0;
2316
            text.select := text.select2;
2317
            SetPos(text, text.last(tLine).length, text.count - 1)
2318
        END
2319
    |ORD("L"), ORD("U"):
9073 leency 2320
        IF ctrl THEN
9174 akron1 2321
        	IF selected(text) THEN
2322
            	chCase(text, code = ORD("U"))
2323
            ELSE
2324
            	changeCase(text, code = ORD("U"))
2325
            END;
2326
            ShowCursor
8728 leency 2327
        END
9010 leency 2328
    |ORD("D"):
9073 leency 2329
        IF ctrl THEN
9010 leency 2330
            dupLine(text)
2331
        END
8728 leency 2332
    ELSE
2333
    END
2334
END key;
2335
 
2336
 
2337
PROCEDURE mouse* (text: tText; x, y: INTEGER);
2338
VAR
2339
    cursorX: INTEGER;
2340
BEGIN
2341
    DEC(x, padding.left);
2342
    DEC(y, padding.top);
2343
    cursorX := (x*2) DIV charWidth;
2344
    SetPos(text, cursorX DIV 2 + cursorX MOD 2 + text.scroll.X, y DIV charHeight + text.scroll.Y)
2345
END mouse;
2346
 
2347
 
2348
PROCEDURE selectWord* (text: tText);
2349
VAR
2350
    cursorX, x1, x2: INTEGER;
2351
    line: tLine;
2352
BEGIN
2353
    resetSelect(text);
2354
    cursorX := text.cursor.X;
2355
    line := text.curLine;
2356
    x1 := cursorX - 1;
9907 akron1 2357
    IF (cursorX < line.length) & U.isWordChar(Lines.getChar(line, cursorX)) THEN
8728 leency 2358
        x2 := cursorX;
9907 akron1 2359
        WHILE (x2 < line.length) & U.isWordChar(Lines.getChar(line, x2)) DO
8728 leency 2360
            INC(x2)
2361
        END
2362
    ELSE
9907 akron1 2363
        WHILE (x1 >= 0) & ~U.isWordChar(Lines.getChar(line, x1)) DO
8728 leency 2364
            DEC(x1)
2365
        END;
2366
        x2 := x1 + 1
2367
    END;
9907 akron1 2368
    WHILE (x1 >= 0) & U.isWordChar(Lines.getChar(line, x1)) DO
8728 leency 2369
        DEC(x1)
2370
    END;
2371
    INC(x1);
2372
    IF x1 < x2 THEN
2373
        SetPos(text, x1, text.cursor.Y);
2374
        setSelect(text);
2375
        SetPos(text, x2, text.cursor.Y)
2376
    END
2377
END selectWord;
2378
 
2379
 
9668 akron1 2380
PROCEDURE cursor* (text: tText);
8728 leency 2381
VAR
9295 akron1 2382
    x, y1, y2, scrollX, scrollY: INTEGER;
8728 leency 2383
    cursor: pPoint;
2384
BEGIN
9668 akron1 2385
	IF drawCursor THEN
2386
	    cursor := text.cursor;
2387
	    scrollX := text.scroll.X;
2388
	    scrollY := text.scroll.Y;
9892 akron1 2389
	    IF ~((scrollY > cursor.Y) OR (scrollY + textsize.Y + 1 <= cursor.Y) OR
9668 akron1 2390
	       (scrollX > cursor.X) OR (scrollX + textsize.X <= cursor.X)) THEN
2391
	        x := (cursor.X - scrollX)*charWidth + padding.left;
9915 akron1 2392
	        y1 := (cursor.Y - scrollY)*charHeight + padding.top + (LineSpacing DIV 2 + 1);
2393
	        y2 := y1 + charHeight - (LineSpacing + 2);
9668 akron1 2394
	        G.notVLine(canvas, x, y1, y2);
2395
	        G.notVLine(canvas, x - 1, y1, y2)
2396
	    END
8728 leency 2397
    END
2398
END cursor;
2399
 
2400
 
2401
PROCEDURE drawSelect (text: tText; line: tLine; selBeg, selEnd, y: INTEGER);
2402
VAR
9915 akron1 2403
	Len, pos, x, firstCharIdx: INTEGER;
8728 leency 2404
BEGIN
9915 akron1 2405
	firstCharIdx := MAX(text.scroll.X, selBeg);
2406
	Len := MAX(MIN(line.length - firstCharIdx, selEnd - firstCharIdx), 0);
2407
	Len := MIN(Len, textsize.X - pos + 1);
2408
	SetColor(colors.seltext, colors.selback);
2409
	pos := MAX((selBeg - text.scroll.X), 0);
2410
	x := pos*charWidth + padding.left;
2411
	G.SetColor(canvas, colors.selback);
2412
	G.FillRect(canvas, x - 1, y - LineSpacing DIV 2,
2413
		x + Len*charWidth, y - LineSpacing DIV 2 + charHeight);
2414
	G.TextOut(canvas, pos*charWidth + padding.left, y, Lines.getPChar(line, firstCharIdx), Len, colors.seltext)
8728 leency 2415
END drawSelect;
2416
 
2417
 
2418
PROCEDURE mark (line: tLine; y: INTEGER);
2419
VAR
2420
    color, i: INTEGER;
2421
BEGIN
2422
    IF line.modified THEN
2423
        color := colors.modified
2424
    ELSIF line.saved THEN
2425
        color := colors.saved
2426
    ELSE
2427
        color := colors.back
2428
    END;
2429
    G.SetColor(canvas, color);
2430
 
2431
    FOR i := 3 TO mark_width + 2 DO
2432
        G.VLine(canvas, padding.left - i, y, y + charHeight)
2433
    END
2434
END mark;
2435
 
2436
 
2437
PROCEDURE setPadding (left, top: INTEGER);
2438
BEGIN
2439
    padding.left := left;
2440
    padding.top := top;
2441
    textsize.X := (size.X - padding.left) DIV charWidth;
2442
    textsize.Y := (size.Y - padding.top) DIV charHeight;
2443
END setPadding;
2444
 
2445
 
2446
PROCEDURE draw* (text: tText);
2447
VAR
9903 akron1 2448
    y, n, cnt, i, x, pos: INTEGER;
8728 leency 2449
    line, firstLine, lastLine: tLine;
2450
    selBeg, selEnd: tPoint;
2451
    s: ARRAY 12 OF WCHAR;
2452
    backColor, numWidth, xNum, wNum: INTEGER;
9903 akron1 2453
    guard: tGuard;
8728 leency 2454
    p: Search.tPos;
2455
BEGIN
9668 akron1 2456
    IF text.comments THEN
8728 leency 2457
        Comments(text)
2458
    END;
9668 akron1 2459
    IF text.search & search(text, text.searchText, text.cs, text.whole) THEN END;
8728 leency 2460
    IF text.guard THEN
2461
        NEW(guard);
9050 leency 2462
        List.append(ChangeLog.CL.Log, guard);
9073 leency 2463
        guard.saved := ChangeLog.isFirstGuard(guard);
8728 leency 2464
        text.edition := guard;
9073 leency 2465
        text.guard := FALSE
8728 leency 2466
    ELSE
2467
        guard := text.edition
2468
    END;
2469
 
2470
    guard.cursor := text.cursor^;
2471
    guard.select2 := text.select2^;
2472
    guard.scroll := text.scroll;
2473
    guard.CurX := text.CurX;
2474
    guard.selected := text.select = text.select2;
2475
 
2476
    G.SetColor(canvas, colors.back);
9668 akron1 2477
    IF ~text.smallMove THEN
2478
    	G.clear(canvas)
2479
    END;
9060 leency 2480
    wNum := charWidth;
9671 akron1 2481
    IF lineNumbers THEN
8728 leency 2482
        numWidth := U.lg10(text.count) + 2;
2483
        xNum := numWidth*wNum - wNum DIV 2;
2484
        setPadding(numWidth*wNum + pad_left, padding.top);
2485
    ELSE
9060 leency 2486
        setPadding(pad_left + wNum*2, padding.top)
8728 leency 2487
    END;
2488
    getSelect(text, selBeg, selEnd);
9915 akron1 2489
    y := padding.top + LineSpacing DIV 2;
8728 leency 2490
    n := text.scroll.Y;
9668 akron1 2491
    firstLine := getLine2(text, n);
9892 akron1 2492
 
9668 akron1 2493
    IF text.smallMove THEN
2494
    	line := text.curLine;
9892 akron1 2495
    	cnt := textsize.Y;
9668 akron1 2496
    	y := y + charHeight*(text.cursor.Y - text.scroll.Y);
2497
    	G.SetColor(canvas, colors.back);
9915 akron1 2498
    	G.FillRect(canvas, padding.left - 2, y - LineSpacing DIV 2,
2499
    		size.X - 1, y - LineSpacing DIV 2 + charHeight);
9668 akron1 2500
    	n := text.cursor.Y
2501
    ELSE
2502
	    line := firstLine;
2503
    	cnt := 0
2504
    END;
2505
 
9892 akron1 2506
    WHILE (line # NIL) & (cnt <= textsize.Y) DO
8728 leency 2507
        backColor := colors.back;
2508
        IF (line = text.curLine) & ~selected(text) THEN
2509
            G.SetColor(canvas, colors.curline);
9915 akron1 2510
            G.FillRect(canvas, padding.left - 2, y - LineSpacing DIV 2,
2511
            	size.X - 1, y - LineSpacing DIV 2 + charHeight);
8728 leency 2512
            backColor := colors.curline
2513
        END;
2514
        SetColor(colors.text, backColor);
9668 akron1 2515
		IF (selBeg.Y < n) & (n < selEnd.Y) THEN
2516
			drawSelect(text, line, 0, line.length, y)
2517
		ELSE
2518
			G.TextOut(canvas, padding.left, y, Lines.getPChar(line, text.scroll.X), MIN(MAX(line.length - text.scroll.X, 0), textsize.X + 1), colors.delim);
2519
			IF text.lang # Lang.langText THEN
2520
				parse(text, line, y, backColor, text.lang)
2521
			END
2522
		END;
2523
		IF (selBeg.Y = n) & (selEnd.Y = n) & (selBeg.X # selEnd.X) THEN
8728 leency 2524
            drawSelect(text, line, selBeg.X, selEnd.X, y)
2525
        ELSIF (selBeg.Y = n) & (selEnd.Y # n) THEN
2526
            drawSelect(text, line, selBeg.X, line.length, y)
2527
        ELSIF (selBeg.Y # n) & (selEnd.Y = n) THEN
2528
            drawSelect(text, line, 0, selEnd.X, y)
2529
        END;
9915 akron1 2530
        mark(line, y - LineSpacing DIV 2);
8728 leency 2531
        NextLine(line);
2532
        INC(y, charHeight);
2533
        INC(n);
2534
        INC(cnt)
2535
    END;
9668 akron1 2536
 
9060 leency 2537
    G.SetColor(canvas, colors.numback);
2538
    G.FillRect(canvas, 0, 0, padding.left - pad_left (*+ 1*), size.Y - 1);
2539
    line := firstLine;
2540
    SetColor(colors.numtext, colors.numback);
9915 akron1 2541
    y := padding.top + LineSpacing DIV 2;
9892 akron1 2542
    n := MIN(text.scroll.Y + textsize.Y + 1, text.count);
9060 leency 2543
    FOR i := text.scroll.Y + 1 TO n DO
9671 akron1 2544
        IF lineNumbers THEN
9060 leency 2545
            IF (i MOD 10 = 0) OR (i - 1 = text.cursor.Y) OR line.label THEN
8728 leency 2546
                U.int2str(i, s);
9060 leency 2547
                G.TextOut2(canvas, (numWidth - U.lg10(i) - 1)*wNum - wNum DIV 2, y, s, LENGTH(s))
8728 leency 2548
            ELSE
2549
                G.SetColor(canvas, colors.numtext);
9915 akron1 2550
                G.HLine(canvas, y - LineSpacing DIV 2 + charHeight DIV 2,
2551
                	xNum - wNum DIV (1 + ORD(i MOD 5 # 0)), xNum)
9060 leency 2552
            END
2553
        END;
2554
        IF line.label THEN
2555
            FOR x := wNum DIV 2 TO (padding.left - pad_left) - wNum DIV 2 DO
9915 akron1 2556
                G.notVLine(canvas, x, y, y + charHeight - (LineSpacing + 1));
2557
                G.xorVLine(canvas, x, y, y + charHeight - (LineSpacing + 1))
9060 leency 2558
            END
2559
        END;
2560
        NextLine(line);
2561
        INC(y, charHeight)
8728 leency 2562
    END;
2563
 
2564
    IF text.searchText # "" THEN
9668 akron1 2565
    	IF text.smallMove THEN
2566
    		firstLine := text.curLine;
2567
    		lastLine := firstLine
2568
    	ELSE
9892 akron1 2569
    	    lastLine := getLine2(text, MIN(text.scroll.Y + textsize.Y + 1, text.count) - 1)
8728 leency 2570
        END;
9903 akron1 2571
 
2572
        i := 0;
8728 leency 2573
        p := text.foundList.first(Search.tPos);
9903 akron1 2574
        pos := Search.next(p, i);
2575
        WHILE pos # -1 DO
9915 akron1 2576
        	y := padding.top + LineSpacing DIV 2;
9668 akron1 2577
        	IF text.smallMove THEN
2578
        		y := y + charHeight*(text.cursor.Y - text.scroll.Y)
2579
            END;
9903 akron1 2580
            IF (firstLine.pos <= pos) & (pos <= lastLine.pos + lastLine.length) THEN
8728 leency 2581
                line := firstLine;
9903 akron1 2582
                WHILE (line.pos <= pos) & (line # lastLine) DO
8728 leency 2583
                    NextLine(line);
2584
                    INC(y, charHeight)
2585
                END;
9903 akron1 2586
                IF (line # lastLine) & (line # firstLine) OR (line = lastLine) & (line.pos > pos) THEN
8728 leency 2587
                    PrevLine(line);
2588
                    DEC(y, charHeight)
2589
                END;
9903 akron1 2590
                x := (pos - line.pos - text.scroll.X)*charWidth + padding.left;
8728 leency 2591
                n := LENGTH(text.searchText)*charWidth;
2592
                WHILE n > 0 DO
2593
                    IF x >= padding.left THEN
9915 akron1 2594
                        G.notVLine(canvas, x, y, y + charHeight - LineSpacing)
8728 leency 2595
                    END;
2596
                    INC(x);
2597
                    DEC(n)
9668 akron1 2598
                END
8728 leency 2599
            END;
9903 akron1 2600
            pos := Search.next(p, i)
8728 leency 2601
        END
2602
    END;
2603
 
9668 akron1 2604
    text.smallMove := FALSE;
2605
 
8728 leency 2606
    IF text.foundSel > 0 THEN
2607
        x := (text.cursor.X - text.scroll.X)*charWidth + padding.left;
9915 akron1 2608
        y := (text.cursor.Y - text.scroll.Y)*charHeight + padding.top + LineSpacing DIV 2;
8728 leency 2609
        n := text.foundSel*charWidth;
2610
        WHILE n > 0 DO
2611
            IF x >= padding.left THEN
9915 akron1 2612
                G.xorVLine(canvas, x, y, y + charHeight - LineSpacing)
8728 leency 2613
            END;
2614
            INC(x);
2615
            DEC(n)
2616
        END
2617
    END;
9668 akron1 2618
	cursor(text)
8728 leency 2619
END draw;
2620
 
2621
 
9050 leency 2622
PROCEDURE switch* (text: tText);
2623
BEGIN
9902 akron1 2624
    ChangeLog.setLog(text.chLog);
9194 akron1 2625
    Lines.setMaxLength(text.maxLength);
2626
    Lang.setCurLang(text.lang)
9050 leency 2627
END switch;
2628
 
2629
 
8728 leency 2630
PROCEDURE create (fileName: RW.tFileName): tText;
2631
VAR
2632
    text: tText;
2633
BEGIN
2634
    NEW(text);
9050 leency 2635
    text.maxLength := 64;
2636
    text.chLog := ChangeLog.create(text.maxLength);
8728 leency 2637
    NEW(text.cursor);
2638
    NEW(text.select2);
2639
    text.cursor.X := 0;
2640
    text.cursor.Y := 0;
2641
    resetSelect(text);
2642
    text.scroll.X := 0;
2643
    text.scroll.Y := 0;
2644
    setPadding(padding.left, padding.top);
2645
    text.curLine := NIL;
2646
    text.modified := FALSE;
9668 akron1 2647
    text.smallMove := FALSE;
8728 leency 2648
    text.comments := TRUE;
2649
    text.search := TRUE;
2650
    text.cs := FALSE;
2651
    text.whole := FALSE;
2652
    text.guard := TRUE;
9904 akron1 2653
    text.wordSel := FALSE;
8728 leency 2654
    text.edition := NIL;
2655
    text.foundList := List.create(NIL);
2656
    text.searchText := "";
2657
    text.foundSel := 0;
2658
    text.CurX := -1;
9668 akron1 2659
    text.smallChange := 0;
9193 akron1 2660
    text.lang := Lang.langText;
9668 akron1 2661
    text.LinesVector := NIL;
9193 akron1 2662
    Lang.setCurLang(Lang.langText);
8728 leency 2663
    setName(text, fileName);
2664
    ASSERT(text = List.create(text))
2665
    RETURN text
2666
END create;
2667
 
2668
 
2669
PROCEDURE setColors* (text, back, seltext, selback, modified, saved, curline, numtext, numback,
9413 akron1 2670
                        comment, string, escape, num, delim, key1, key2, key3: INTEGER);
8728 leency 2671
BEGIN
2672
    colors.text := text;
2673
    colors.back := back;
2674
    colors.seltext := seltext;
2675
    colors.selback := selback;
2676
    colors.modified := modified;
2677
    colors.saved := saved;
2678
    colors.curline := curline;
2679
    colors.numtext := numtext;
2680
    colors.numback := numback;
2681
    colors.comment := comment;
2682
    colors.string  := string;
9413 akron1 2683
    colors.escape  := escape;
8728 leency 2684
    colors.num := num;
2685
    colors.delim := delim;
2686
    colors.key1 := key1;
2687
    colors.key2 := key2;
2688
    colors.key3 := key3;
2689
END setColors;
2690
 
2691
 
9659 akron1 2692
PROCEDURE setCanvas* (_canvas: G.tCanvas);
8728 leency 2693
BEGIN
9659 akron1 2694
    canvas := _canvas;
2695
    charWidth := _canvas.font.width;
9915 akron1 2696
    charHeight := _canvas.font.height + LineSpacing
8728 leency 2697
END setCanvas;
2698
 
2699
 
2700
PROCEDURE resize* (width, height: INTEGER);
2701
BEGIN
2702
    size.X := width;
2703
    size.Y := height;
2704
    setPadding(padding.left, padding.top)
2705
END resize;
2706
 
2707
 
2708
PROCEDURE destroy* (VAR text: tText);
2709
BEGIN
2710
    IF search(text, "", FALSE, FALSE) THEN END;
9448 akron1 2711
    ChangeLog.destroy(text.chLog);
9668 akron1 2712
    Lines.destroyVector(text.LinesVector);
8728 leency 2713
    DISPOSE(text.foundList);
2714
    DISPOSE(text.cursor);
2715
    DISPOSE(text.select2);
2716
    DISPOSE(text)
2717
END destroy;
2718
 
2719
 
9674 akron1 2720
PROCEDURE open* (name: RW.tFileName; ptr, size: INTEGER; VAR errno: INTEGER): tText;
8728 leency 2721
VAR
2722
    text: tText;
2723
    file: RW.tInput;
9180 akron1 2724
    n, enc, eol: INTEGER;
2725
    _eol: BOOLEAN;
8728 leency 2726
    line: tLine;
2727
BEGIN
2728
    errno := 0;
9522 akron1 2729
    text := create(name);
2730
    IF text # NIL THEN
9674 akron1 2731
    	IF ptr = 0 THEN
2732
    		file := RW.loadFromFile(name, enc, eol)
2733
    	ELSE
2734
    		file := RW.loadFromMem(ptr, size, enc, eol)
2735
    	END;
9522 akron1 2736
    	IF file = NIL THEN
2737
    		destroy(text)
2738
    	END
2739
    ELSE
2740
    	file := NIL
2741
    END;
8728 leency 2742
    IF file # NIL THEN
9336 akron1 2743
        ChangeLog.changeInt(text.enc, enc);
2744
        ChangeLog.changeInt(text.eol, eol);
8728 leency 2745
        text.enc := enc;
9180 akron1 2746
        text.eol := eol;
2747
        line := Lines.create(FALSE);
2748
        List._append(text, line);
8728 leency 2749
        REPEAT
9180 akron1 2750
            n := RW.getString(file, line, Lines.tabs, _eol);
2751
            IF _eol THEN
2752
            	line := Lines.create(FALSE);
2753
            	List._append(text, line)
8728 leency 2754
            END
9180 akron1 2755
        UNTIL ~_eol;
8728 leency 2756
        RW.destroy(file);
9180 akron1 2757
        text.curLine := text.first(tLine);
2758
        SetPos(text, 0, 0);
9668 akron1 2759
        resetSelect(text);
2760
        Comments(text)
8728 leency 2761
    ELSE
2762
        errno := 1
2763
    END
2764
    RETURN text
2765
END open;
2766
 
2767
 
2768
PROCEDURE findNext* (text: tText; prev: BOOLEAN): BOOLEAN;
2769
VAR
9915 akron1 2770
	cursorPos, x, y, X, Y, Len: INTEGER;
2771
	line: tLine;
2772
	res: BOOLEAN;
2773
	pos, i, pos0, first, last, num, cnt: INTEGER;
2774
	p: Search.tPos;
8728 leency 2775
BEGIN
9915 akron1 2776
	X := text.cursor.X;
2777
	Y := text.cursor.Y;
2778
	text.cursor.X := MIN(text.cursor.X, text.curLine.length);
2779
	cursorPos := text.curLine.pos + text.cursor.X - ORD(prev) - ORD(~prev & (text.foundSel = 0));
2780
	pos0 := -1;
2781
 
2782
	cnt := 0;
2783
	IF text.foundList.count # 0 THEN
2784
		p := text.foundList.first(Search.tPos);
2785
		first := p.pos[0];
2786
		WHILE p # NIL DO
2787
			INC(cnt, p.cnt);
2788
			p := p.next(Search.tPos)
2789
		END;
2790
		p := text.foundList.last(Search.tPos);
2791
		last := p.pos[p.cnt - 1]
2792
	ELSE
2793
		first := -1;
2794
		last := -1
2795
	END;
2796
	text.foundCnt := cnt;
2797
 
2798
	num := 1;
2799
	i := 0;
2800
	p := text.foundList.first(Search.tPos);
2801
	pos := Search.next(p, i);
2802
	WHILE (pos # -1) & (pos <= cursorPos) DO
2803
		pos0 := pos;
2804
		pos := Search.next(p, i);
2805
		INC(num)
2806
	END;
2807
	IF prev THEN
2808
		pos := pos0;
2809
		DEC(num)
2810
	END;
2811
 
2812
	IF pos = -1 THEN
2813
		IF prev THEN
2814
			pos := last;
2815
			num := cnt
2816
		ELSE
2817
			pos := first;
2818
			num := 1
2819
		END
2820
	END;
2821
 
2822
	res := pos # -1;
2823
	IF res THEN
2824
		y := 0;
2825
		line := text.first(tLine);
2826
		WHILE (line.pos <= pos) & (line.next # NIL) DO
2827
			NextLine(line);
2828
			INC(y)
2829
		END;
2830
		IF (line.next # NIL) OR (line.pos > pos) THEN
2831
			PrevLine(line);
2832
			DEC(y)
2833
		END;
2834
		resetSelect(text);
2835
		searchScroll(text, y);
2836
		x := pos - line.pos;
2837
		Len := LENGTH(text.searchText);
2838
		IF x + Len > text.scroll.X + textsize.X THEN
2839
			text.scroll.X := MAX(x + Len - textsize.X + 3, 0)
2840
		ELSIF x < text.scroll.X THEN
2841
			text.scroll.X := MAX(x - 3, 0)
2842
		END;
2843
		SetPos(text, x, y);
2844
		text.foundSel := Len;
2845
		text.foundCur := num
2846
	ELSE
2847
		SetPos(text, X, Y);
2848
		text.foundCur := 0
2849
	END
2850
	RETURN res
8728 leency 2851
END findNext;
2852
 
2853
 
2854
PROCEDURE replace* (text: tText; s: ARRAY OF WCHAR; n: INTEGER);
2855
VAR
2856
    line: tLine;
2857
    sLen, i: INTEGER;
2858
BEGIN
2859
    IF text.foundSel > 0 THEN
2860
        line := text.curLine;
2861
        sLen := LENGTH(s);
2862
        i := text.cursor.X;
2863
        IF sLen > n THEN
2864
            Lines.insert3(line, i, sLen - n)
9560 akron1 2865
        ELSIF n > sLen THEN
2866
            Lines.delCharN(line, i, n - sLen)
2867
        ELSE (* n = sLen *)
2868
        	Lines.copy(line)
8728 leency 2869
        END;
2870
        SetPos(text, i + sLen, text.cursor.Y);
9560 akron1 2871
	    WHILE sLen > 0 DO
2872
	        DEC(sLen);
2873
	        Lines.setChar(line, i + sLen, s[sLen])
2874
	    END;
8728 leency 2875
        resetSelect(text);
2876
        Lines.modify(line);
2877
        modify(text)
2878
    END
2879
END replace;
2880
 
2881
 
2882
PROCEDURE replaceAll* (text: tText; s: ARRAY OF WCHAR; n: INTEGER): INTEGER;
2883
VAR
9903 akron1 2884
    line: tLine;
2885
    y, k, d, pos, y0, i, c: INTEGER;
8728 leency 2886
    p: Search.tPos;
2887
BEGIN
2888
    resetSelect(text);
2889
    SetPos(text, 0, 0);
2890
    line := text.first(tLine);
2891
    y := 0;
2892
    y0 := -1;
2893
    k := 0;
2894
    d := LENGTH(s) - n;
9903 akron1 2895
    c := 0;
2896
    i := 0;
8728 leency 2897
    p := text.foundList.first(Search.tPos);
9903 akron1 2898
    pos := Search.next(p, i);
2899
    WHILE pos # -1 DO
8728 leency 2900
        WHILE (line.pos <= pos) & (line.next # NIL) DO
2901
            NextLine(line);
2902
            INC(y)
2903
        END;
2904
        IF (line.next # NIL) OR (line.pos > pos) THEN
2905
            PrevLine(line);
2906
            DEC(y)
2907
        END;
2908
        IF y = y0 THEN
2909
            INC(k, d)
2910
        ELSE
2911
            k := 0;
2912
            y0 := y
2913
        END;
2914
        SetPos(text, pos - line.pos + k, y);
2915
        text.foundSel := n;
2916
        replace(text, s, n);
9903 akron1 2917
        INC(c);
2918
        pos := Search.next(p, i)
8728 leency 2919
    END
9903 akron1 2920
    RETURN c
8728 leency 2921
END replaceAll;
2922
 
2923
 
9674 akron1 2924
PROCEDURE conv (VAR c: WCHAR; cp: E.CP; enc: INTEGER): BOOLEAN;
2925
VAR
2926
	code: INTEGER;
2927
	res: BOOLEAN;
2928
BEGIN
2929
	res := FALSE;
2930
	IF (c # 0X) & (c # Lines.NUL) & (c # Lines.TAB1) THEN
2931
		code := E.UNI[ORD(c), enc];
2932
		IF (0 <= code) & (code <= 255) THEN
2933
			code := cp[code]
2934
		ELSE
2935
			code := ORD(c)
2936
		END;
9708 akron1 2937
		IF code # ORD(c) THEN
2938
			c := WCHR(code);
2939
			res := TRUE
2940
		END
9674 akron1 2941
	END
2942
	RETURN res
2943
END conv;
2944
 
2945
 
2946
PROCEDURE conv1251to866 (VAR c: WCHAR): BOOLEAN;
9708 akron1 2947
	RETURN conv(c, E.cp866, E.CP1251)
9674 akron1 2948
END conv1251to866;
2949
 
2950
 
2951
PROCEDURE conv866to1251 (VAR c: WCHAR): BOOLEAN;
2952
	RETURN conv(c, E.cp1251, E.CP866)
2953
END conv866to1251;
2954
 
2955
 
9708 akron1 2956
PROCEDURE convert* (text: tText; (*cp: E.CP;*) enc: INTEGER);
9674 akron1 2957
VAR
2958
	line: tLine;
2959
	func: Lines.fConvert;
2960
	modified: BOOLEAN;
2961
BEGIN
2962
	modified := FALSE;
2963
	line := text.first(tLine);
2964
	IF enc = E.CP866 THEN
2965
		func := conv866to1251
9708 akron1 2966
	ELSIF enc = E.CP1251 THEN
9674 akron1 2967
		func := conv1251to866
2968
	ELSE
2969
		line := NIL
2970
	END;
2971
 
2972
	WHILE line # NIL DO
2973
		IF Lines.convert(line, 0, line.length - 1, func) THEN
2974
			modified := TRUE
2975
		END;
2976
		NextLine(line)
2977
	END;
2978
 
2979
	IF modified THEN
2980
		modify(text)
2981
	END
2982
END convert;
2983
 
2984
 
8728 leency 2985
PROCEDURE New* (): tText;
2986
VAR
2987
    text: tText;
2988
BEGIN
2989
    text := create("");
2990
    List._append(text, Lines.create(FALSE));
2991
    text.curLine := text.first(tLine);
9336 akron1 2992
    ChangeLog.changeInt(text.enc, E.CP866);
9659 akron1 2993
    ChangeLog.changeInt(text.eol, E.EOL_CRLF);
8728 leency 2994
    text.enc := E.CP866;
9659 akron1 2995
    text.eol := E.EOL_CRLF;
8728 leency 2996
    SetPos(text, 0, 0);
9913 akron1 2997
    resetSelect(text);
2998
    Comments(text)
8728 leency 2999
    RETURN text
3000
END New;
3001
 
3002
 
9731 akron1 3003
PROCEDURE empty* (text: tText): BOOLEAN;
3004
	RETURN (text.count = 1) & (text.curLine.length = 0)
3005
END empty;
3006
 
3007
 
9671 akron1 3008
PROCEDURE init* (pShowCursor: tProcedure; _lineNumbers, _autoIndents, _autoBrackets, _trimSpace: BOOLEAN);
8728 leency 3009
BEGIN
9174 akron1 3010
    ShowCursor := pShowCursor;
8728 leency 3011
    pdelete := delete;
3012
    drawCursor := TRUE;
9671 akron1 3013
    lineNumbers := _lineNumbers;
3014
    autoIndents := _autoIndents;
3015
    autoBrackets := _autoBrackets;
3016
    trimSpace := _trimSpace;
8728 leency 3017
    padding.left := pad_left;
3018
    padding.top := pad_top;
3019
END init;
3020
 
3021
 
3022
END Text.