DEADSOFTWARE

Port, TODO
[bbcp.git] / Trurl-based / Text / Mod / Cmds.txt
1 MODULE TextCmds;
3 (* THIS IS TEXT COPY OF BlackBox Text/Mod/Cmds.odc *)
4 (* DO NOT EDIT *)
6 (* could eliminate ReplList/ReplOp and use Models.Begin/EndScript instead (as already done for shifting) *)
7 (* move ListAlienViews to StdCmds and generalize accordingly? *)
10 IMPORT
11 Strings, Ports, Stores, Models, Views, Controllers, Properties, Dialog, Containers,
12 TextModels, TextMappers, TextRulers, TextSetters, TextViews, TextControllers;
14 CONST
15 (* ShiftOp.left *)
16 left = TRUE; right = FALSE;
18 (* PreparePat, FindPat *)
19 leftTerm = 3X; rightTerm = 4X;
21 (* DoReplace mode *)
22 replace = 0; replaceAndFind = 1; replaceAll = 2;
24 (* FindIn first *)
25 first = TRUE; again = FALSE;
27 mm = Ports.mm; point = Ports.point; maxPat = 256;
28 viewcode = TextModels.viewcode;
29 tab = TextModels.tab; line = TextModels.line; para = TextModels.para;
30 nbspace = TextModels.nbspace; digitspace = TextModels.digitspace;
31 hyphen = TextModels.hyphen;
32 nbhyphen = TextModels.nbhyphen; softhyphen = TextModels.softhyphen;
34 posKey = "#Text:Position";
35 searchAliensKey = "#Text:SearchForAlienViews"; (* dormant code option *)
36 alienTypeKey = "#Text:AlienViewType";
37 noAliensKey = "#Text:NoAlienViewsFound";
38 noRulerKey = "#Text:NoRulerSelected";
39 noMatchKey = "#Text:SelectionDoesNotMatch";
40 noTargetKey = "#Text:NoTargetFound";
41 noSelectionKey = "#Text:NoSelectionFound";
42 noPatternKey = "#Text:PatternNotSpecified";
43 notFoundKey = "#Text:PatternNotFound"; (* not used *)
44 replacingKey = "#System:Replacing";
45 shiftingKey = "#Text:Shifting";
46 showMarksKey = "#Text:ShowMarks";
47 hideMarksKey = "#Text:HideMarks";
48 replaceSelectionKey = "#Text:ReplaceAllInSelection";
49 replaceAllKey = "#Text:ReplaceAll";
52 TYPE
53 FindSpec = RECORD
54 valid, ignoreCase, wordBeginsWith, wordEndsWith, reverse: BOOLEAN;
55 start: INTEGER;
56 find: ARRAY maxPat OF CHAR
57 END;
59 ReplList = POINTER TO RECORD
60 next: ReplList;
61 beg, end: INTEGER;
62 buf: TextModels.Model
63 END;
65 ReplOp = POINTER TO RECORD (Stores.Operation)
66 text: TextModels.Model;
67 list, last: ReplList;
68 find: FindSpec
69 END;
72 VAR
73 find*: RECORD
74 find*: ARRAY maxPat OF CHAR;
75 replace*: ARRAY maxPat OF CHAR;
76 ignoreCase*, wordBeginsWith*, wordEndsWith*: BOOLEAN;
77 reverseOrientation*: BOOLEAN
78 END;
80 ruler*: RECORD
81 pageBreaks*: RECORD
82 notInside*, joinPara*: BOOLEAN
83 END
84 END;
87 PROCEDURE Show (t: TextModels.Model; beg, end: INTEGER);
88 BEGIN
89 TextViews.ShowRange(t, beg, end, TextViews.focusOnly);
90 IF beg = end THEN
91 TextControllers.SetCaret(t, beg)
92 ELSE
93 TextControllers.SetSelection(t, beg, end)
94 END
95 END Show;
97 PROCEDURE NoShow (t: TextModels.Model; pos: INTEGER);
98 BEGIN
99 TextControllers.SetSelection(t, pos, pos);
100 TextControllers.SetCaret(t, pos)
101 END NoShow;
103 PROCEDURE Ruler (): TextRulers.Ruler;
104 VAR r: TextRulers.Ruler;
105 BEGIN
106 r := TextRulers.dir.New(NIL);
107 TextRulers.AddTab(r, 4*mm); TextRulers.AddTab(r, 20*mm);
108 RETURN r
109 END Ruler;
112 (* search & replace *)
114 PROCEDURE LeftTerminator (ch: CHAR): BOOLEAN;
115 BEGIN
116 IF ch < 100X THEN
117 CASE ch OF
118 viewcode, tab, line, para, " ",
119 "(", "[", "{", "=",
120 hyphen, softhyphen: RETURN TRUE
121 ELSE RETURN FALSE
122 END
123 ELSE RETURN TRUE
124 END
125 END LeftTerminator;
127 PROCEDURE RightTerminator (ch: CHAR): BOOLEAN;
128 BEGIN
129 IF ch < 100X THEN
130 CASE ch OF
131 0X, viewcode, tab, line, para, " ",
132 "!", "(", ")", ",", ".", ":", ";", "?", "[", "]", "{", "}",
133 hyphen, softhyphen: RETURN TRUE
134 ELSE RETURN FALSE
135 END
136 ELSE RETURN TRUE
137 END
138 END RightTerminator;
140 PROCEDURE PreparePat (spec: FindSpec;
141 VAR pat: ARRAY OF CHAR; VAR n: INTEGER;
142 VAR wordBeg, wordEnd: BOOLEAN);
143 VAR i: INTEGER; ch: CHAR;
144 BEGIN
145 i := 0; ch := spec.find[0];
146 wordBeg := spec.wordBeginsWith & ~LeftTerminator(ch);
147 IF wordBeg THEN pat[0] := leftTerm; n := 1 ELSE n := 0 END;
148 WHILE ch # 0X DO
149 IF ch # softhyphen THEN
150 IF spec.ignoreCase THEN pat[n] := Strings.Upper(ch) ELSE pat[n] := ch END;
151 INC(n)
152 END;
153 INC(i); ch := spec.find[i]
154 END;
155 wordEnd := spec.wordEndsWith & ~RightTerminator(pat[n - 1]);
156 IF wordEnd THEN pat[n] := rightTerm; INC(n) END
157 END PreparePat;
159 PROCEDURE FindPat (t: TextModels.Model; spec: FindSpec; VAR beg, end: INTEGER);
160 (* post: beg < end => t[beg, end) = spec.find, start <= beg; else beg = end *)
161 VAR r: TextModels.Reader; start: INTEGER;
162 i, j, b, e, n: INTEGER; ch0, ch, ch1: CHAR; wordBeg, wordEnd, icase: BOOLEAN;
163 pat, ref: ARRAY maxPat OF CHAR; (* ref [b..e) is readback buffer *)
164 pos0, pos1, absStart: INTEGER;
165 orientation: INTEGER;
166 BEGIN
167 IF spec.reverse THEN
168 orientation := -1; absStart := t.Length();
169 PreparePat(spec, ref, n, wordEnd, wordBeg);
170 i := n; j := 0; REPEAT DEC(i); pat[j] := ref[i]; INC(j) UNTIL i = 0 (* Just reverse the pattern... *)
171 ELSE
172 orientation := 1; absStart := 0;
173 PreparePat(spec, pat, n, wordBeg, wordEnd)
174 END;
175 start := spec.start; icase := spec.ignoreCase;
176 r := t.NewReader(NIL); i := 0;
177 IF wordBeg THEN
178 IF start # absStart THEN
179 DEC(start, orientation)
180 ELSE
181 r.SetPos(absStart);
182 IF spec.reverse THEN r.ReadPrevChar(ch) ELSE r.ReadChar(ch) END;
183 IF ~LeftTerminator(ch) THEN i := 1 END
184 END
185 END;
186 r.SetPos(start); IF spec.reverse THEN r.ReadPrevChar(ch) ELSE r.ReadChar(ch) END;
187 pos0 := start; pos1 := start;
188 IF icase THEN ch := Strings.Upper(ch) END;
189 ref[0] := ch; ch0 := ch; j := 0; b := 0; e := 1;
190 WHILE ~r.eot & (i < n) DO
191 ch1 := pat[i];
192 IF (ch1 = ch)
193 OR (ch1 = leftTerm) & LeftTerminator(ch)
194 OR (ch1 = rightTerm) & RightTerminator(ch) THEN
195 INC(i); j := (j + 1) MOD maxPat
196 ELSIF ch = softhyphen THEN
197 j := (j + 1) MOD maxPat
198 ELSE
199 i := 0; INC(pos0, orientation); b := (b + 1) MOD maxPat; j := b
200 END;
201 IF j # e THEN
202 ch := ref[j]
203 ELSE
204 INC(pos1, orientation);
205 IF spec.reverse THEN r.ReadPrevChar(ch) ELSE r.ReadChar(ch) END;
206 IF icase THEN ch := Strings.Upper(ch) END;
207 ref[j] := ch; e := (e + 1) MOD maxPat
208 END
209 END;
210 IF wordEnd & ~((i + 1 = n) & r.eot) THEN DEC(pos1, orientation) END;
211 IF (n > 0) & ((i = n) OR wordEnd & (i + 1 = n) & r.eot) THEN
212 IF wordBeg & ((pos0 # absStart) OR LeftTerminator(ch0)) THEN INC(pos0, orientation) END
213 ELSE
214 pos0 := pos1
215 END;
216 IF spec.reverse THEN
217 beg := pos1; end := pos0
218 ELSE
219 beg := pos0; end := pos1
220 END
221 END FindPat;
223 PROCEDURE OverrideSpecWithOption (VAR spec: FindSpec; option: ARRAY OF CHAR);
224 VAR i: INTEGER; choice: BOOLEAN; ch: CHAR;
225 BEGIN
226 choice := TRUE; i := 0; ch := option[i];
227 WHILE ch # 0X DO
228 CASE option[i] OF
229 '~': choice := ~choice
230 | 'I', 'i': spec.ignoreCase := choice; choice := TRUE
231 | 'B', 'b': spec.wordBeginsWith := choice; choice := TRUE
232 | 'E', 'e': spec.wordEndsWith := choice; choice := TRUE
233 | 'R', 'r': spec.reverse := choice; choice := TRUE
234 ELSE choice := TRUE
235 END;
236 INC(i); ch := option[i]
237 END
238 END OverrideSpecWithOption;
240 PROCEDURE SetSpec (VAR spec: FindSpec; pos0, pos1: INTEGER; option: ARRAY OF CHAR);
241 BEGIN
242 ASSERT(find.find # "", 20);
243 spec.valid := TRUE;
244 spec.ignoreCase := find.ignoreCase;
245 spec.wordBeginsWith := find.wordBeginsWith;
246 spec.wordEndsWith := find.wordEndsWith;
247 spec.reverse := find.reverseOrientation;
248 OverrideSpecWithOption(spec, option);
249 IF spec.reverse THEN spec.start := pos1
250 ELSE spec.start := pos0
251 END;
252 spec.find := find.find$
253 END SetSpec;
255 PROCEDURE SetFindSpec (c: TextControllers.Controller; first: BOOLEAN; option: ARRAY OF CHAR;
256 VAR spec: FindSpec
257 );
258 VAR (*start,*) pos0, pos1, beg, end: INTEGER;
259 BEGIN
260 IF first THEN pos0 := 0; pos1 := pos0
261 ELSIF c.HasCaret() THEN pos0 := c.CaretPos(); pos1 := pos0
262 ELSIF c.HasSelection() THEN c.GetSelection(beg, end); pos0 := beg + 1; pos1 := end - 1
263 ELSE pos0 := 0; pos1 := pos0
264 END;
265 SetSpec(spec, pos0, pos1, option);
266 IF spec.reverse THEN
267 IF spec.start = 0 THEN spec.start := c.text.Length() END
268 ELSE
269 IF spec.start = c.text.Length() THEN spec.start := 0 END
270 END
271 END SetFindSpec;
274 PROCEDURE ReplBuf (target: TextModels.Model; pos: INTEGER): TextModels.Model;
275 VAR buf: TextModels.Model; attr: TextModels.Attributes; rd: TextModels.Reader;
276 out: TextModels.Writer; i: INTEGER;
277 BEGIN
278 rd := target.NewReader(NIL); rd.SetPos(pos); rd.ReadRun(attr);
279 buf := TextModels.CloneOf(target); out := buf.NewWriter(NIL); out.SetPos(0);
280 IF attr # NIL THEN out.SetAttr(attr) END;
281 i := 0; WHILE find.replace[i] # 0X DO out.WriteChar(find.replace[i]); INC(i) END;
282 RETURN buf
283 END ReplBuf;
286 (* operations *)
288 PROCEDURE (op: ReplOp) Do;
289 VAR u, v: ReplList; text, save: TextModels.Model; beg, end, delta, len: INTEGER;
290 BEGIN
291 text := op.text;
292 u := op.list; v := NIL; delta := 0;
293 WHILE u # NIL DO
294 INC(u.beg, delta); INC(u.end, delta);
295 IF u.end > u.beg THEN
296 save := TextModels.CloneOf(text); save.Insert(0, text, u.beg, u.end);
297 DEC(delta, u.end - u.beg)
298 ELSE
299 save := NIL
300 END;
301 IF u.buf # NIL THEN
302 len := u.buf.Length();
303 text.Insert(u.beg, u.buf, 0, len);
304 u.end := u.beg + len;
305 INC(delta, len)
306 ELSE
307 u.end := u.beg
308 END;
309 u.buf := save;
310 v := u; u := u.next
311 END;
312 IF op.find.valid THEN
313 FindPat(text, op.find, beg, end); op.find.valid := FALSE;
314 IF beg = end THEN Dialog.Beep END
315 ELSIF v # NIL THEN
316 beg := v.beg; end := v.end
317 ELSE
318 beg := 0; end := 0
319 END;
320 IF end > beg THEN Show(text, beg, end) ELSE NoShow(text, beg) END
321 END Do;
323 PROCEDURE AddRepl (op: ReplOp; beg, end: INTEGER; reverse: BOOLEAN);
324 VAR u: ReplList;
325 BEGIN
326 NEW(u); u.beg := beg; u.end := end; u.buf := ReplBuf(op.text, beg);
327 IF reverse THEN (* append *)
328 u.next := op.list; op.list := u
329 ELSE (* prepend *)
330 IF op.list = NIL THEN op.list := u ELSE op.last.next := u END;
331 op.last := u
332 END
333 END AddRepl;
335 PROCEDURE DoReplaceThis (
336 t: TextModels.Model; mode: INTEGER;
337 firstBeg, firstEnd: INTEGER;
338 rngBeg, rngEnd: INTEGER;
339 option: ARRAY OF CHAR
340 );
341 VAR op: ReplOp; spec: FindSpec; beg, end, len: INTEGER;
342 BEGIN
343 NEW(op); op.text := t; op.list := NIL;
344 beg := firstBeg; end := firstEnd;
345 IF mode IN {replace, replaceAndFind} THEN
346 AddRepl(op, firstBeg, firstEnd, spec.reverse)
347 END;
348 IF mode = replaceAndFind THEN
349 SetSpec(op.find, firstBeg + (* LEN(find.replace$) *) ReplBuf(t, 0).Length(), firstBeg, option)
350 ELSE
351 op.find.valid := FALSE
352 END;
353 IF mode = replaceAll THEN
354 len := LEN(find.find$);
355 SetSpec(spec, 0, t.Length(), option);
356 WHILE (rngBeg <= beg) & (beg < end) & (end <= rngEnd) DO
357 AddRepl(op, beg, end, spec.reverse);
358 IF spec.reverse THEN spec.start := beg ELSE spec.start := beg + len END;
359 FindPat(t, spec, beg, end)
360 END
361 END;
362 Models.Do(t, replacingKey, op)
363 END DoReplaceThis;
365 PROCEDURE DoReplace (c: TextControllers.Controller; mode: INTEGER; option: ARRAY OF CHAR);
366 VAR t: TextModels.Model; spec: FindSpec;
367 selBeg, selEnd, beg, end, len0: INTEGER; hasSel0: BOOLEAN;
368 BEGIN
369 IF c # NIL THEN
370 t := c.text; len0 := t.Length(); hasSel0 := c.HasSelection();
371 IF hasSel0 THEN
372 c.GetSelection(selBeg, selEnd);
373 IF selEnd < len0 THEN
374 SetSpec(spec, selBeg, selEnd + 1, option)
375 ELSE SetSpec(spec, selBeg, selEnd, option)
376 END
377 ELSE
378 selBeg := 0; selEnd := len0;
379 SetFindSpec(c, (* again *) mode = replaceAll, option, spec)
380 END;
381 FindPat(t, spec, beg, end);
382 IF mode = replaceAll THEN
383 IF (selBeg <= beg) & (beg < end) & (end <= selEnd) THEN
384 DoReplaceThis(t, mode, beg, end, selBeg, selEnd, option);
385 IF hasSel0 THEN Show(c.text, selBeg, selEnd + t.Length() - len0) END
386 ELSE NoShow(c.text, 0); Dialog.Beep
387 END
388 ELSIF hasSel0 THEN
389 IF (beg = selBeg) & (end = selEnd) THEN
390 DoReplaceThis(t, mode, selBeg, selEnd, 0, len0, option)
391 ELSE Dialog.ShowParamMsg(noMatchKey, spec.find, "", "")
392 END
393 ELSE Dialog.ShowMsg(noSelectionKey)
394 END
395 ELSE Dialog.ShowMsg(noTargetKey)
396 END
397 END DoReplace;
399 PROCEDURE DoShift (c: TextControllers.Controller; left: BOOLEAN);
400 VAR script: Stores.Operation;
401 t: TextModels.Model; st: TextSetters.Setter;
402 rd: TextModels.Reader; wr: TextModels.Writer;
403 box: TextSetters.LineBox; beg, pos, end: INTEGER; ch: CHAR;
404 BEGIN
405 IF (c # NIL) & (c.HasSelection() OR c.HasCaret()) THEN
406 t := c.text;
407 IF c.HasSelection() THEN c.GetSelection(beg, end) ELSE beg := c.CaretPos(); end := beg END;
408 st := c.view.ThisSetter(); beg := st.ThisSequence(beg); pos := beg;
409 rd := t.NewReader(NIL); rd.SetPos(pos);
410 IF ~left THEN wr := t.NewWriter(NIL) END;
411 Models.BeginScript(t, shiftingKey, script);
412 REPEAT
413 rd.ReadChar(ch);
414 IF rd.view # NIL THEN
415 st.GetLine(pos, box);
416 IF box.rbox THEN ch := para END
417 END;
418 IF left & ((ch = tab) OR (ch = " ") OR (ch = digitspace) OR (ch = nbspace)) THEN
419 t.Delete(pos, pos + 1); rd.SetPos(pos); DEC(end)
420 ELSIF ~left & (ch # line) & (ch # para) THEN
421 wr.SetPos(pos);
422 IF (ch = " ") OR (ch = digitspace) OR (ch = nbspace) THEN
423 wr.WriteChar(ch)
424 ELSE wr.WriteChar(tab)
425 END;
426 INC(pos); INC(end)
427 ELSE INC(pos)
428 END;
429 WHILE ~rd.eot & (ch # line) & (ch # para) DO
430 INC(pos); rd.ReadChar(ch)
431 END
432 UNTIL rd.eot OR (pos >= end);
433 Models.EndScript(t, script);
434 IF end > beg THEN TextControllers.SetSelection(t, beg, end) END
435 END
436 END DoShift;
438 (** commands **)
440 PROCEDURE ListAlienViews*;
441 VAR t: TextModels.Model; v: TextViews.View; wr: TextMappers.Formatter;
442 rd: TextModels.Reader; view: Views.View;
443 type: Stores.TypeName; none: BOOLEAN;
444 BEGIN
445 t := TextViews.FocusText();
446 IF t # NIL THEN
447 wr.ConnectTo(TextModels.dir.New());
448 rd := t.NewReader(NIL); rd.ReadView(view); none := TRUE;
449 WHILE view # NIL DO
450 IF view IS Views.Alien THEN
451 IF none THEN
452 wr.WriteTab; wr.WriteMsg(posKey);
453 wr.WriteTab; wr.WriteMsg(alienTypeKey); wr.WriteLn
454 END;
455 none := FALSE;
456 type := view(Views.Alien).store.path[0]$;
457 wr.WriteTab;
458 wr.WriteIntForm(rd.Pos() - 1,
459 TextMappers.decimal, 5, nbspace, TextMappers.hideBase);
460 wr.WriteTab; wr.WriteString(type); wr.WriteLn
461 END;
462 rd.ReadView(view)
463 END;
464 IF none THEN wr.WriteString(noAliensKey); wr.WriteLn END;
465 v := TextViews.dir.New(wr.rider.Base());
466 v.SetDefaults(Ruler(), TextViews.dir.defAttr);
467 Views.OpenView(v)
468 END
469 END ListAlienViews;
472 PROCEDURE ToggleMarksGuard* (VAR par: Dialog.Par);
473 VAR v: TextViews.View;
474 BEGIN
475 v := TextViews.Focus();
476 IF (v # NIL) & v.HidesMarks() THEN par.label := showMarksKey
477 ELSE par.label := hideMarksKey
478 END
479 END ToggleMarksGuard;
481 PROCEDURE ToggleMarks*;
482 VAR v: TextViews.View;
483 BEGIN
484 v := TextViews.Focus();
485 IF v # NIL THEN v.DisplayMarks(~v.HidesMarks()) END
486 END ToggleMarks;
488 PROCEDURE ShowMarks*;
489 VAR v: TextViews.View;
490 BEGIN
491 v := TextViews.Focus();
492 IF (v # NIL) & v.HidesMarks() THEN v.DisplayMarks(TextViews.show) END
493 END ShowMarks;
495 PROCEDURE HideMarks*;
496 VAR v: TextViews.View;
497 BEGIN
498 v := TextViews.Focus();
499 IF (v # NIL) & ~v.HidesMarks() THEN v.DisplayMarks(TextViews.hide) END
500 END HideMarks;
502 PROCEDURE MakeDefaultRulerGuard* (VAR par: Dialog.Par);
503 VAR c: TextControllers.Controller; v: Views.View;
504 BEGIN
505 c := TextControllers.Focus();
506 IF c # NIL THEN
507 v := c.Singleton();
508 IF (v = NIL) OR ~(v IS TextRulers.Ruler) THEN par.disabled := TRUE END
509 ELSE par.disabled := TRUE
510 END
511 END MakeDefaultRulerGuard;
513 PROCEDURE MakeDefaultRuler*;
514 VAR c: TextControllers.Controller; rd: TextModels.Reader;
515 r: TextRulers.Ruler; a: TextModels.Attributes;
516 beg, end: INTEGER;
517 BEGIN
518 c := TextControllers.Focus();
519 IF c # NIL THEN
520 IF c.HasSelection() THEN
521 c.GetSelection(beg, end);
522 rd := c.text.NewReader(NIL); rd.SetPos(beg); rd.Read;
523 IF (rd.view # NIL) & (rd.view IS TextRulers.Ruler) THEN
524 c.view.PollDefaults(r, a);
525 c.view.SetDefaults(rd.view(TextRulers.Ruler), a)
526 ELSE Dialog.ShowMsg(noRulerKey)
527 END
528 ELSE Dialog.ShowMsg(noSelectionKey)
529 END
530 ELSE Dialog.ShowMsg(noTargetKey)
531 END
532 END MakeDefaultRuler;
534 PROCEDURE MakeDefaultAttributes*;
535 VAR c: TextControllers.Controller; rd: TextModels.Reader;
536 r: TextRulers.Ruler; a: TextModels.Attributes;
537 beg, end: INTEGER;
538 BEGIN
539 c := TextControllers.Focus();
540 IF c # NIL THEN
541 IF c.HasSelection() THEN
542 c.GetSelection(beg, end);
543 rd := c.text.NewReader(NIL); rd.SetPos(beg); rd.Read;
544 c.view.PollDefaults(r, a);
545 c.view.SetDefaults(r, rd.attr)
546 ELSE Dialog.ShowMsg(noSelectionKey)
547 END
548 ELSE Dialog.ShowMsg(noTargetKey)
549 END
550 END MakeDefaultAttributes;
552 PROCEDURE ShiftLeft*;
553 BEGIN
554 DoShift(TextControllers.Focus(), left)
555 END ShiftLeft;
557 PROCEDURE ShiftRight*;
558 BEGIN
559 DoShift(TextControllers.Focus(), right)
560 END ShiftRight;
563 PROCEDURE Subscript*;
564 VAR q, p0: Properties.Property; p: TextModels.Prop;
565 BEGIN
566 Properties.CollectProp(q);
567 p0 := q; WHILE (p0 # NIL) & ~(p0 IS TextModels.Prop) DO p0 := p0.next END;
568 NEW(p); p.valid := {TextModels.offset};
569 IF (p0 # NIL) & (TextModels.offset IN p0.valid) THEN
570 p.offset := p0(TextModels.Prop).offset - point
571 ELSE p.offset := -point
572 END;
573 Properties.EmitProp(NIL, p)
574 END Subscript;
576 PROCEDURE Superscript*;
577 VAR q, p0: Properties.Property; p: TextModels.Prop;
578 BEGIN
579 Properties.CollectProp(q);
580 p0 := q; WHILE (p0 # NIL) & ~(p0 IS TextModels.Prop) DO p0 := p0.next END;
581 NEW(p); p.valid := {TextModels.offset};
582 IF (p0 # NIL) & (TextModels.offset IN p0.valid) THEN
583 p.offset := p0(TextModels.Prop).offset + point
584 ELSE p.offset := point
585 END;
586 Properties.EmitProp(NIL, p)
587 END Superscript;
590 PROCEDURE ForceToNewLine (c: TextControllers.Controller);
591 VAR st: TextSetters.Setter; pos, start: INTEGER; msg: Controllers.EditMsg;
592 BEGIN
593 IF c.HasCaret() THEN
594 pos := c.CaretPos();
595 st := c.view.ThisSetter(); start := st.ThisLine(pos);
596 IF pos # start THEN
597 msg.op := Controllers.pasteChar; msg.char := line;
598 Controllers.Forward(msg)
599 END
600 END
601 END ForceToNewLine;
603 PROCEDURE InsertParagraph*;
604 VAR c: TextControllers.Controller; script: Stores.Operation; msg: Controllers.EditMsg;
605 BEGIN
606 c := TextControllers.Focus();
607 IF c # NIL THEN
608 Models.BeginScript(c.text, "#Text:InsertParagraph", script);
609 ForceToNewLine(c);
610 msg.op := Controllers.pasteChar; msg.char := para;
611 Controllers.Forward(msg);
612 Models.EndScript(c.text, script)
613 END
614 END InsertParagraph;
616 PROCEDURE InsertRuler*;
617 VAR c: TextControllers.Controller; script: Stores.Operation;
618 rd: TextModels.Reader; r: TextRulers.Ruler;
619 pos, end: INTEGER;
620 BEGIN
621 c := TextControllers.Focus();
622 IF c # NIL THEN
623 r := NIL;
624 IF c.HasSelection() THEN
625 c.GetSelection(pos, end);
626 rd := c.text.NewReader(NIL); rd.SetPos(pos); rd.Read;
627 IF (rd.view # NIL) & (rd.view IS TextRulers.Ruler) THEN
628 r := rd.view(TextRulers.Ruler)
629 END
630 ELSE pos := c.CaretPos()
631 END;
632 IF r = NIL THEN r := TextViews.ThisRuler(c.view, pos) END;
633 r := TextRulers.CopyOf(r, Views.deep);
634 Models.BeginScript(c.text, "#Text:InsertRuler", script);
635 ForceToNewLine(c);
636 c.view.DisplayMarks(TextViews.show);
637 Controllers.PasteView(r, Views.undefined, Views.undefined, FALSE);
638 Models.EndScript(c.text, script)
639 END
640 END InsertRuler;
642 PROCEDURE InsertSoftHyphen*;
643 VAR msg: Controllers.EditMsg;
644 BEGIN
645 msg.op := Controllers.pasteChar; msg.char := softhyphen;
646 Controllers.Forward(msg)
647 END InsertSoftHyphen;
649 PROCEDURE InsertNBHyphen*;
650 VAR msg: Controllers.EditMsg;
651 BEGIN
652 msg.op := Controllers.pasteChar; msg.char := nbhyphen;
653 Controllers.Forward(msg)
654 END InsertNBHyphen;
656 PROCEDURE InsertNBSpace*;
657 VAR msg: Controllers.EditMsg;
658 BEGIN
659 msg.op := Controllers.pasteChar; msg.char := nbspace;
660 Controllers.Forward(msg)
661 END InsertNBSpace;
663 PROCEDURE InsertDigitSpace*;
664 VAR msg: Controllers.EditMsg;
665 BEGIN
666 msg.op := Controllers.pasteChar; msg.char := digitspace;
667 Controllers.Forward(msg)
668 END InsertDigitSpace;
671 PROCEDURE GetFindPattern (c: TextControllers.Controller);
672 VAR r: TextModels.Reader; beg, end: INTEGER; i: INTEGER; ch: CHAR;
673 new: ARRAY maxPat OF CHAR;
674 BEGIN
675 IF (c # NIL) & c.HasSelection() THEN
676 c.GetSelection(beg, end);
677 r := c.text.NewReader(NIL); r.SetPos(beg); r.ReadChar(ch); i := 0;
678 WHILE (r.Pos() <= end) & (i < maxPat - 1) DO
679 new[i] := ch; INC(i); r.ReadChar(ch)
680 END;
681 new[i] := 0X;
682 IF (new # "") & (new # find.find) THEN
683 find.find := new$;
684 find.ignoreCase := FALSE;
685 find.wordBeginsWith := FALSE; find.wordEndsWith := FALSE;
686 Dialog.Update(find)
687 END
688 END
689 END GetFindPattern;
691 PROCEDURE FindIn (c: TextControllers.Controller; first: BOOLEAN; option: ARRAY OF CHAR);
692 VAR spec: FindSpec; beg, end: INTEGER;
693 BEGIN
694 IF c # NIL THEN
695 IF find.find # "" THEN
696 SetFindSpec(c, first, option, spec);
697 FindPat(c.text, spec, beg, end);
698 IF end > beg THEN Show(c.text, beg, end) ELSE NoShow(c.text, 0); Dialog.Beep END
699 ELSE Dialog.ShowMsg(noPatternKey)
700 END
701 ELSE Dialog.ShowMsg(noTargetKey)
702 END
703 END FindIn;
706 PROCEDURE FindGuard* (VAR par: Dialog.Par);
707 VAR c: TextControllers.Controller;
708 BEGIN
709 c := TextControllers.Focus();
710 IF (c = NIL) OR (find.find = "") THEN par.disabled := TRUE END
711 END FindGuard;
713 PROCEDURE FindFirst* (option: ARRAY OF CHAR);
714 BEGIN
715 FindIn(TextControllers.Focus(), first, option)
716 END FindFirst;
718 PROCEDURE FindAgainGuard* (VAR par: Dialog.Par);
719 VAR c: TextControllers.Controller;
720 BEGIN
721 c := TextControllers.Focus();
722 IF (c = NIL) OR (~c.HasSelection() & (find.find = "")) THEN par.disabled := TRUE END
723 END FindAgainGuard;
725 PROCEDURE FindAgain* (option: ARRAY OF CHAR);
726 BEGIN
727 FindIn(TextControllers.Focus(), again, option)
728 END FindAgain;
731 PROCEDURE ReplaceGuard* (VAR par: Dialog.Par);
732 VAR c: TextControllers.Controller;
733 BEGIN
734 c := TextControllers.Focus();
735 IF (c = NIL) OR (Containers.noCaret IN c.opts) OR ~c.HasSelection() OR (find.find = "") THEN
736 par.disabled := TRUE
737 END
738 END ReplaceGuard;
740 PROCEDURE Replace* (option: ARRAY OF CHAR);
741 BEGIN
742 DoReplace(TextControllers.Focus(), replace, option)
743 END Replace;
745 PROCEDURE ReplaceAndFindNext* (option: ARRAY OF CHAR);
746 BEGIN
747 DoReplace(TextControllers.Focus(), replaceAndFind, option)
748 END ReplaceAndFindNext;
751 PROCEDURE ReplaceAllGuard* (VAR par: Dialog.Par);
752 VAR c: TextControllers.Controller;
753 BEGIN
754 c := TextControllers.Focus();
755 IF (c = NIL) OR (Containers.noCaret IN c.opts) OR (find.find = "") THEN
756 par.disabled := TRUE
757 ELSE
758 IF c.HasSelection() THEN par.label := replaceSelectionKey ELSE par.label := replaceAllKey END
759 END
760 END ReplaceAllGuard;
762 PROCEDURE ReplaceAll* (option: ARRAY OF CHAR);
763 BEGIN
764 DoReplace(TextControllers.Focus(), replaceAll, option)
765 END ReplaceAll;
768 PROCEDURE SetNormalOrientation*;
769 BEGIN
770 find.reverseOrientation := FALSE;
771 Dialog.Update(find)
772 END SetNormalOrientation;
774 PROCEDURE SetReverseOrientation*;
775 BEGIN
776 find.reverseOrientation := TRUE;
777 Dialog.Update(find)
778 END SetReverseOrientation;
780 PROCEDURE InitFindDialog*;
781 BEGIN
782 GetFindPattern(TextControllers.Focus())
783 END InitFindDialog;
786 (** ruler dialog **)
788 PROCEDURE InitRulerDialog*;
789 VAR v: Views.View; ra: TextRulers.Attributes;
790 BEGIN
791 v := Controllers.FocusView();
792 IF v # NIL THEN
793 WITH v: TextRulers.Ruler DO
794 ra := v.style.attr;
795 ruler.pageBreaks.notInside := TextRulers.noBreakInside IN ra.opts;
796 ruler.pageBreaks.joinPara := TextRulers.parJoin IN ra.opts
797 ELSE
798 END
799 END
800 END InitRulerDialog;
802 PROCEDURE SetRuler*;
803 VAR v: Views.View; p: TextRulers.Prop;
804 BEGIN
805 v := Controllers.FocusView();
806 IF v # NIL THEN
807 WITH v: TextRulers.Ruler DO
808 NEW(p); p.valid := {TextRulers.opts};
809 p.opts.mask := {TextRulers.noBreakInside, TextRulers.parJoin};
810 p.opts.val := {};
811 IF ruler.pageBreaks.notInside THEN INCL(p.opts.val, TextRulers.noBreakInside) END;
812 IF ruler.pageBreaks.joinPara THEN INCL(p.opts.val, TextRulers.parJoin) END;
813 Properties.EmitProp(NIL, p)
814 ELSE
815 END
816 END
817 END SetRuler;
820 (** standard text-related guards **)
822 PROCEDURE FocusGuard* (VAR par: Dialog.Par);
823 (** in non-TextView menus; otherwise implied by menu type **)
824 BEGIN
825 IF TextViews.Focus() = NIL THEN par.disabled := TRUE END
826 END FocusGuard;
828 PROCEDURE EditGuard* (VAR par: Dialog.Par);
829 (** in non-TextView menus; otherwise use "StdCmds.EditGuard" **)
830 VAR c: TextControllers.Controller;
831 BEGIN
832 c := TextControllers.Focus();
833 IF (c = NIL) OR (Containers.noCaret IN c.opts) THEN par.disabled := TRUE END
834 END EditGuard;
836 PROCEDURE SelectionGuard* (VAR par: Dialog.Par);
837 (** in non-TextView menus; otherwise use "StdCmds.SelectionGuard" **)
838 VAR c: TextControllers.Controller;
839 BEGIN
840 c := TextControllers.Focus();
841 IF (c = NIL) OR ~c.HasSelection() THEN par.disabled := TRUE END
842 END SelectionGuard;
844 PROCEDURE EditSelectionGuard* (VAR par: Dialog.Par);
845 (** in non-TextView menus; otherwise use "StdCmds.SelectionGuard" **)
846 VAR c: TextControllers.Controller;
847 BEGIN
848 c := TextControllers.Focus();
849 IF (c = NIL) OR (Containers.noCaret IN c.opts) OR ~c.HasSelection() THEN par.disabled := TRUE END
850 END EditSelectionGuard;
852 PROCEDURE SingletonGuard* (VAR par: Dialog.Par);
853 (** in non-TextView menus; otherwise use "StdCmds.SingletonGuard" **)
854 VAR c: TextControllers.Controller;
855 BEGIN
856 c := TextControllers.Focus();
857 IF (c = NIL) OR (c.Singleton() = NIL) THEN par.disabled := TRUE END
858 END SingletonGuard;
860 END TextCmds.