home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #6 / amigamamagazinepolishissue1998.iso / coders / jËzyki_programowania / oberon / system / edittools.mod (.txt) < prev    next >
Oberon Text  |  1977-12-31  |  31KB  |  734 lines

  1. Syntax10.Scn.Fnt
  2. Syntax12.Scn.Fnt
  3. Syntax10b.Scn.Fnt
  4. Syntax10i.Scn.Fnt
  5. Syntax8.Scn.Fnt
  6. MODULE EditTools;    (** CAS/HM 26 Aug 94 **)
  7.     IMPORT
  8.         Files, Fonts, Modules, Texts, Viewers, Oberon, MenuViewers, TextFrames, ParcElems, Display;
  9.     CONST
  10.         mm = TextFrames.mm; MonsterW = 250*mm; MonsterH = 200*mm; TAB = 9X; CR = 0DX;
  11.         elem = 0; fnt = 1; col = 2; voff = 3;
  12.         OptionChar = "\";
  13.     TYPE
  14.         Node = POINTER TO NodeDesc;
  15.         NodeDesc = RECORD
  16.             l, r: Node;
  17.             mod: ARRAY 32 OF CHAR;
  18.             fnt: Fonts.Font;
  19.             col, voff: SHORTINT
  20.         END;
  21.         W, WR: Texts.Writer;
  22.         lastTime: LONGINT;
  23.         search: RECORD
  24.             set: SET;
  25.             node: Node
  26.         END;
  27.     (* output primitives *)
  28.     PROCEDURE Ch (ch: CHAR);
  29.     BEGIN Texts.Write(W, ch)
  30.     END Ch;
  31.     PROCEDURE Str (s: ARRAY OF CHAR);
  32.     BEGIN Texts.WriteString(W, s)
  33.     END Str;
  34.     PROCEDURE Int (n: LONGINT);
  35.     BEGIN Ch(" "); Texts.WriteInt(W, n, 0)
  36.     END Int;
  37.     PROCEDURE Ln;
  38.     BEGIN Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf)
  39.     END Ln;
  40.     PROCEDURE Plural (n: LONGINT; s: ARRAY OF CHAR);
  41.     BEGIN Int(n); Ch(" "); Str(s);
  42.         IF n # 1 THEN Ch("s") END
  43.     END Plural;
  44.     (* generic frame primitives *)
  45.     PROCEDURE Unmark (f: TextFrames.Frame);
  46.         VAR m: Oberon.ControlMsg;
  47.     BEGIN Oberon.RemoveMarks(f.X, f.Y, f.W, f.H); m.id := Oberon.neutralize; f.handle(f, m)
  48.     END Unmark;
  49.     PROCEDURE Show (f: TextFrames.Frame; pos: LONGINT);
  50.         VAR F: TextFrames.Frame; beg, end, delta: LONGINT;
  51.     BEGIN delta := 200; Unmark(f);
  52.         LOOP beg := f.org; end := TextFrames.Pos(f, f.X + f.W, f.Y);
  53.             IF (beg <= pos) & (pos < end) OR (delta = 0) THEN EXIT END;
  54.             TextFrames.Show(f, pos - delta); delta := delta DIV 2
  55.         END
  56.     END Show;
  57.     (* argument primitives *)
  58.     PROCEDURE HoldsTF (V: Viewers.Viewer): BOOLEAN;
  59.     BEGIN
  60.         RETURN (V IS MenuViewers.Viewer) & (V.dsc.next IS TextFrames.Frame)
  61.     END HoldsTF;
  62.     PROCEDURE MarkedFrame (): TextFrames.Frame;
  63.         VAR V: Viewers.Viewer;
  64.     BEGIN V := Oberon.MarkedViewer();
  65.         IF HoldsTF(V) THEN RETURN V.dsc.next(TextFrames.Frame) ELSE RETURN NIL END
  66.     END MarkedFrame;
  67.     PROCEDURE FocusFrame (): TextFrames.Frame;
  68.         VAR V: Viewers.Viewer;
  69.     BEGIN V := Oberon.FocusViewer;
  70.         IF HoldsTF(V) THEN RETURN V.dsc.next(TextFrames.Frame) ELSE RETURN NIL END
  71.     END FocusFrame;
  72.     PROCEDURE GetMainArg (VAR S: Texts.Scanner; VAR beg, end: LONGINT);
  73.         VAR text: Texts.Text; sbeg, send, time: LONGINT;
  74.     BEGIN beg := Oberon.Par.pos; end := Oberon.Par.text.len;
  75.         Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
  76.         IF (S.class = Texts.Char) & (S.line = 0) & (S.c = "^") THEN Oberon.GetSelection(text, sbeg, send, time);
  77.             IF time >= 0 THEN beg := sbeg; end := send; Texts.OpenScanner(S, text, beg); Texts.Scan(S) END
  78.         END
  79.     END GetMainArg;
  80.     PROCEDURE SkipArrow (VAR S: Texts.Scanner);
  81.     BEGIN Texts.Scan(S);
  82.         IF (S.class = Texts.Char) & (S.c = "=") THEN Texts.Scan(S);
  83.             IF (S.class = Texts.Char) & (S.c = ">") THEN Texts.Scan(S) ELSE S.class := Texts.Inval END
  84.         ELSE S.class := Texts.Inval 
  85.         END
  86.     END SkipArrow;
  87.     (* string primitives *)
  88.     PROCEDURE SplitFontName (fn: ARRAY OF CHAR; VAR i, j, size: INTEGER);
  89.         VAR k: INTEGER;
  90.     BEGIN i := 0; size := 0;
  91.         WHILE (fn[i] # 0X) & ((fn[i] < "0") OR ("9" < fn[i])) DO INC(i) END;
  92.         j := i; WHILE ("0" <= fn[j]) & (fn[j] <= "9") DO INC(j) END;
  93.         k := i; WHILE k < j DO size := size * 10 + ORD(fn[k]) - 30H; INC(k) END
  94.     END SplitFontName;
  95.     PROCEDURE CombineFontName (prefix, suffix: ARRAY OF CHAR; i, j, size: INTEGER; VAR fn: ARRAY OF CHAR);
  96.         VAR k: INTEGER; ch: CHAR; dig: ARRAY 10 OF CHAR;
  97.     BEGIN COPY(prefix, fn); k := 0;
  98.         REPEAT dig[k] := CHR(size MOD 10 + 30H); size := size DIV 10; INC(k) UNTIL size = 0;
  99.         REPEAT DEC(k); fn[i] := dig[k]; INC(i) UNTIL k = 0;
  100.         REPEAT ch := suffix[j]; fn[i] := ch; INC(i); INC(j) UNTIL ch = 0X
  101.     END CombineFontName;
  102.     PROCEDURE ReadName (t: Texts.Text; pos: LONGINT; VAR name: ARRAY OF CHAR);    (*ww 21 Aug 91/mh 26 Aug 94*)
  103.         VAR i: INTEGER; r: Texts.Reader; ch: CHAR;
  104.     BEGIN Texts.OpenReader(r, t, pos); i := 0;
  105.         REPEAT Texts.Read(r, ch) UNTIL (ch > " ") OR (ch = 0AX) OR (ch = 0DX);
  106.         IF ~r.eot & (ch = 22X) THEN Texts.Read(r, ch) END;
  107.         WHILE ~r.eot & (ch > " ") DO name[i] := ch; Texts.Read(r, ch); INC(i) END;
  108.         IF (i > 0) & (name[i-1] = 22X) THEN DEC(i) END;
  109.         name[i] := 0X
  110.     END ReadName;
  111.     (* attribute extraction / searching *)
  112.     PROCEDURE SetNode (n: Node; VAR R: Texts.Reader);
  113.         VAR msg: Texts.IdentifyMsg;
  114.     BEGIN n.fnt := R.fnt; n.col := R.col; n.voff := R.voff;
  115.         IF R.elem # NIL THEN R.elem.handle(R.elem, msg); COPY(msg.mod, n.mod)
  116.         ELSE n.mod[0] := 0X
  117.         END
  118.     END SetNode;
  119.     PROCEDURE Less (x, y: Node): BOOLEAN;
  120.     BEGIN
  121.         IF x.mod < y.mod THEN RETURN TRUE
  122.         ELSIF x.mod = y.mod THEN
  123.             IF x.fnt.name < y.fnt.name THEN RETURN TRUE
  124.             ELSIF x.fnt.name = y.fnt.name THEN
  125.                 IF x.col < y.col THEN RETURN TRUE
  126.                 ELSIF x.col = y.col THEN
  127.                     IF x.voff < y.voff THEN RETURN TRUE END
  128.                 END
  129.             END
  130.         END;
  131.         RETURN FALSE
  132.     END Less;
  133.     PROCEDURE Insert (t, x: Node);
  134.         VAR p, c: Node;
  135.     BEGIN p := t; c := NIL;
  136.         WHILE t # NIL DO p := t;
  137.             IF Less(x, t) THEN t := t.l ELSE c := t; t := t.r END
  138.         END;
  139.         IF (c = NIL) OR Less(c, x) THEN
  140.             IF Less(x, p) THEN NEW(p.l); c := p.l ELSE NEW(p.r); c := p.r END;
  141.             c^ := x^
  142.         END
  143.     END Insert;
  144.     PROCEDURE List (t: Node);
  145.     BEGIN
  146.         IF t # NIL THEN
  147.             List(t.l);
  148.             Ln;
  149.             IF t.mod[0] # 0X THEN Str("  elem "); Str(t.mod) END;
  150.             Str("  font "); Str(t.fnt.name); Str("  col"); Int(t.col); Str("  off"); Int(t.voff);
  151.             List(t.r)
  152.         END
  153.     END List;
  154.     PROCEDURE ScanText (text: Texts.Text; beg, end: LONGINT);
  155.         VAR tree, cand: Node; R: Texts.Reader; pos: LONGINT; ch0, ch: CHAR;
  156.     BEGIN  pos := beg;
  157.         Texts.OpenReader(R, text, beg); Texts.Read(R, ch0); INC(pos);
  158.         IF pos > end THEN Str("  end of text")
  159.         ELSE NEW(tree); SetNode(tree, R); tree.l := NIL; tree.r := NIL;
  160.             IF pos = end THEN List(tree); Str(" ascii"); Int(ORD(ch0))
  161.             ELSE Texts.Read(R, ch); INC(pos);
  162.                 NEW(cand); cand.l := NIL; cand.r := NIL;
  163.                 WHILE pos <= end DO SetNode(cand, R); Insert(tree, cand);
  164.                     Texts.Read(R, ch); INC(pos)
  165.                 END;
  166.                 List(tree)
  167.             END
  168.         END;
  169.     END ScanText;
  170.     PROCEDURE Scan (VAR S: Texts.Scanner; beg, end: LONGINT; n: Node; VAR set: SET);
  171.     BEGIN set := {};
  172.         WHILE (beg < end) & (S.line = 0) & (S.class = Texts.Name) DO beg := Texts.Pos(S);
  173.             IF S.s = "elem" THEN Texts.Scan(S);
  174.                 IF (S.line = 0) & (S.class = Texts.Name) THEN
  175.                     INCL(set, elem); COPY(S.s, n.mod); Texts.Scan(S)
  176.                 END
  177.             ELSIF S.s = "font" THEN Texts.Scan(S);
  178.                 IF (S.line = 0) & (S.class = Texts.Name) THEN n.fnt := Fonts.This(S.s);
  179.                     IF n.fnt.name = S.s THEN INCL(set, fnt); Texts.Scan(S) END
  180.                 END
  181.             ELSIF S.s = "col" THEN Texts.Scan(S);
  182.                 IF (S.line = 0) & (S.class = Texts.Int) & (-128 <= S.i) & (S.i <= 127) THEN
  183.                     INCL(set, col); n.col := SHORT(SHORT(S.i)); Texts.Scan(S)
  184.                 END
  185.             ELSIF S.s = "off" THEN Texts.Scan(S);
  186.                 IF (S.line = 0) & (S.class = Texts.Int) & (-128 <= S.i) & (S.i <= 127) THEN
  187.                     INCL(set, voff); n.voff := SHORT(SHORT(S.i)); Texts.Scan(S)
  188.                 END
  189.             ELSE beg := end
  190.             END
  191.         END
  192.     END Scan;
  193.     PROCEDURE Equal (x, y: Node; set: SET): BOOLEAN;
  194.     BEGIN
  195.         IF (elem IN set) & (x.mod # y.mod) THEN RETURN FALSE END;
  196.         IF (fnt IN set) & (x.fnt # y.fnt) THEN RETURN FALSE END;
  197.         IF (col IN set) & (x.col # y.col) THEN RETURN FALSE END;
  198.         RETURN ~(voff IN set) OR (x.voff = y.voff)
  199.     END Equal;
  200.     (** text manipulation **)
  201.     PROCEDURE IncFontSize* (T: Texts.Text; beg, end: LONGINT; delta: INTEGER);
  202.         VAR R: Texts.Reader; fnt: Fonts.Font; fn: Fonts.Name; org: LONGINT; i, j, size: INTEGER; ch: CHAR;
  203.     BEGIN Texts.OpenReader(R, T, beg); Texts.Read(R, ch);
  204.         WHILE ~R.eot & (beg < end) DO org := beg; fnt := R.fnt;
  205.             WHILE ~R.eot & (beg < end) & (R.fnt = fnt) DO INC(beg); Texts.Read(R, ch) END;
  206.             SplitFontName(fnt.name, i, j, size);
  207.             IF i < j THEN CombineFontName(fnt.name, fnt.name, i, j, size + delta, fn); fnt := Fonts.This(fn);
  208.                 IF fnt.name = fn THEN Texts.ChangeLooks(T, org, beg, {0}, fnt, 0, 0) END
  209.             END
  210.         END
  211.     END IncFontSize;
  212.     PROCEDURE ChangeFontSize* (T: Texts.Text; beg, end: LONGINT; old, new: INTEGER);
  213.         VAR R: Texts.Reader; fnt: Fonts.Font; fn: Fonts.Name; org: LONGINT; i, j, size: INTEGER; ch: CHAR;
  214.     BEGIN Texts.OpenReader(R, T, beg); Texts.Read(R, ch);
  215.         WHILE ~R.eot & (beg < end) DO org := beg; fnt := R.fnt;
  216.             WHILE ~R.eot & (beg < end) & (R.fnt = fnt) DO INC(beg); Texts.Read(R, ch) END;
  217.             SplitFontName(fnt.name, i, j, size);
  218.             IF (i < j) & ((size = old) OR (old = -1)) THEN
  219.                 CombineFontName(fnt.name, fnt.name, i, j, new, fn); fnt := Fonts.This(fn);
  220.                 IF fnt.name = fn THEN Texts.ChangeLooks(T, org, beg, {0}, fnt, 0, 0) END
  221.             END
  222.         END
  223.     END ChangeFontSize;
  224.     PROCEDURE ChangeFontFamily* (T: Texts.Text; beg, end: LONGINT; old, new: ARRAY OF CHAR);
  225.         VAR R: Texts.Reader; fnt: Fonts.Font; fn: Fonts.Name; org: LONGINT; i, i1, j, j1, size, size1: INTEGER; ch: CHAR;
  226.     BEGIN Texts.OpenReader(R, T, beg); Texts.Read(R, ch);
  227.         WHILE ~R.eot & (beg < end) DO org := beg; fnt := R.fnt;
  228.             WHILE ~R.eot & (beg < end) & (R.fnt = fnt) DO INC(beg); Texts.Read(R, ch) END;
  229.             SplitFontName(fnt.name, i, j, size); COPY(fnt.name, fn); fn[i] := 0X;
  230.             IF (i < j) & ((fn = old) OR (old[0] = "?")) THEN SplitFontName(new, i1, j1, size1);
  231.                 CombineFontName(new, fnt.name, i1, j, size, fn); fnt := Fonts.This(fn);
  232.                 IF fnt.name = fn THEN Texts.ChangeLooks(T, org, beg, {0}, fnt, 0, 0) END
  233.             END
  234.         END
  235.     END ChangeFontFamily;
  236.     PROCEDURE ChangeFontStyle* (T: Texts.Text; beg, end: LONGINT; old, new: CHAR);
  237.         VAR R: Texts.Reader; fnt: Fonts.Font; fn: Fonts.Name; org: LONGINT; i, j, k, size: INTEGER; ch: CHAR;
  238.     BEGIN Texts.OpenReader(R, T, beg); Texts.Read(R, ch);
  239.         WHILE ~R.eot & (beg < end) DO org := beg; fnt := R.fnt;
  240.             WHILE ~R.eot & (beg < end) & (R.fnt = fnt) DO INC(beg); Texts.Read(R, ch) END;
  241.             SplitFontName(fnt.name, i, j, size);
  242.             IF (i < j) & ((fnt.name[j] = old) OR (old = "?")) & (fnt.name[j] # new) THEN COPY(fnt.name, fn);
  243.                 IF fn[j] = "." THEN k := j+1;
  244.                     WHILE fn[k] # 0X DO INC(k) END;
  245.                     WHILE k >= j DO fn[k+1] := fn[k]; DEC(k) END
  246.                 ELSIF new = "." THEN k := j;
  247.                     REPEAT fn[k] := fn[k+1]; INC(k) UNTIL fn[k] = 0X
  248.                 END;
  249.                 fn[j] := new; fnt := Fonts.This(fn);
  250.                 IF fnt.name = fn THEN Texts.ChangeLooks(T, org, beg, {0}, fnt, 0, 0) END
  251.             END
  252.         END
  253.     END ChangeFontStyle;
  254.     PROCEDURE ChangeFont* (T: Texts.Text; beg, end: LONGINT; old, new: ARRAY OF CHAR);
  255.         VAR R: Texts.Reader; fnt: Fonts.Font; org: LONGINT; ch: CHAR;
  256.     BEGIN Texts.OpenReader(R, T, beg); Texts.Read(R, ch);
  257.         WHILE ~R.eot & (beg < end) DO org := beg; fnt := R.fnt;
  258.             WHILE ~R.eot & (beg < end) & (R.fnt = fnt) DO INC(beg); Texts.Read(R, ch) END;
  259.             IF fnt.name = old THEN fnt := Fonts.This(new);
  260.                 IF fnt.name = new THEN Texts.ChangeLooks(T, org, beg, {0}, fnt, 0, 0) END
  261.             END
  262.         END
  263.     END ChangeFont;
  264.     PROCEDURE Count* (T: Texts.Text; beg, end: LONGINT; VAR wc, pc, ec: LONGINT);
  265.         VAR R: Texts.Reader; ch: CHAR;
  266.     BEGIN wc := 0; pc := 0; ec := 0;
  267.         Texts.OpenReader(R, T, beg); Texts.Read(R, ch); INC(beg);
  268.         WHILE beg <= end DO
  269.             WHILE (beg <= end) & (ch <= " ") DO
  270.                 IF R.elem # NIL THEN INC(ec)
  271.                 ELSIF ch = CR THEN INC(pc)
  272.                 END;
  273.                 Texts.Read(R, ch); INC(beg)
  274.             END;
  275.             IF beg <= end THEN INC(wc);
  276.                 WHILE (beg <= end) & (ch > " ") DO Texts.Read(R, ch); INC(beg) END
  277.             END
  278.         END
  279.     END Count;
  280.     PROCEDURE DeleteMonsters* (T: Texts.Text; monsterW, monsterH: LONGINT; VAR mc: LONGINT);
  281.         VAR e: Texts.Elem; R: Texts.Reader; pos: LONGINT;
  282.             msg: TextFrames.DisplayMsg;
  283.     BEGIN Texts.OpenReader(R, T, 0); Texts.ReadElem(R); mc := 0;
  284.         WHILE R.elem # NIL DO e := R.elem;
  285.             IF ~(e IS TextFrames.Parc) THEN pos := Texts.Pos(R)-1;
  286.                 msg.prepare := TRUE; msg.fnt := R.fnt; msg.col := R.col; msg.pos := pos; msg.indent := 0;
  287.                 e.handle(e, msg);
  288.                 IF (e.W > monsterW) OR (e.H > monsterH) THEN
  289.                     Texts.Delete(T, pos, pos + 1); INC(mc); Texts.OpenReader(R, T, pos)
  290.                 END
  291.             END;
  292.             Texts.ReadElem(R)
  293.         END
  294.     END DeleteMonsters;
  295.     PROCEDURE DeleteElems* (T: Texts.Text; beg, end: LONGINT);
  296.         VAR R: Texts.Reader; ch: CHAR;
  297.     BEGIN Texts.OpenReader(R, T, beg); Texts.Read(R, ch);
  298.         WHILE beg < end DO
  299.             IF R.elem # NIL THEN Texts.Delete(T, beg, beg + 1); Texts.OpenReader(R, T, beg); DEC(end)
  300.             ELSE INC(beg)
  301.             END;
  302.             Texts.Read(R, ch)
  303.         END
  304.     END DeleteElems;
  305.     PROCEDURE SelectedFrame* (): TextFrames.Frame;
  306.         VAR time: LONGINT; v: Viewers.Viewer; x: INTEGER; f, F: TextFrames.Frame;
  307.     BEGIN
  308.         time := -1; x := 0; F := NIL;
  309.         WHILE x < Viewers.curW DO
  310.             v := Viewers.This(x, 0);
  311.             WHILE v.state > 1 DO
  312.                 IF v.dsc.next IS TextFrames.Frame THEN
  313.                     f := v.dsc.next(TextFrames.Frame); 
  314.                     IF f.hasSel & (f.time > time) THEN F := f; time := f.time END;
  315.                 END;
  316.                 v := Viewers.Next(v)
  317.             END;
  318.             x := x + v.W
  319.         END;
  320.         RETURN F
  321.     END SelectedFrame;
  322.     PROCEDURE ConvertToAscii* (T: Texts.Text; beg, end: LONGINT);    (* mh 27.10.92 *)
  323.         CONST doubleS = 0ABX;
  324.         VAR R: Texts.Reader; ch: CHAR;
  325.         PROCEDURE repl (by: ARRAY OF CHAR);
  326.             VAR i: LONGINT;
  327.         BEGIN i := 0;
  328.             WHILE by[i] # 0X DO INC(i) END;
  329.             Texts.Delete(T, beg, beg+1); DEC(end);
  330.             IF i > 0 THEN Texts.SetFont(WR, R.fnt); Texts.SetColor(WR, R.col); Texts.SetOffset(WR, R.voff);
  331.                 Texts.WriteString(WR, by); Texts.Insert(T, beg, WR.buf); INC(beg, i); INC(end, i)
  332.             END;
  333.             Texts.OpenReader(R, T, beg)
  334.         END repl;
  335.         PROCEDURE replch (by: CHAR);    (* needed because compiler does not allow open arrays of length 1 *)
  336.         BEGIN
  337.             Texts.Delete(T, beg, beg+1); DEC(end);
  338.             Texts.SetFont(WR, R.fnt); Texts.SetColor(WR, R.col); Texts.SetOffset(WR, R.voff);
  339.             Texts.Write(WR, by); Texts.Insert(T, beg, WR.buf); INC(beg); INC(end);
  340.             Texts.OpenReader(R, T, beg)
  341.         END replch;
  342.     BEGIN Texts.OpenReader(R, T, beg); Texts.Read(R, ch);
  343.         WHILE beg < end DO
  344.             IF ch = TAB THEN repl("  ")
  345.             ELSIF ch = "
  346. " THEN repl("ae") ELSIF ch = "
  347. " THEN repl("oe") ELSIF ch = "
  348. " THEN repl("ue")
  349.             ELSIF ch = "
  350. " THEN repl("Ae") ELSIF ch = "
  351. " THEN repl("Oe") ELSIF ch = "
  352. " THEN repl("Ue")
  353.             ELSIF ch = doubleS THEN repl("ss")
  354.             ELSIF (ch = "
  355. ") OR (ch = "
  356. ") OR (ch = "
  357. ") THEN replch("a")
  358.             ELSIF (ch = "
  359. ") OR (ch = "
  360. ") OR (ch = "
  361. ") OR (ch = "
  362. ") THEN replch("e")
  363.             ELSIF (ch = "
  364. ") OR (ch = "
  365. ") OR (ch = "
  366. ") THEN replch("i")
  367.             ELSIF (ch = "
  368. ") OR (ch = "
  369. ") THEN replch("o")
  370.             ELSIF (ch = "
  371. ") OR (ch = "
  372. ") THEN replch("u")
  373.             ELSIF (ch = "
  374. ") THEN replch("c")
  375.             ELSIF (ch = "
  376. ") THEN replch("n")
  377.             ELSE INC(beg)
  378.             END;
  379.             Texts.Read(R, ch)
  380.         END
  381.     END ConvertToAscii;
  382.     PROCEDURE UnmarkMenu* (V: Viewers.Viewer);
  383.         VAR R: Texts.Reader; text: Texts.Text; ch: CHAR;
  384.     BEGIN
  385.         IF (V IS MenuViewers.Viewer) & (V.dsc IS TextFrames.Frame) THEN
  386.             text := V.dsc(TextFrames.Frame).text;
  387.             IF text.len > 0 THEN Texts.OpenReader(R, text, text.len - 1); Texts.Read(R, ch);
  388.                 IF ch = "!" THEN Texts.Delete(text, text.len - 1, text.len) END
  389.             END
  390.         END
  391.     END UnmarkMenu;
  392.     PROCEDURE ReadNonWhiteSp (VAR R: Texts.Reader; VAR ch: CHAR);
  393.     BEGIN
  394.         REPEAT Texts.Read(R, ch) UNTIL (ch > " ") OR R.eot;
  395.     END ReadNonWhiteSp;
  396.     (** commands **)
  397.     PROCEDURE SearchDiff*;    (** takes the two most recent selections **)
  398.         VAR f0, f1: TextFrames.Frame; R0, R1: Texts.Reader; ch0, ch1: CHAR; pos: LONGINT;
  399.             S: Texts.Scanner; whiteSp: BOOLEAN;
  400.     BEGIN
  401.         whiteSp := TRUE;
  402.         Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
  403.         IF (S.line = 0) & (S.class = Texts.Char) & (S.c = OptionChar) THEN Texts.Scan(S);
  404.             IF (S.class = Texts.Name) & (CAP(S.s[0]) = "W") THEN whiteSp := FALSE END;
  405.         END;
  406.         f0 := SelectedFrame(); IF f0 # NIL THEN TextFrames.RemoveSelection(f0) END;
  407.         f1 := SelectedFrame();
  408.         IF f1 # NIL THEN
  409.             Texts.OpenReader(R0, f0.text, f0.selbeg.pos); Texts.OpenReader(R1, f1.text, f1.selbeg.pos);
  410.             IF whiteSp THEN
  411.                 REPEAT Texts.Read(R0, ch0); Texts.Read(R1, ch1) UNTIL (ch0 # ch1) OR (ch0 = 0X)
  412.             ELSE
  413.                 REPEAT ReadNonWhiteSp(R0, ch0); ReadNonWhiteSp(R1, ch1) UNTIL (ch0 # ch1) OR (ch0 = 0X)
  414.             END;
  415.             pos := Texts.Pos(R0)-1; Show(f0, pos); TextFrames.SetSelection(f0, pos, pos + 1);
  416.             pos := Texts.Pos(R1)-1; Show(f1, pos); TextFrames.SetSelection(f1, pos, pos + 1);
  417.         END
  418.     END SearchDiff;
  419.     PROCEDURE GetAttr*;    (** ("*" | "@") **)
  420.         VAR F: TextFrames.Frame; S: Texts.Scanner; text: Texts.Text; beg, end, time: LONGINT;
  421.     BEGIN Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
  422.         IF (S.class = Texts.Char) & (S.line = 0) THEN Str("EditTools.GetAttr");
  423.             F := MarkedFrame(); Oberon.GetSelection(text, beg, end, time);
  424.             IF (S.c = "*") & (F # NIL) THEN ScanText(F.text, 0, F.text.len)
  425.             ELSIF (S.c = "@") & (time >= 0) THEN ScanText(text, beg, end)
  426.             END
  427.         END
  428.     END GetAttr;
  429.     PROCEDURE SearchAttr*;    (** selection, caret **)
  430.         VAR f: TextFrames.Frame; S: Texts.Scanner; R: Texts.Reader;
  431.             org, beg, end: LONGINT; ch: CHAR;
  432.             x, n: Node; set: SET;
  433.     BEGIN f := FocusFrame();
  434.         IF f # NIL THEN GetMainArg(S, beg, end);
  435.             NEW(n); Scan(S, beg, end, n, set);
  436.             IF (set = {}) & (search.set # {}) THEN set := search.set; n := search.node END;
  437.             IF set # {} THEN search.set := set; search.node := n;
  438.                 IF f.hasCar THEN org := f.carloc.pos ELSE org := 0 END;
  439.                 Texts.OpenReader(R, f.text, org); Texts.Read(R, ch);
  440.                 NEW(x); SetNode(x, R);
  441.                 WHILE ~R.eot & ~Equal(x, n, set) DO Texts.Read(R, ch); SetNode(x, R) END;
  442.                 IF ~R.eot THEN Show(f, Texts.Pos(R)); TextFrames.SetCaret(f, Texts.Pos(R))
  443.                 ELSE TextFrames.RemoveCaret(f)
  444.                 END
  445.             END
  446.         END
  447.     END SearchAttr;
  448.     PROCEDURE IncSize*;    (** size; selection **)
  449.         VAR S: Texts.Scanner; text: Texts.Text; beg, end, time: LONGINT;
  450.     BEGIN Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
  451.         Oberon.GetSelection(text, beg, end, time);
  452.         IF (time >= lastTime) & (S.class = Texts.Int) & (S.line = 0) & (-1000 <= S.i) & (S.i < 1000) THEN lastTime := time;
  453.             IncFontSize(text, beg, end, SHORT(S.i))
  454.         END
  455.     END IncSize;
  456.     PROCEDURE ChangeSize*;    (** {old "=>" new}, selection **)
  457.         VAR S: Texts.Scanner; text: Texts.Text; beg, end, time: LONGINT; old: INTEGER;
  458.     BEGIN Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
  459.         Oberon.GetSelection(text, beg, end, time);
  460.         IF (time >= lastTime) & (S.line = 0) THEN
  461.             WHILE ~S.eot & ((S.class = Texts.Int) & (-1000 <= S.i) & (S.i < 1000) OR (S.class = Texts.Char) & (S.c = "?")) DO
  462.                 IF (S.class = Texts.Char) & (S.c = "?") THEN old := -1 ELSE old := SHORT(S.i) END;
  463.                 SkipArrow(S);
  464.                 IF (S.class = Texts.Int) & (-1000 <= S.i) & (S.i < 1000) THEN lastTime := time;
  465.                     ChangeFontSize(text, beg, end, old, SHORT(S.i)); Texts.Scan(S)
  466.                 END
  467.             END
  468.         END
  469.     END ChangeSize;
  470.     PROCEDURE ChangeStyle*;    (** {old "=>" new}, selection **)
  471.         VAR S: Texts.Scanner; text: Texts.Text; beg, end, time: LONGINT; old, new: CHAR;
  472.     BEGIN Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
  473.         Oberon.GetSelection(text, beg, end, time);
  474.         IF (time >= lastTime) & (S.line = 0) THEN
  475.             WHILE ~S.eot & ((S.class = Texts.Name) OR (S.class = Texts.Char)) DO
  476.                 IF S.class = Texts.Char THEN old := S.c ELSE old := S.s[0] END;
  477.                 SkipArrow(S);
  478.                 IF (S.class = Texts.Name) OR (S.class = Texts.Char) THEN lastTime := time;
  479.                     IF S.class = Texts.Char THEN new := S.c ELSE new := S.s[0] END;
  480.                     ChangeFontStyle(text, beg, end, old, new); Texts.Scan(S)
  481.                 END
  482.             END
  483.         END
  484.     END ChangeStyle;
  485.     PROCEDURE ChangeFamily*;    (** {old "=>" new}, selection **)
  486.         VAR S: Texts.Scanner; text: Texts.Text; beg, end, time: LONGINT; old: Fonts.Name;
  487.     BEGIN Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
  488.         Oberon.GetSelection(text, beg, end, time);
  489.         IF (time >= lastTime) & (S.line = 0) THEN
  490.             WHILE ~S.eot & ((S.class = Texts.Name) OR (S.class = Texts.Char) & (S.c = "?")) DO
  491.                 IF (S.class = Texts.Char) & (S.c = "?") THEN old[0] := "?"; old[1] := 0X ELSE COPY(S.s, old) END;
  492.                 SkipArrow(S);
  493.                 IF S.class = Texts.Name THEN lastTime := time;
  494.                     ChangeFontFamily(text, beg, end, old, S.s); Texts.Scan(S)
  495.                 END
  496.             END
  497.         END
  498.     END ChangeFamily;
  499.     PROCEDURE Change*;    (** {old "=>" new}, selection **)
  500.         VAR S: Texts.Scanner; text: Texts.Text; beg, end, time: LONGINT; old: Fonts.Name;
  501.     BEGIN Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
  502.         Oberon.GetSelection(text, beg, end, time);
  503.         IF (time >= lastTime) & (S.line = 0) THEN
  504.             WHILE S.class = Texts.Name DO COPY(S.s, old); SkipArrow(S);
  505.                 IF S.class = Texts.Name THEN lastTime := time;
  506.                     ChangeFont(text, beg, end, old, S.s); Texts.Scan(S)
  507.                 END
  508.             END
  509.         END
  510.     END Change;
  511.     PROCEDURE Words*;    (** "@" | ("^" | "*" | {name} "~") **)
  512.         VAR S: Texts.Scanner; frame: TextFrames.Frame; text: Texts.Text;
  513.             cc, ct, wc, wt, pc, pt, ec, et, beg1, end1, beg, end, time: LONGINT;
  514.     BEGIN GetMainArg(S, beg1, end1); frame := MarkedFrame(); Oberon.GetSelection(text, beg, end, time);
  515.         ct := 0; wt := 0; pt := 0; et := 0;
  516.         IF (S.class = Texts.Char) & (S.c = "*") & (frame # NIL) THEN Str("EditTools.Words  *");
  517.             cc := frame.text.len; Count(frame.text, 0, cc, wc, pc, ec);
  518.             Plural(pc, "CR"); Ch(","); Plural(wc, "word"); Ch(","); Plural(cc, "char"); Ch(","); Plural(ec, "element"); Ln
  519.         ELSIF (S.class = Texts.Char) & (S.c = "@") & (time >= 0) THEN Str("EditTools.Words  @");
  520.             cc := end - beg; Count(text, beg, end, wc, pc, ec);
  521.             Plural(pc, "CR"); Ch(","); Plural(wc, "word"); Ch(","); Plural(cc, "char"); Ch(","); Plural(ec, "element"); Ln
  522.         ELSIF S.class = Texts.Name THEN Str("EditTools.Words");
  523.             REPEAT text := TextFrames.Text(S.s);
  524.                 Str("  "); Str(S.s); cc := text.len; Count(text, 0, cc, wc, pc, ec);
  525.                 Plural(pc, "CR"); Ch(","); Plural(wc, "word"); Ch(","); Plural(cc, "char"); Ch(","); Plural(ec, "element"); Ln;
  526.                 INC(ct, cc); INC(wt, wc); INC(pt, pc); INC(et, ec); Texts.Scan(S)
  527.             UNTIL S.eot OR (S.class # Texts.Name) OR (Texts.Pos(S) > end1);
  528.             Str("  total");
  529.             Plural(pt, "CR"); Ch(","); Plural(wt, "word"); Ch(","); Plural(ct, "char"); Ch(","); Plural(et, "element"); Ln
  530.         END
  531.     END Words;
  532.     PROCEDURE Cleanup*;    (** "*" | ("^" | {name} "~") **)
  533.         VAR S: Texts.Scanner; frame: TextFrames.Frame; text: Texts.Text; mc, beg, end, len: LONGINT; res: INTEGER;
  534.     BEGIN GetMainArg(S, beg, end); frame := MarkedFrame();
  535.         IF (S.class = Texts.Char) & (S.c = "*") & (frame # NIL) THEN Str("EditTools.Cleanup  *");
  536.             DeleteMonsters(frame.text, MonsterW, MonsterH, mc);
  537.             Ch(" "); Plural(mc, "elem"); Str(" deleted"); Ln
  538.         ELSIF S.class = Texts.Name THEN Str("EditTools.Cleanup"); Ln;
  539.             REPEAT text := TextFrames.Text(S.s);
  540.                 Str("  "); Str(S.s); DeleteMonsters(text, MonsterW, MonsterH, mc);
  541.                 IF mc # 0 THEN Texts.Close(text, S.s) ELSE Str(" not changed") END;
  542.                 Ln; Texts.Scan(S)
  543.             UNTIL S.eot OR (S.class # Texts.Name) OR (Texts.Pos(S) > end)
  544.         END
  545.     END Cleanup;
  546.     PROCEDURE Refresh*;    (** "*" **)
  547.         VAR frame: TextFrames.Frame; f: Files.File; text: Texts.Text; r: Files.Rider;
  548.     BEGIN frame := MarkedFrame();
  549.         IF frame # NIL THEN Str("EditTools.Refresh"); Texts.Append(Oberon.Log, W.buf);
  550.             text := frame.text; f := Files.New("");
  551.             Files.Set(r, f, 0); Texts.Store(r, text);
  552.             Files.Set(r, f, 0); Texts.Load(r, text);
  553.             Texts.ChangeLooks(text, 0, text.len, {}, NIL, 0, 0);
  554.             Int(Files.Length(f)); Ln
  555.         END
  556.     END Refresh;
  557.     PROCEDURE RemoveElems*;    (** "*" | "@" **)
  558.         VAR S: Texts.Scanner; frame: TextFrames.Frame; text: Texts.Text; beg, end, time: LONGINT;
  559.     BEGIN Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
  560.         IF (S.line = 0) & (S.class = Texts.Char) THEN
  561.             Oberon.GetSelection(text, beg, end, time); frame := MarkedFrame();
  562.             IF (S.c = "*") & (frame # NIL) THEN DeleteElems(frame.text, 0, frame.text.len)
  563.             ELSIF (S.c = "@") & (time >= lastTime) THEN lastTime := time;
  564.                 DeleteElems(text, beg, end)
  565.             END
  566.         END
  567.     END RemoveElems;
  568.     PROCEDURE ToAscii*;    (** "*" | "@" **)
  569.         VAR S: Texts.Scanner; frame: TextFrames.Frame; text: Texts.Text; beg, end, time: LONGINT;
  570.     BEGIN Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
  571.         IF (S.line = 0) & (S.class = Texts.Char) THEN
  572.             Oberon.GetSelection(text, beg, end, time); frame := MarkedFrame();
  573.             IF (S.c = "*") & (frame # NIL) THEN ConvertToAscii(frame.text, 0, frame.text.len)
  574.             ELSIF (S.c = "@") & (time >= lastTime) THEN lastTime := time;
  575.                 ConvertToAscii(text, beg, end)
  576.             END
  577.         END
  578.     END ToAscii;
  579.     PROCEDURE NoNotify (text: Texts.Text; op: INTEGER; beg, end: LONGINT);
  580.     END NoNotify;
  581.     PROCEDURE InsertCR*;    (** int ( "*" | "@") **)
  582.         VAR S: Texts.Scanner; text: Texts.Text; R: Texts.Reader; oldNotify: Texts.Notifier; ch: CHAR;
  583.             beg, beg0, end, lineEnd, time: LONGINT; frame: TextFrames.Frame;
  584.         PROCEDURE GetLineEnd (pos, len: LONGINT; VAR end: LONGINT; VAR ch: CHAR);
  585.             VAR R: Texts.Reader; pos0: LONGINT;
  586.         BEGIN end := pos; pos0 := pos;
  587.             Texts.OpenReader(R, text, pos);
  588.             LOOP  (*end = pos0 or position after last read blank*)
  589.                 Texts.Read(R, ch); INC(pos); DEC(len);
  590.                 IF R.eot THEN end := text.len; EXIT
  591.                 ELSIF ch = CR THEN end := pos; EXIT
  592.                 ELSIF ch = " " THEN end := pos
  593.                 ELSIF len <= 0 THEN
  594.                     IF end = pos0 THEN end := pos ELSE ch := " " END;
  595.                     EXIT
  596.                 END
  597.             END
  598.         END GetLineEnd;
  599.     BEGIN Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
  600.         IF (S.class = Texts.Int) THEN Texts.Scan(S); text := NIL;
  601.             IF (S.line = 0) & (S.class = Texts.Char) THEN
  602.                 IF S.c = "*" THEN frame := MarkedFrame(); text := frame.text; beg := 0; end := text.len; time := 1;
  603.                 ELSIF S.c = "@" THEN Oberon.GetSelection(text, beg, end, time);
  604.                 END;
  605.             END;
  606.             IF text # NIL THEN beg0 := beg; ch := " ";
  607.                 oldNotify :=  text.notify; text.notify := NoNotify;
  608.                 WHILE (beg > 0) & (ch # CR) DO
  609.                     DEC(beg); Texts.OpenReader(R, text, beg); Texts.Read(R, ch);
  610.                     IF ch = CR THEN INC(beg) END
  611.                 END;
  612.                 LOOP GetLineEnd(beg, S.i, lineEnd, ch);
  613.                     IF lineEnd >= end THEN EXIT
  614.                     ELSIF ch = CR THEN (*line already terminated by CR*)
  615.                     ELSIF ch = " " THEN (*replace blank by CR*)
  616.                         Texts.Delete(text, lineEnd - 1, lineEnd);
  617.                         Texts.WriteLn(W); Texts.Insert(text, lineEnd - 1, W.buf)
  618.                     ELSE (*the whole line is one word; break it*)
  619.                         Texts.WriteLn(W); Texts.Insert(text, lineEnd, W.buf); INC(lineEnd); INC(end)
  620.                     END;
  621.                     beg := lineEnd
  622.                 END;
  623.                 text.notify := oldNotify;
  624.                 text.notify(text, Texts.replace, beg0, end)
  625.             END
  626.         END
  627.     END InsertCR;
  628.     PROCEDURE RemoveCR*;     (** "*" | "@" **)
  629.         VAR text: Texts.Text; R: Texts.Reader; beg, beg0, end, time: LONGINT; ch, lastCh, nextCh: CHAR;
  630.         oldNotify: Texts.Notifier; frame: TextFrames.Frame; S: Texts.Scanner;
  631.     BEGIN
  632.         Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S); text := NIL;
  633.         IF (S.line = 0) & (S.class = Texts.Char) THEN
  634.             IF S.c = "*" THEN frame := MarkedFrame(); text := frame.text; beg := 0; end := text.len; time := 1;
  635.             ELSIF S.c = "@" THEN Oberon.GetSelection(text, beg, end, time);
  636.             END
  637.         END;
  638.         IF text # NIL THEN
  639.             IF time >= 0 THEN beg0 := beg; lastCh := 0X;
  640.                 oldNotify :=  text.notify; text.notify := NoNotify;
  641.                 Texts.OpenReader(R, text, beg);
  642.                 WHILE beg < end DO
  643.                     Texts.Read(R, ch); INC(beg);
  644.                     IF ch = CR THEN
  645.                         Texts.Read(R, nextCh);
  646.                         IF (lastCh # CR) & (nextCh # CR) THEN
  647.                             Texts.Delete(text, beg-1, beg); Texts.Write(W, " "); Texts.Insert(text, beg-1, W.buf)
  648.                         END;
  649.                         Texts.OpenReader(R, text, beg)
  650.                     END;
  651.                     lastCh := ch
  652.                 END;
  653.                 text.notify := oldNotify;
  654.                 text.notify(text, Texts.replace, beg0, end)
  655.             END
  656.         END
  657.     END RemoveCR;
  658.     PROCEDURE ShowAliens*;
  659.         VAR F: TextFrames.Frame; R: Texts.Reader; none: BOOLEAN; identify: Texts.IdentifyMsg;
  660.     BEGIN F := MarkedFrame();
  661.         IF (F # NIL) THEN Str("EditTools.ShowAliens"); none := TRUE;
  662.             Texts.OpenReader(R, F.text, 0); Texts.ReadElem(R);
  663.             WHILE ~R.eot DO identify.mod[31] := 0X; R.elem.handle(R.elem, identify);
  664.                 IF identify.mod[31] = 1X THEN none := FALSE; Ln; Str("pos"); Int(Texts.Pos(R) - 1);
  665.                     Str("  unknown element allocator: "); Str(identify.mod); Ch("."); Str(identify.proc)
  666.                 END;
  667.                 Texts.ReadElem(R)
  668.             END;
  669.             IF none THEN Str("  none") END;
  670.             Ln
  671.         END
  672.     END ShowAliens;
  673.     PROCEDURE StoreAscii*;    (*ww 21 Aug 91 / CAS 5-Nov-91 / mh 26 Aug 94 *)
  674.         VAR r: Texts.Reader; t: Texts.Text; f: Files.File; fr: Files.Rider; v: Viewers.Viewer;
  675.             name, bak: ARRAY 64 OF CHAR; ch: CHAR; beg, end, time: LONGINT; i, res: INTEGER;
  676.     BEGIN t := NIL;
  677.         IF Oberon.Par.frame = Oberon.Par.vwr.dsc THEN v := Oberon.Par.vwr;
  678.             ReadName(Oberon.Par.frame(TextFrames.Frame).text, 0, name);
  679.             t := Oberon.Par.frame.next(TextFrames.Frame).text
  680.         ELSE ReadName(Oberon.Par.text, Oberon.Par.pos, name); v := Oberon.MarkedViewer();
  681.             IF (name[0] = "^") & (name[1] = 0X) THEN Oberon.GetSelection(t, beg, end, time);
  682.                 IF time > 0 THEN ReadName(t, beg, name) ELSE name := "" END
  683.             END;
  684.             IF (name[0] = "*") & (name[1] = 0X) THEN ReadName(v.dsc(TextFrames.Frame).text, 0, name) END;
  685.             t := v.dsc.next(TextFrames.Frame).text
  686.         END;
  687.         IF (t # NIL) & (name # "") THEN UnmarkMenu(v);
  688.             Str("EditTools.StoreAscii "); Str(name); Ch(" ");
  689.             f := Files.New(name); Files.Set(fr, f, 0); Texts.OpenReader(r, t, 0); Texts.Read(r, ch);
  690.             WHILE ~r.eot DO
  691.                 IF ch = 0DX THEN ch := 0AX END;
  692.                 IF ch # Texts.ElemChar THEN Files.Write(fr, ch) END;
  693.                 Texts.Read(r, ch)
  694.             END;
  695.             COPY(name, bak); i := 0;
  696.             WHILE bak[i] # 0X DO INC(i) END;
  697.             bak[i] := "."; bak[i+1] := "B"; bak[i+2] := "a"; bak[i+3] := "k"; bak[i+4] := 0X;
  698.             Files.Rename(name, bak, res);
  699.             Files.Register(f); Int(Files.Pos(fr)); Ln
  700.         END
  701.     END StoreAscii;
  702.     PROCEDURE LocateLine*;
  703.         VAR f: TextFrames.Frame;
  704.             S: Texts.Scanner; R: Texts.Reader; line, beg, end: LONGINT; ch: CHAR;
  705.     BEGIN f := MarkedFrame(); GetMainArg(S, beg, end);
  706.         WHILE ~S.eot & (S.class < Texts.Int) & (S.line = 0) DO Texts.Scan(S) END ;    (*skip names*)
  707.         IF (S.class = Texts.Int) & (f # NIL) THEN
  708.             Texts.OpenReader(R, f.text, 0); line := 1; Texts.Read(R, ch);
  709.             WHILE ~R.eot & (line < S.i) DO
  710.                 IF ch = CR THEN INC(line) END;
  711.                 Texts.Read(R, ch)
  712.             END;
  713.             Show(f, Texts.Pos(R)-1); TextFrames.SetCaret(f, Texts.Pos(R)-1)
  714.         END
  715.     END LocateLine;
  716. BEGIN Texts.OpenWriter(W); Texts.OpenWriter(WR); lastTime := 0; search.set := {}
  717. END EditTools.
  718.     EditTools.GetAttr *
  719.     EditTools.SearchAttr font Syntax10b.Scn.Fnt  off 0
  720.     EditTools.IncSize 4
  721.     EditTools.ChangeSize ? => 12 ~
  722.     EditTools.ChangeFamily ? => Syntax ~
  723.     EditTools.ChangeStyle b => . ~
  724.     EditTools.Change Syntax12.Scn.Fnt => Courier10.Scn.Fnt ~
  725.     EditTools.Words * EditTools.Mod ~
  726.     EditTools.Cleanup ~
  727.     EditTools.RemoveElems *
  728.     EditTools.ToAscii *
  729.     EditTools.InsertCR 80 @
  730.     EditTools.RemoveCR @
  731.     EditTools.StoreAscii 
  732.     EditTools.LocateLine 15
  733.     test text using some mixed fonts
  734.