Subversion Repositories Kolibri OS

Rev

Rev 9413 | Rev 9452 | 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
            IF line.modified THEN
1372
                Lines.save(line)
1373
            END;
1374
            NextLine(line);
1375
            IF line # NIL THEN
1376
                IF ~RW.newLine(file) THEN
1377
                    res := FALSE
1378
                END
1379
            END
1380
        END;
1381
        IF ~RW.close(file) THEN
1382
            res := FALSE
1383
        END
1384
    ELSE
1385
        res := FALSE
1386
    END;
9073 leency 1387
    IF res THEN
1388
        res := File.Copy(tempFile, name);
1389
        IF res THEN
1390
            text.modified := FALSE;
1391
            ChangeLog.save(text.edition);
1392
            IF File.Delete(tempFile) THEN END
1393
        END
1394
    END;
1395
    IF ~res THEN
1396
        ChangeLog.delCurSaved
1397
    END
8728 leency 1398
    RETURN res
1399
END save;
1400
 
1401
 
1402
PROCEDURE redoGuard (text: tText; guard: tGuard);
1403
BEGIN
1404
    text.edition := guard;
1405
    text.cursor^ := guard.cursor;
1406
    text.select2^ := guard.select2;
1407
    text.scroll := guard.scroll;
1408
    text.CurX := guard.CurX;
1409
    IF guard.selected THEN
1410
        text.select := text.select2
1411
    ELSE
1412
        text.select := text.cursor
1413
    END;
1414
    text.curLine := getLine(text, text.cursor.Y);
1415
    text.comments := TRUE;
1416
    text.search := TRUE
1417
END redoGuard;
1418
 
1419
 
1420
PROCEDURE undo* (text: tText);
1421
VAR
1422
    item: List.tItem;
1423
    guard: tGuard;
1424
BEGIN
1425
    guard := text.edition;
1426
    item := guard.prev;
1427
    WHILE (item # NIL) & ~(item IS tGuard) DO
1428
        item := item.prev
1429
    END;
1430
 
1431
    IF item # NIL THEN
1432
        guard := item(tGuard);
9073 leency 1433
        text.edition := guard
8728 leency 1434
    END;
1435
 
9050 leency 1436
    item := ChangeLog.CL.Log.first;
8728 leency 1437
    WHILE item # guard DO
1438
        ChangeLog.redo(item);
1439
        item := item.next
1440
    END;
1441
    redoGuard(text, guard);
9073 leency 1442
    ChangeLog.setGuard(guard);
9174 akron1 1443
    text.modified := ~guard.saved;
1444
    ShowCursor
8728 leency 1445
END undo;
1446
 
1447
 
1448
PROCEDURE redo* (text: tText);
1449
VAR
1450
    item: List.tItem;
1451
    guard: tGuard;
1452
BEGIN
1453
    guard := text.edition;
1454
    item := guard.next;
1455
    WHILE (item # NIL) & ~(item IS tGuard) DO
1456
        ChangeLog.redo(item);
1457
        item := item.next
1458
    END;
1459
    IF item # NIL THEN
1460
        guard := item(tGuard);
1461
        redoGuard(text, guard)
1462
    END;
9073 leency 1463
    ChangeLog.setGuard(guard);
9174 akron1 1464
    text.modified := ~guard.saved;
1465
    ShowCursor
8728 leency 1466
END redo;
1467
 
1468
 
1469
PROCEDURE copy (text: tText);
1470
VAR
1471
    selBeg, selEnd: tPoint;
1472
    first, line: tLine;
1473
    cnt, n: INTEGER;
1474
    buffer: CB.tBuffer;
1475
 
1476
 
1477
    PROCEDURE append (buffer: CB.tBuffer; line: tLine; first, last: INTEGER);
1478
    BEGIN
1479
        IF first <= last THEN
1480
            CB.append(buffer, line, first, last)
1481
        ELSE
1482
            IF U.OS = "KOS" THEN
1483
                CB.appends(buffer, SPACE, 0, 0)
1484
            END
1485
        END
1486
    END append;
1487
 
1488
 
1489
BEGIN
1490
    getSelect(text, selBeg, selEnd);
1491
 
1492
    first := getLine(text, selBeg.Y);
1493
    line := first;
1494
 
1495
    n := selEnd.Y - selBeg.Y;
1496
    cnt := 0;
1497
    WHILE n >= 0 DO
1498
        INC(cnt, line.length + lenEOL);
1499
        NextLine(line);
1500
        DEC(n)
1501
    END;
1502
 
1503
    buffer := CB.create(cnt);
1504
 
1505
    n := selEnd.Y - selBeg.Y;
1506
    line := first;
1507
    IF n = 0 THEN
1508
        CB.append(buffer, line, selBeg.X, selEnd.X - 1)
1509
    ELSE
1510
        append(buffer, line, selBeg.X, line.length - 1);
1511
        REPEAT
1512
            DEC(n);
1513
            CB.eol(buffer);
1514
            NextLine(line);
1515
            IF n > 0 THEN
1516
                append(buffer, line, 0, line.length - 1)
1517
            END
1518
        UNTIL n = 0;
1519
        append(buffer, line, 0, selEnd.X - 1)
1520
    END;
1521
    CB.eot(buffer);
1522
    CB.put(buffer);
1523
    CB.destroy(buffer)
1524
END copy;
1525
 
1526
 
1527
PROCEDURE paste (text: tText);
1528
VAR
1529
    line, newLine, curLine: tLine;
9174 akron1 1530
    w: INTEGER;
8728 leency 1531
    cliptext: RW.tInput;
1532
    eol: BOOLEAN;
1533
    cursor: pPoint;
9174 akron1 1534
 
1535
 
1536
    PROCEDURE lineWidth (line: tLine; pos: INTEGER): INTEGER;
1537
    VAR
1538
    	i, res: INTEGER;
1539
    	c: WCHAR;
1540
    BEGIN
1541
    	res := pos;
1542
    	i := 0;
1543
    	REPEAT
1544
	    	c := getChar(line, i);
1545
	    	IF c = TAB THEN
1546
	    		INC(res, Lines.tab - res MOD Lines.tab)
1547
	    	ELSIF c # TAB1 THEN
1548
	    		INC(res)
1549
	    	END;
1550
	    	INC(i)
1551
    	UNTIL c = 0X
1552
    	RETURN res - pos - 1
1553
    END lineWidth;
1554
 
1555
 
8728 leency 1556
BEGIN
1557
    line := Lines.create(TRUE);
1558
    cliptext := RW.clipboard();
1559
    delSelect(text);
1560
    cursor := text.cursor;
9174 akron1 1561
    WHILE (cliptext # NIL) & (RW.getString(cliptext, line, Lines.tabs, eol) >= 0) DO
1562
        IF line.length > 0 THEN
1563
        	w := lineWidth(line, cursor.X);
8728 leency 1564
            Lines.insert2(text.curLine, cursor.X, line);
1565
            Lines.modify(text.curLine);
1566
            modify(text);
9174 akron1 1567
            SetPos(text, cursor.X + w, cursor.Y);
8728 leency 1568
            resetSelect(text)
1569
        END;
1570
        IF eol THEN
1571
            newLine := Lines.create(FALSE);
1572
            modify(text);
1573
            curLine := text.curLine;
1574
            IF cursor.X < curLine.length THEN
9174 akron1 1575
                Lines.wrap(curLine, newLine, cursor.X);
1576
                Lines.modify(curLine)
8728 leency 1577
            END;
1578
            List._insert(text, curLine, newLine);
9174 akron1 1579
            Lines.modify(newLine);
8728 leency 1580
            SetPos(text, 0, cursor.Y + 1);
1581
            resetSelect(text)
1582
        END;
1583
        Lines.destroy(line);
1584
        line := Lines.create(TRUE)
1585
    END;
1586
    Lines.destroy(line);
1587
    RW.destroy(cliptext)
1588
END paste;
1589
 
1590
 
1591
PROCEDURE searchScroll (text: tText; n: INTEGER);
1592
BEGIN
1593
    IF n - text.scroll.Y > textsize.Y - 1 THEN
1594
        text.scroll.Y := MAX(n - 2 * textsize.Y DIV 3, 0)
1595
    ELSIF n < text.scroll.Y THEN
1596
        text.scroll.Y := MAX(n - textsize.Y DIV 3, 0)
1597
    END
1598
END searchScroll;
1599
 
1600
 
1601
PROCEDURE goto* (text: tText; n: INTEGER): BOOLEAN;
1602
VAR
1603
    res: BOOLEAN;
1604
BEGIN
1605
    DEC(n);
1606
    IF (0 <= n) & (n < text.count) THEN
1607
        resetSelect(text);
1608
        searchScroll(text, n);
1609
        SetPos(text, 0, n);
1610
        res := TRUE
1611
    ELSE
1612
        res := FALSE
1613
    END
1614
    RETURN res
1615
END goto;
1616
 
1617
 
9060 leency 1618
PROCEDURE toggleLabel* (text: tText);
1619
BEGIN
1620
    text.curLine.label := ~text.curLine.label
1621
END toggleLabel;
1622
 
1623
 
1624
PROCEDURE gotoLabel* (text: tText; frw: BOOLEAN);
1625
VAR
1626
    line: tLine;
1627
    n: INTEGER;
9073 leency 1628
 
1629
    PROCEDURE search (VAR line: tLine; VAR n: INTEGER; frw: BOOLEAN);
1630
    BEGIN
1631
        IF frw THEN
1632
            WHILE (line # NIL) & ~line.label DO
1633
                NextLine(line);
1634
                INC(n)
1635
            END
1636
        ELSE
1637
            WHILE (line # NIL) & ~line.label DO
1638
                PrevLine(line);
1639
                DEC(n)
1640
            END
1641
        END
1642
    END search;
1643
 
9060 leency 1644
BEGIN
1645
    n := text.cursor.Y;
1646
    line := text.curLine;
1647
    IF frw THEN
9073 leency 1648
        NextLine(line);
1649
        INC(n)
9060 leency 1650
    ELSE
9073 leency 1651
        PrevLine(line);
1652
        DEC(n)
9060 leency 1653
    END;
9073 leency 1654
    search(line, n, frw);
1655
    IF line = NIL THEN
1656
        IF frw THEN
1657
            n := 0;
1658
            line := text.first(tLine)
1659
        ELSE
1660
            n := text.count - 1;
1661
            line := text.last(tLine)
1662
        END;
1663
        search(line, n, frw)
1664
    END;
9060 leency 1665
    IF line # NIL THEN
1666
        IF goto(text, n + 1) THEN END
1667
    END
1668
END gotoLabel;
1669
 
1670
 
8728 leency 1671
PROCEDURE changeCase (text: tText; upper: BOOLEAN);
1672
VAR
1673
    i: INTEGER;
1674
    line: tLine;
1675
BEGIN
1676
    line := text.curLine;
1677
    i := text.cursor.X - 1;
1678
 
1679
    WHILE (i >= 0) & U.isLetter(getChar(line, i)) DO
1680
        DEC(i)
1681
    END;
1682
 
1683
    IF Lines.chCase(line, i + 1, text.cursor.X - 1, upper) THEN
1684
        modify(text)
1685
    END
1686
END changeCase;
1687
 
1688
 
1689
PROCEDURE chCase* (text: tText; upper: BOOLEAN);
1690
VAR
1691
    selBeg, selEnd: tPoint;
1692
    first, line: Lines.tLine;
1693
    cnt: INTEGER;
1694
    modified: BOOLEAN;
1695
BEGIN
1696
    modified := FALSE;
1697
    IF selected(text) THEN
1698
        getSelect(text, selBeg, selEnd);
1699
        first := getLine(text, selBeg.Y);
1700
        line := first;
1701
        cnt := selEnd.Y - selBeg.Y;
1702
        IF cnt = 0 THEN
1703
            IF Lines.chCase(line, selBeg.X, selEnd.X - 1, upper) THEN
1704
                modified := TRUE
1705
            END
1706
        ELSE
1707
            IF Lines.chCase(line, selBeg.X, line.length - 1, upper) THEN
1708
                modified := TRUE
1709
            END;
1710
            WHILE cnt > 1 DO
1711
                NextLine(line);
1712
                IF Lines.chCase(line, 0, line.length - 1, upper) THEN
1713
                    modified := TRUE
1714
                END;
1715
                DEC(cnt)
1716
            END;
1717
            NextLine(line);
1718
            IF Lines.chCase(line, 0, selEnd.X - 1, upper) THEN
1719
                modified := TRUE
1720
            END
1721
        END
1722
    END;
1723
    IF modified THEN
1724
        modify(text)
1725
    END
1726
END chCase;
1727
 
1728
 
1729
PROCEDURE UpDown (text: tText; step: INTEGER);
1730
VAR
1731
    temp: INTEGER;
1732
BEGIN
1733
    IF text.CurX = -1 THEN
1734
        text.CurX := text.cursor.X
1735
    END;
1736
    temp := text.CurX;
1737
    SetPos(text, temp, text.cursor.Y + step);
1738
    text.CurX := temp
1739
END UpDown;
1740
 
1741
 
1742
PROCEDURE delLine* (text: tText);
1743
BEGIN
1744
    resetSelect(text);
1745
    IF text.curLine.length > 0 THEN
1746
        Lines.delCharN(text.curLine, 0, text.curLine.length)
1747
    END;
1748
    SetPos(text, 0, text.cursor.Y);
1749
    IF text.cursor.Y = text.count - 1 THEN
1750
        BkSpace(text)
1751
    ELSE
1752
        delete(text)
1753
    END
1754
END delLine;
1755
 
1756
 
9174 akron1 1757
PROCEDURE dupLine* (text: tText);
9010 leency 1758
VAR
1759
    newLine, curLine: tLine;
1760
BEGIN
1761
    curLine := text.curLine;
1762
    newLine := Lines.create(FALSE);
1763
    modify(text);
1764
    Lines.insert3(newLine, 0, curLine.length);
1765
    List._insert(text, curLine, newLine);
9174 akron1 1766
    Lines.move(curLine, newLine);
1767
    Lines.modify(newLine)
9010 leency 1768
END dupLine;
1769
 
1770
 
1771
PROCEDURE exchange (text: tText; first, second: tLine);
1772
BEGIN
1773
    List._exchange(text, first, second);
1774
    Lines.modify(text.curLine);
1775
    modify(text);
1776
    UpDown(text, 0)
1777
END exchange;
1778
 
1779
 
9413 akron1 1780
PROCEDURE upLine (text: tText);
9010 leency 1781
BEGIN
9413 akron1 1782
	DEC(text.cursor.Y);
1783
	exchange(text, text.curLine.prev(tLine), text.curLine)
9010 leency 1784
END upLine;
1785
 
1786
 
9413 akron1 1787
PROCEDURE downLine (text: tText);
9010 leency 1788
BEGIN
9413 akron1 1789
	INC(text.cursor.Y);
1790
	exchange(text, text.curLine, text.curLine.next(tLine))
9010 leency 1791
END downLine;
1792
 
1793
 
9413 akron1 1794
PROCEDURE MoveLines* (text: tText; down: BOOLEAN);
1795
VAR
1796
	last: tLine;
1797
	selBeg, selEnd, temp: tPoint;
1798
	n, step: INTEGER;
1799
	frw: BOOLEAN;
1800
	moveLine: PROCEDURE (text: tText);
1801
BEGIN
1802
	getSelect(text, selBeg, selEnd);
1803
	IF (selBeg.Y > 0) & ~down OR (selEnd.Y < text.count - 1) & down THEN
1804
		IF down THEN
1805
			step := -2;
1806
			moveLine := downLine
1807
		ELSE
1808
			step := 2;
1809
			moveLine := upLine
1810
		END;
1811
		frw := (text.cursor.X = selEnd.X) & (text.cursor.Y = selEnd.Y);
1812
		IF selEnd.Y # selBeg.Y THEN
1813
			IF down # frw THEN
1814
				temp := text.cursor^;
1815
				SetPos(text, 0, text.select.Y);
1816
				setSelect(text);
1817
				text.select^ := temp
1818
			END;
1819
			last := getLine(text, selEnd.Y);
1820
			selBeg.X := 0;
1821
			selEnd.X := last.length;
1822
			n := selEnd.Y - selBeg.Y + 1;
1823
			WHILE n > 0 DO
1824
				moveLine(text);
1825
				SetPos(text, 0, text.cursor.Y + step);
1826
				DEC(n)
1827
			END
1828
		ELSE
1829
			moveLine(text)
1830
		END;
1831
 
1832
		IF frw THEN
1833
			temp := selBeg;
1834
			selBeg := selEnd;
1835
			selEnd := temp
1836
		END;
1837
		step := step DIV 2;
1838
		SetPos(text, selBeg.X, selBeg.Y - step);
1839
		setSelect(text);
1840
		text.select.X := selEnd.X;
1841
		text.select.Y := selEnd.Y - step
1842
	END
1843
END MoveLines;
1844
 
1845
 
9010 leency 1846
PROCEDURE isWordChar (c: WCHAR): BOOLEAN;
1847
    RETURN U.isLetter(c) OR U.isDigit(c) OR (c = "_")
1848
END isWordChar;
1849
 
1850
 
9197 akron1 1851
PROCEDURE getSelectedText* (text: tText; VAR s: ARRAY OF WCHAR);
1852
VAR
1853
    n: INTEGER;
1854
    selBeg, selEnd: tPoint;
1855
BEGIN
1856
	s[0] := 0X;
1857
    IF selected(text) & (text.cursor.Y = text.select.Y) THEN
1858
        getSelect(text, selBeg, selEnd);
1859
        n := getString(text.curLine, selBeg.X, selEnd.X - selBeg.X, s)
1860
    END
1861
END getSelectedText;
1862
 
1863
 
9010 leency 1864
PROCEDURE wordSel* (text: tText);
1865
VAR
1866
    n, i, x1, x2: INTEGER;
1867
    selBeg, selEnd: tPoint;
1868
    str: tString;
1869
    curLine: tLine;
1870
BEGIN
1871
    curLine := text.curLine;
1872
    IF selected(text) & (text.cursor.Y = text.select.Y) THEN
1873
        getSelect(text, selBeg, selEnd);
1874
        x1 := selBeg.X;
1875
        x2 := selEnd.X;
1876
        n := getString(curLine, x1, x2 - x1, str);
1877
    ELSE
1878
        str := ""
1879
    END;
1880
    IF str # "" THEN
1881
        i := 0;
1882
        WHILE (i < n) & isWordChar(str[i]) DO
1883
            INC(i)
1884
        END;
1885
        IF (i # n) OR
1886
            ((x1 > 0) & isWordChar(getChar(curLine, x1 - 1))) OR
1887
            ((x2 < curLine.length) & isWordChar(getChar(curLine, x2))) THEN
1888
            str := ""
1889
        END
1890
    END;
9050 leency 1891
    IF search(text, str, Lang.isCS(text.lang), TRUE) THEN END
9010 leency 1892
END wordSel;
1893
 
1894
 
9336 akron1 1895
PROCEDURE getWordPos (line: tLine; pos: INTEGER): INTEGER;
1896
VAR
1897
	c: WCHAR;
1898
BEGIN
1899
	c := getChar(line, pos);
1900
	IF isWordChar(c) THEN
1901
		WHILE (pos < line.length) & isWordChar(getChar(line, pos)) DO
1902
			INC(pos)
1903
		END
1904
	ELSIF Lines.isSpace(c) THEN
1905
		WHILE (pos < line.length) & Lines.isSpace(getChar(line, pos)) DO
1906
			INC(pos)
1907
		END
1908
	ELSE
1909
		WHILE (pos < line.length) & ~Lines.isSpace(getChar(line, pos)) & ~isWordChar(getChar(line, pos)) DO
1910
			INC(pos)
1911
		END
1912
	END
1913
	RETURN pos
1914
END getWordPos;
1915
 
1916
 
9073 leency 1917
PROCEDURE key* (text: tText; code: INTEGER; shift, ctrl: BOOLEAN);
9174 akron1 1918
VAR
9336 akron1 1919
	n, wPos: INTEGER;
8728 leency 1920
BEGIN
9073 leency 1921
    IF shift THEN
8728 leency 1922
        setSelect(text)
1923
    ELSE
1924
        IF (33 <= code) & (code <= 40) THEN
9413 akron1 1925
        	IF ~(((code = 38) OR (code = 40)) & ctrl) THEN
1926
	            resetSelect(text)
1927
            END
8728 leency 1928
        END
1929
    END;
1930
 
1931
    CASE code OF
1932
    |33:
9073 leency 1933
        IF ctrl THEN
8728 leency 1934
            UpDown(text, text.scroll.Y - text.cursor.Y)
1935
        ELSE
1936
            text.scroll.Y := MAX(text.scroll.Y - textsize.Y, 0);
1937
            UpDown(text, -textsize.Y)
1938
        END
1939
    |34:
9073 leency 1940
        IF ctrl THEN
8728 leency 1941
            UpDown(text, MIN(text.scroll.Y + textsize.Y - 1, text.count - 1) - text.cursor.Y)
1942
        ELSE
1943
            text.scroll.Y := MIN(text.scroll.Y + textsize.Y, text.count - 1);
1944
            UpDown(text, textsize.Y)
1945
        END
1946
    |35:
9073 leency 1947
        IF ctrl THEN
8728 leency 1948
            SetPos(text, text.last(tLine).length, text.count - 1)
1949
        ELSE
1950
            SetPos(text, text.curLine.length, text.cursor.Y)
1951
        END
1952
    |36:
9073 leency 1953
        IF ctrl THEN
8728 leency 1954
            SetPos(text, 0, 0)
1955
        ELSE
9174 akron1 1956
        	n := leadingSpaces(text.curLine);
1957
        	IF text.cursor.X > n THEN
1958
	            SetPos(text, n, text.cursor.Y)
1959
        	ELSE
1960
        		SetPos(text, 0, text.cursor.Y)
1961
        	END
8728 leency 1962
        END
1963
    |37:
1964
        IF (text.cursor.X = 0) & (text.curLine.prev # NIL) THEN
1965
            SetPos(text, text.curLine.prev(tLine).length, text.cursor.Y - 1)
1966
        ELSE
9336 akron1 1967
        	IF ctrl THEN
1968
        		wPos := 0;
1969
        		REPEAT
1970
        			n := wPos;
1971
        			wPos := getWordPos(text.curLine, wPos)
1972
        		UNTIL wPos >= text.cursor.X;
1973
				move(text, n - text.cursor.X)
1974
        	ELSE
1975
            	move(text, -1)
1976
            END
8728 leency 1977
        END
1978
    |38:
9073 leency 1979
        IF ctrl THEN
9413 akron1 1980
            MoveLines(text, FALSE)
9010 leency 1981
        ELSE
1982
            UpDown(text, -1)
1983
        END
8728 leency 1984
    |39:
1985
        IF (text.cursor.X = text.curLine.length) & (text.curLine.next # NIL) THEN
1986
            SetPos(text, 0, text.cursor.Y + 1)
1987
        ELSE
9336 akron1 1988
        	IF ctrl THEN
1989
				move(text, getWordPos(text.curLine, text.cursor.X) - text.cursor.X)
1990
        	ELSE
1991
            	move(text, 1)
1992
        	END
8728 leency 1993
        END
1994
    |40:
9073 leency 1995
        IF ctrl THEN
9413 akron1 1996
            MoveLines(text, TRUE)
9010 leency 1997
        ELSE
1998
            UpDown(text, 1)
1999
        END
2000
    |46:
9073 leency 2001
        IF ctrl THEN
9010 leency 2002
            delLine(text)
2003
        ELSE
9174 akron1 2004
            delete(text);
2005
            ShowCursor
9010 leency 2006
        END
8728 leency 2007
    |ORD("C"):
9073 leency 2008
        IF ctrl THEN
8728 leency 2009
            IF selected(text) THEN
2010
                copy(text)
2011
            END
2012
        END
2013
    |ORD("X"):
9073 leency 2014
        IF ctrl THEN
8728 leency 2015
            IF selected(text) THEN
2016
                copy(text);
2017
                delSelect(text)
2018
            END
2019
        END
2020
    |ORD("V"):
9073 leency 2021
        IF ctrl THEN
8728 leency 2022
            IF CB.available() THEN
2023
                paste(text)
2024
            END
2025
        END
2026
    |ORD("A"):
9073 leency 2027
        IF ctrl THEN
8728 leency 2028
            text.select2.X := 0;
2029
            text.select2.Y := 0;
2030
            text.select := text.select2;
2031
            SetPos(text, text.last(tLine).length, text.count - 1)
2032
        END
2033
    |ORD("L"), ORD("U"):
9073 leency 2034
        IF ctrl THEN
9174 akron1 2035
        	IF selected(text) THEN
2036
            	chCase(text, code = ORD("U"))
2037
            ELSE
2038
            	changeCase(text, code = ORD("U"))
2039
            END;
2040
            ShowCursor
8728 leency 2041
        END
9010 leency 2042
    |ORD("D"):
9073 leency 2043
        IF ctrl THEN
9010 leency 2044
            dupLine(text)
2045
        END
8728 leency 2046
    ELSE
2047
    END
2048
END key;
2049
 
2050
 
2051
PROCEDURE mouse* (text: tText; x, y: INTEGER);
2052
VAR
2053
    cursorX: INTEGER;
2054
BEGIN
2055
    DEC(x, padding.left);
2056
    DEC(y, padding.top);
2057
    cursorX := (x*2) DIV charWidth;
2058
    SetPos(text, cursorX DIV 2 + cursorX MOD 2 + text.scroll.X, y DIV charHeight + text.scroll.Y)
2059
END mouse;
2060
 
2061
 
2062
PROCEDURE selectWord* (text: tText);
2063
VAR
2064
    cursorX, x1, x2: INTEGER;
2065
    line: tLine;
2066
BEGIN
2067
    resetSelect(text);
2068
    cursorX := text.cursor.X;
2069
    line := text.curLine;
2070
    x1 := cursorX - 1;
9336 akron1 2071
    IF (cursorX < line.length) & isWordChar(getChar(line, cursorX)) THEN
8728 leency 2072
        x2 := cursorX;
2073
        WHILE (x2 < line.length) & isWordChar(getChar(line, x2)) DO
2074
            INC(x2)
2075
        END
2076
    ELSE
2077
        WHILE (x1 >= 0) & ~isWordChar(getChar(line, x1)) DO
2078
            DEC(x1)
2079
        END;
2080
        x2 := x1 + 1
2081
    END;
2082
    WHILE (x1 >= 0) & isWordChar(getChar(line, x1)) DO
2083
        DEC(x1)
2084
    END;
2085
    INC(x1);
2086
    IF x1 < x2 THEN
2087
        SetPos(text, x1, text.cursor.Y);
2088
        setSelect(text);
2089
        SetPos(text, x2, text.cursor.Y)
2090
    END
2091
END selectWord;
2092
 
2093
 
2094
PROCEDURE cursor (text: tText);
2095
VAR
9295 akron1 2096
    x, y1, y2, scrollX, scrollY: INTEGER;
8728 leency 2097
    cursor: pPoint;
2098
BEGIN
2099
    cursor := text.cursor;
9295 akron1 2100
    scrollX := text.scroll.X;
2101
    scrollY := text.scroll.Y;
2102
    IF ~((scrollY > cursor.Y) OR (scrollY + textsize.Y <= cursor.Y) OR
2103
       (scrollX > cursor.X) OR (scrollX + textsize.X <= cursor.X)) THEN
2104
        x := (cursor.X - scrollX)*charWidth + padding.left;
2105
        y1 := (cursor.Y - scrollY)*charHeight + padding.top + (inter DIV 2 + 1);
2106
        y2 := y1 + charHeight - (inter + 2);
2107
        G.notVLine(canvas, x, y1, y2);
2108
        G.notVLine(canvas, x - 1, y1, y2)
8728 leency 2109
    END
2110
END cursor;
2111
 
2112
 
2113
PROCEDURE drawSelect (text: tText; line: tLine; selBeg, selEnd, y: INTEGER);
2114
VAR
2115
    Len, pos, x, firstCharIdx: INTEGER;
2116
BEGIN
2117
    firstCharIdx := MAX(text.scroll.X, selBeg);
2118
    Len := MAX(MIN(line.length - firstCharIdx, selEnd - firstCharIdx), 0);
2119
    Len := MIN(Len, textsize.X - pos + 1);
2120
    SetColor(colors.seltext, colors.selback);
2121
    pos := MAX((selBeg - text.scroll.X), 0);
2122
    x := pos*charWidth + padding.left;
2123
    G.SetColor(canvas, colors.selback);
2124
    G.FillRect(canvas, x - 2, y - inter DIV 2, x + 1 + Len*charWidth, y - inter DIV 2 + charHeight);
9193 akron1 2125
    G.TextOut(canvas, pos*charWidth + padding.left, y, Lines.getPChar(line, firstCharIdx), Len, colors.seltext)
8728 leency 2126
END drawSelect;
2127
 
2128
 
2129
PROCEDURE mark (line: tLine; y: INTEGER);
2130
VAR
2131
    color, i: INTEGER;
2132
BEGIN
2133
    IF line.modified THEN
2134
        color := colors.modified
2135
    ELSIF line.saved THEN
2136
        color := colors.saved
2137
    ELSE
2138
        color := colors.back
2139
    END;
2140
    G.SetColor(canvas, color);
2141
 
2142
    FOR i := 3 TO mark_width + 2 DO
2143
        G.VLine(canvas, padding.left - i, y, y + charHeight)
2144
    END
2145
END mark;
2146
 
2147
 
2148
PROCEDURE setPadding (left, top: INTEGER);
2149
BEGIN
2150
    padding.left := left;
2151
    padding.top := top;
2152
    textsize.X := (size.X - padding.left) DIV charWidth;
2153
    textsize.Y := (size.Y - padding.top) DIV charHeight;
2154
END setPadding;
2155
 
2156
 
2157
PROCEDURE draw* (text: tText);
2158
VAR
2159
    y, n, Len, cnt, i, x: INTEGER;
2160
    line, firstLine, lastLine: tLine;
2161
    selBeg, selEnd: tPoint;
2162
    s: ARRAY 12 OF WCHAR;
2163
    backColor, numWidth, xNum, wNum: INTEGER;
2164
    p: Search.tPos;
2165
    guard: tGuard;
2166
BEGIN
2167
    IF text.search & search(text, text.searchText, text.cs, text.whole) THEN END;
9190 akron1 2168
    IF (text.lang # Lang.langText) & text.comments THEN
8728 leency 2169
        Comments(text)
2170
    END;
2171
    IF text.guard THEN
2172
        NEW(guard);
9050 leency 2173
        List.append(ChangeLog.CL.Log, guard);
9073 leency 2174
        guard.saved := ChangeLog.isFirstGuard(guard);
8728 leency 2175
        text.edition := guard;
9073 leency 2176
        text.guard := FALSE
8728 leency 2177
    ELSE
2178
        guard := text.edition
2179
    END;
2180
 
2181
    guard.cursor := text.cursor^;
2182
    guard.select2 := text.select2^;
2183
    guard.scroll := text.scroll;
2184
    guard.CurX := text.CurX;
2185
    guard.selected := text.select = text.select2;
2186
 
2187
    G.SetColor(canvas, colors.back);
2188
    G.clear(canvas);
9060 leency 2189
    wNum := charWidth;
8728 leency 2190
    IF text.numbers THEN
2191
        numWidth := U.lg10(text.count) + 2;
2192
        xNum := numWidth*wNum - wNum DIV 2;
2193
        setPadding(numWidth*wNum + pad_left, padding.top);
2194
    ELSE
9060 leency 2195
        setPadding(pad_left + wNum*2, padding.top)
8728 leency 2196
    END;
2197
    getSelect(text, selBeg, selEnd);
2198
    y := padding.top + inter DIV 2;
2199
    n := text.scroll.Y;
2200
    line := getLine(text, n);
2201
    firstLine := line;
2202
    cnt := 0;
9210 akron1 2203
    WHILE (line # NIL) & (cnt < textsize.Y) DO
8728 leency 2204
        backColor := colors.back;
2205
        IF (line = text.curLine) & ~selected(text) THEN
2206
            G.SetColor(canvas, colors.curline);
2207
            G.FillRect(canvas, padding.left - 2, y - inter DIV 2, size.X - 1, y - inter DIV 2 + charHeight);
2208
            backColor := colors.curline
2209
        END;
2210
        SetColor(colors.text, backColor);
2211
        Len := MAX(line.length - text.scroll.X, 0);
9193 akron1 2212
        G.TextOut(canvas, padding.left, y, Lines.getPChar(line, text.scroll.X), MIN(Len, textsize.X + 1), colors.delim);
9190 akron1 2213
        IF text.lang # Lang.langText THEN
8728 leency 2214
            parse(text, line, y, backColor, text.lang)
2215
        END;
2216
        mark(line, y - inter DIV 2);
2217
        IF (selBeg.Y < n) & (n < selEnd.Y) THEN
2218
            drawSelect(text, line, 0, line.length, y)
2219
        ELSIF (selBeg.Y = n) & (selEnd.Y = n) & (selBeg.X # selEnd.X) THEN
2220
            drawSelect(text, line, selBeg.X, selEnd.X, y)
2221
        ELSIF (selBeg.Y = n) & (selEnd.Y # n) THEN
2222
            drawSelect(text, line, selBeg.X, line.length, y)
2223
        ELSIF (selBeg.Y # n) & (selEnd.Y = n) THEN
2224
            drawSelect(text, line, 0, selEnd.X, y)
2225
        END;
2226
        NextLine(line);
2227
        INC(y, charHeight);
2228
        INC(n);
2229
        INC(cnt)
2230
    END;
9060 leency 2231
    G.SetColor(canvas, colors.numback);
2232
    G.FillRect(canvas, 0, 0, padding.left - pad_left (*+ 1*), size.Y - 1);
2233
    line := firstLine;
2234
    SetColor(colors.numtext, colors.numback);
2235
    y := padding.top + inter DIV 2;
9210 akron1 2236
    n := MIN(text.scroll.Y + textsize.Y, text.count);
9060 leency 2237
    FOR i := text.scroll.Y + 1 TO n DO
2238
        IF text.numbers THEN
2239
            IF (i MOD 10 = 0) OR (i - 1 = text.cursor.Y) OR line.label THEN
8728 leency 2240
                U.int2str(i, s);
9060 leency 2241
                G.TextOut2(canvas, (numWidth - U.lg10(i) - 1)*wNum - wNum DIV 2, y, s, LENGTH(s))
8728 leency 2242
            ELSE
2243
                G.SetColor(canvas, colors.numtext);
9208 akron1 2244
                G.HLine(canvas, y - inter DIV 2 + charHeight DIV 2, xNum - wNum DIV (1 + ORD(i MOD 5 # 0)), xNum)
9060 leency 2245
            END
2246
        END;
2247
        IF line.label THEN
2248
            FOR x := wNum DIV 2 TO (padding.left - pad_left) - wNum DIV 2 DO
2249
                G.notVLine(canvas, x, y, y + charHeight - inter);
2250
                G.xorVLine(canvas, x, y, y + charHeight - inter)
2251
            END
2252
        END;
2253
        NextLine(line);
2254
        INC(y, charHeight)
8728 leency 2255
    END;
2256
 
2257
    IF text.searchText # "" THEN
2258
        cnt := 0;
2259
        line := firstLine;
2260
        lastLine := line;
9210 akron1 2261
        WHILE (line # NIL) & (cnt < textsize.Y) DO
8728 leency 2262
            lastLine := line;
2263
            NextLine(line);
2264
            INC(cnt)
2265
        END;
2266
        p := text.foundList.first(Search.tPos);
2267
        WHILE p # NIL DO
2268
            y := padding.top + inter DIV 2;
2269
            IF (firstLine.pos <= p.pos) & (p.pos <= lastLine.pos + lastLine.length) THEN
2270
                line := firstLine;
2271
                WHILE (line.pos <= p.pos) & (line # lastLine) DO
2272
                    NextLine(line);
2273
                    INC(y, charHeight)
2274
                END;
2275
                IF (line # lastLine) & (line # firstLine) OR (line = lastLine) & (line.pos > p.pos) THEN
2276
                    PrevLine(line);
2277
                    DEC(y, charHeight)
2278
                END;
2279
                x := (p.pos - line.pos - text.scroll.X)*charWidth + padding.left;
2280
                n := LENGTH(text.searchText)*charWidth;
2281
                WHILE n > 0 DO
2282
                    IF x >= padding.left THEN
2283
                        G.notVLine(canvas, x, y, y + charHeight - inter)
2284
                    END;
2285
                    INC(x);
2286
                    DEC(n)
2287
                END;
2288
            END;
2289
            p := p.next(Search.tPos)
2290
        END
2291
    END;
2292
 
2293
    IF text.foundSel > 0 THEN
2294
        x := (text.cursor.X - text.scroll.X)*charWidth + padding.left;
2295
        y := (text.cursor.Y - text.scroll.Y)*charHeight + padding.top + inter DIV 2;
2296
        n := text.foundSel*charWidth;
2297
        WHILE n > 0 DO
2298
            IF x >= padding.left THEN
2299
                G.xorVLine(canvas, x, y, y + charHeight - inter)
2300
            END;
2301
            INC(x);
2302
            DEC(n)
2303
        END
2304
    END;
2305
 
2306
    IF drawCursor THEN
2307
        cursor(text)
2308
    END;
8762 leency 2309
    G.SetColor(canvas, K.borderColor);
9060 leency 2310
    G.VLine(canvas, 0, 0, size.Y - 1);
8728 leency 2311
END draw;
2312
 
2313
 
9050 leency 2314
PROCEDURE switch* (text: tText);
2315
BEGIN
2316
    ChangeLog.set(text.chLog);
9194 akron1 2317
    Lines.setMaxLength(text.maxLength);
2318
    Lang.setCurLang(text.lang)
9050 leency 2319
END switch;
2320
 
2321
 
8728 leency 2322
PROCEDURE create (fileName: RW.tFileName): tText;
2323
VAR
2324
    text: tText;
2325
BEGIN
2326
    NEW(text);
9050 leency 2327
    text.maxLength := 64;
2328
    text.chLog := ChangeLog.create(text.maxLength);
8728 leency 2329
    NEW(text.cursor);
2330
    NEW(text.select2);
2331
    text.cursor.X := 0;
2332
    text.cursor.Y := 0;
2333
    resetSelect(text);
2334
    text.scroll.X := 0;
2335
    text.scroll.Y := 0;
2336
    setPadding(padding.left, padding.top);
2337
    text.curLine := NIL;
2338
    text.modified := FALSE;
2339
    text.comments := TRUE;
2340
    text.search := TRUE;
2341
    text.cs := FALSE;
2342
    text.whole := FALSE;
2343
    text.numbers := TRUE;
2344
    text.guard := TRUE;
2345
    text.idxData := NIL;
2346
    text.edition := NIL;
2347
    text.foundList := List.create(NIL);
2348
    text.searchText := "";
2349
    text.foundSel := 0;
2350
    text.CurX := -1;
9193 akron1 2351
    text.lang := Lang.langText;
2352
    Lang.setCurLang(Lang.langText);
8728 leency 2353
    setName(text, fileName);
2354
    ASSERT(text = List.create(text))
2355
    RETURN text
2356
END create;
2357
 
2358
 
2359
PROCEDURE setColors* (text, back, seltext, selback, modified, saved, curline, numtext, numback,
9413 akron1 2360
                        comment, string, escape, num, delim, key1, key2, key3: INTEGER);
8728 leency 2361
BEGIN
2362
    colors.text := text;
2363
    colors.back := back;
2364
    colors.seltext := seltext;
2365
    colors.selback := selback;
2366
    colors.modified := modified;
2367
    colors.saved := saved;
2368
    colors.curline := curline;
2369
    colors.numtext := numtext;
2370
    colors.numback := numback;
2371
    colors.comment := comment;
2372
    colors.string  := string;
9413 akron1 2373
    colors.escape  := escape;
8728 leency 2374
    colors.num := num;
2375
    colors.delim := delim;
2376
    colors.key1 := key1;
2377
    colors.key2 := key2;
2378
    colors.key3 := key3;
2379
END setColors;
2380
 
2381
 
2382
PROCEDURE setCanvas* (Canvas: G.tCanvas);
2383
BEGIN
2384
    canvas := Canvas;
2385
    charWidth := canvas.font.width;
2386
    charHeight := canvas.font.height + inter
2387
END setCanvas;
2388
 
2389
 
2390
PROCEDURE resize* (width, height: INTEGER);
2391
BEGIN
2392
    size.X := width;
2393
    size.Y := height;
2394
    setPadding(padding.left, padding.top)
2395
END resize;
2396
 
2397
 
2398
PROCEDURE destroy* (VAR text: tText);
2399
BEGIN
2400
    IF search(text, "", FALSE, FALSE) THEN END;
9448 akron1 2401
    ChangeLog.destroy(text.chLog);
8728 leency 2402
    DISPOSE(text.foundList);
2403
    DISPOSE(text.cursor);
2404
    DISPOSE(text.select2);
2405
    DISPOSE(text)
2406
END destroy;
2407
 
2408
 
2409
PROCEDURE open* (name: RW.tFileName; VAR errno: INTEGER): tText;
2410
VAR
2411
    text: tText;
2412
    file: RW.tInput;
9180 akron1 2413
    n, enc, eol: INTEGER;
2414
    _eol: BOOLEAN;
8728 leency 2415
    line: tLine;
2416
BEGIN
2417
    errno := 0;
2418
    text := NIL;
9180 akron1 2419
    file := RW.load(name, enc, eol);
8728 leency 2420
    IF file # NIL THEN
2421
        text := create(name);
9336 akron1 2422
        ChangeLog.changeInt(text.enc, enc);
2423
        ChangeLog.changeInt(text.eol, eol);
8728 leency 2424
        text.enc := enc;
9180 akron1 2425
        text.eol := eol;
2426
        line := Lines.create(FALSE);
2427
        List._append(text, line);
8728 leency 2428
        REPEAT
9180 akron1 2429
            n := RW.getString(file, line, Lines.tabs, _eol);
2430
            IF _eol THEN
2431
            	line := Lines.create(FALSE);
2432
            	List._append(text, line)
8728 leency 2433
            END
9180 akron1 2434
        UNTIL ~_eol;
8728 leency 2435
        RW.destroy(file);
9180 akron1 2436
        text.curLine := text.first(tLine);
2437
        SetPos(text, 0, 0);
2438
        resetSelect(text)
8728 leency 2439
    ELSE
2440
        errno := 1
2441
    END;
9190 akron1 2442
    IF (text # NIL) & (text.lang # Lang.langText) THEN
8728 leency 2443
        Comments(text)
2444
    END
2445
    RETURN text
2446
END open;
2447
 
2448
 
2449
PROCEDURE findNext* (text: tText; prev: BOOLEAN): BOOLEAN;
2450
VAR
2451
    cursorPos, x, y, X, Y, Len: INTEGER;
2452
    p: Search.tPos;
2453
    line: tLine;
2454
    res: BOOLEAN;
2455
BEGIN
2456
    X := text.cursor.X;
2457
    Y := text.cursor.Y;
2458
    text.cursor.X := MIN(text.cursor.X, text.curLine.length);
2459
    cursorPos := text.curLine.pos + text.cursor.X - ORD(prev) - ORD(~prev & (text.foundSel = 0));
2460
    p := text.foundList.first(Search.tPos);
2461
    WHILE (p # NIL) & (p.pos <= cursorPos) DO
2462
        p := p.next(Search.tPos)
2463
    END;
2464
    IF prev THEN
2465
        IF p = NIL THEN
2466
            p := text.foundList.last(Search.tPos)
2467
        ELSE
2468
            p := p.prev(Search.tPos)
2469
        END
2470
    END;
2471
    res := p # NIL;
2472
    IF res THEN
2473
        y := 0;
2474
        line := text.first(tLine);
2475
        WHILE (line.pos <= p.pos) & (line.next # NIL) DO
2476
            NextLine(line);
2477
            INC(y)
2478
        END;
2479
        IF (line.next # NIL) OR (line.pos > p.pos) THEN
2480
            PrevLine(line);
2481
            DEC(y)
2482
        END;
2483
        resetSelect(text);
2484
        searchScroll(text, y);
2485
        x := p.pos - line.pos;
2486
        Len := LENGTH(text.searchText);
2487
        IF x + Len > text.scroll.X + textsize.X THEN
2488
            text.scroll.X := MAX(x + Len - textsize.X + 3, 0)
2489
        ELSIF x < text.scroll.X THEN
2490
            text.scroll.X := MAX(x - 3, 0)
2491
        END;
2492
        SetPos(text, x, y);
2493
        text.foundSel := Len
2494
    ELSE
2495
        SetPos(text, X, Y)
2496
    END
2497
    RETURN res
2498
END findNext;
2499
 
2500
 
2501
PROCEDURE rewrite (line: tLine; repl: ARRAY OF WCHAR; pos, n: INTEGER);
2502
BEGIN
2503
    IF n > 0 THEN
2504
        Lines.copy(line)
2505
    END;
2506
    WHILE n > 0 DO
2507
        DEC(n);
2508
        Lines.setChar(line, pos + n, repl[n])
2509
    END
2510
END rewrite;
2511
 
2512
 
2513
PROCEDURE replace* (text: tText; s: ARRAY OF WCHAR; n: INTEGER);
2514
VAR
2515
    line: tLine;
2516
    sLen, i: INTEGER;
2517
BEGIN
2518
    IF text.foundSel > 0 THEN
2519
        line := text.curLine;
2520
        sLen := LENGTH(s);
2521
        i := text.cursor.X;
2522
        IF sLen > n THEN
2523
            Lines.insert3(line, i, sLen - n)
2524
        END;
2525
        SetPos(text, i + sLen, text.cursor.Y);
2526
        rewrite(line, s, i, sLen);
2527
        IF n > sLen THEN
2528
            Lines.delCharN(line, text.cursor.X, n - sLen)
2529
        END;
2530
        resetSelect(text);
2531
        Lines.modify(line);
2532
        modify(text)
2533
    END
2534
END replace;
2535
 
2536
 
2537
PROCEDURE replaceAll* (text: tText; s: ARRAY OF WCHAR; n: INTEGER): INTEGER;
2538
VAR
2539
    p: Search.tPos;
2540
    line: tLine;
2541
    y, k, d, pos, y0: INTEGER;
2542
BEGIN
2543
    resetSelect(text);
2544
    SetPos(text, 0, 0);
2545
    line := text.first(tLine);
2546
    y := 0;
2547
    y0 := -1;
2548
    k := 0;
2549
    d := LENGTH(s) - n;
2550
    p := text.foundList.first(Search.tPos);
2551
    WHILE p # NIL DO
2552
        pos := p.pos;
2553
        WHILE (line.pos <= pos) & (line.next # NIL) DO
2554
            NextLine(line);
2555
            INC(y)
2556
        END;
2557
        IF (line.next # NIL) OR (line.pos > pos) THEN
2558
            PrevLine(line);
2559
            DEC(y)
2560
        END;
2561
        IF y = y0 THEN
2562
            INC(k, d)
2563
        ELSE
2564
            k := 0;
2565
            y0 := y
2566
        END;
2567
        SetPos(text, pos - line.pos + k, y);
2568
        text.foundSel := n;
2569
        replace(text, s, n);
2570
        p := p.next(Search.tPos)
2571
    END
2572
    RETURN text.foundList.count
2573
END replaceAll;
2574
 
2575
 
2576
PROCEDURE New* (): tText;
2577
VAR
2578
    text: tText;
2579
BEGIN
2580
    text := create("");
2581
    List._append(text, Lines.create(FALSE));
2582
    text.curLine := text.first(tLine);
9336 akron1 2583
    ChangeLog.changeInt(text.enc, E.CP866);
2584
    ChangeLog.changeInt(text.eol, RW.EOL_CRLF);
8728 leency 2585
    text.enc := E.CP866;
9180 akron1 2586
    text.eol := RW.EOL_CRLF;
8728 leency 2587
    SetPos(text, 0, 0);
2588
    resetSelect(text)
2589
    RETURN text
2590
END New;
2591
 
2592
 
2593
PROCEDURE init* (pShowCursor: tProcedure);
2594
BEGIN
9174 akron1 2595
    ShowCursor := pShowCursor;
8728 leency 2596
    pdelete := delete;
2597
    drawCursor := TRUE;
2598
    padding.left := pad_left;
2599
    padding.top := pad_top;
2600
END init;
2601
 
2602
 
2603
END Text.