Subversion Repositories Kolibri OS

Rev

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

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