Subversion Repositories Kolibri OS

Rev

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