ðB5Syntax10.Scn.FntúÿÿÐûÐûBalloonElemsAlloc#Syntax10.Scn.FntÅÅ"VersionElems" Version elements simplify the handling of multiple versions of a module in the same source file. Text pieces that differ from one version to the other are enclosed in version elements which look like angle brackets. When the user middle-clicks on the opening bracket a popup menu with a list of version names appears. Selecting one of the names replaces the bracketed text with the text that is stored for the selected version. "Beg" The opening bracket of a pair of version elements. When it is clicked at it shows a list of version names. Selecting one of these names replaces the text between the Beg and the End element with the text that is stored for this version name. "End" The closing bracket of a pair of version elements. "CheckMenu" Makes sure that the variants in the element are exactly the variants in the popup menu. "IndexOf" e.IndexOf(vers) returns the index i so that e.buf[i] is the text corresponding to vers. "TwinPos" e.TwinPos() returns the position of the corresponding right bracket of e. "SwitchTo" e.SwitchTo(vers) switches the element e to version vers. "Insert" VersionElems.Insert name Inserts a pair of version elements around the current selection. 'name' is the version name. "SetVersion" VersionElems.SetVersion name Switches all version elements in the marked text to version 'name'. "Find" VersionElems.Find Searches the next version element starting from the caret position and sets the caret to this element.÷ÿÿÿP¥ÀÔStampElemsAlloc7 Aug 2÷üÿÿÐûÐûInfoElemsAllocTSyntax10.Scn.Fnt÷ÿÿÿÐÝÀÔStampElemsAlloc7 Aug 2 µ"Title": Version elements "Author": H. Moessenboeck "Abstract": Allows a programmer to keep several versions of a module in the same file and to switch between these versions consistently. "Keywords": version handling "Version": no version "From": 28.06.96 08:30:39 "Until":  "Changes": 95-09-14 First version 96-06-28 Insert v switches all elements to version v Current version is shown in the opened popup menu of the version element e.SwitchTo(v) adds version v to e.menu if not already present Switches also elements in collapsed folds Nested version elements allowed Commands Find and SetVersion removed "Hints": This text can again contain arbitrary text elements! ¿Syntax10b.Scn.Fnt<Syntax10i.Scn.Fnt$ .  Äÿÿÿ€8ÀÔFoldElemsNew$Syntax10i.Scn.Fntcontents of a Beg elementÿÿÿÿ€8ÀÔ/"þÿÿ€8ÀÔ#Syntax10.Scn.Fnt¼¼ VAR line: ARRAY 10 OF SET; BEGIN line[1] := {4}; line[2] := {3}; line[3] := {2}; line[4] := {1}; line[5] := {0}; line[6] := {1}; line[7] := {2}; line[8] := {3}; line[9] := {4}; begIcon := Display.NewPattern(line, 6, 9); line[1] := {1}; line[2] := {2}; line[3] := {3}; line[4] := {4}; line[5] := {5}; line[6] := {4}; line[7] := {3}; line[8] := {2}; line[9] := {1}; endIcon := Display.NewPattern(line, 6, 9); END InitIcons; ÿÿÿÿ€8ÀÔEÏÿÿÿ€8ÀÔ#Syntax10.Scn.Fnt END NoNotify; ÿÿÿÿ€8ÀÔ(~ÿÿÿ€8ÀÔ#Syntax10.Scn.Fnt`` VAR ch: CHAR; BEGIN IF In.Next() = In.name THEN In.Name(s) ELSE In.String(s) END END Read; ÿÿÿÿ€8ÀÔDHÿÿÿ€8ÀÔ#Syntax10.Scn.Fnt–– VAR i: INTEGER; ch: CHAR; BEGIN i := 0; REPEAT Texts.Read(r, ch); line[i] := ch; INC(i) UNTIL r.eot OR (ch = 0DX); line[i-1] := 0X END ReadLine; ÿÿÿÿ€8ÀÔ@;ÿÿÿ€8ÀÔ#Syntax10.Scn.Fnt££ VAR i: INTEGER; BEGIN i := 0; WHILE (i < maxVersions) & (e.vers[i] # "") DO IF e.vers[i] = version THEN RETURN i END; INC(i) END; RETURN -1 END IndexOf; ÿÿÿÿ€8ÀÔýÿÿ€8ÀÔ#Syntax10.Scn.FntQQ VAR r: Texts.Reader; vers: ARRAY maxVersions, 32 OF CHAR; buf: ARRAY maxVersions OF Texts.Buffer; i, j: INTEGER; version: ARRAY 32 OF CHAR; BEGIN Texts.OpenReader(r, e.menu, 0); i := 0; REPEAT ReadLine(r, version); IF (i < maxVersions) & (version # "") THEN COPY(version, vers[i]); j := e.IndexOf(version); IF j >= 0 THEN buf[i] := e.buf[j] ELSE NEW(buf[i]); Texts.OpenBuf(buf[i]) END; INC(i) END UNTIL r.eot; FOR j := 0 TO i-1 DO COPY(vers[j], e.vers[j]); e.buf[j] := buf[j] END; WHILE i < maxVersions DO e.vers[i] := ""; e.buf[i] := NIL; INC(i) END END CheckMenu; ÿÿÿÿ€8ÀÔ)œþÿÿ€8ÀÔ#Syntax10.Scn.FntBB VAR r: Texts.Reader; level: INTEGER; BEGIN Texts.OpenReader(r, Texts.ElemBase(e), Texts.ElemPos(e)+1); level := 1; LOOP Texts.ReadElem(r); IF r.eot THEN RETURN -1 ELSIF r.elem IS Beg THEN INC(level) ELSIF r.elem IS End THEN DEC(level); IF level = 0 THEN RETURN Texts.Pos(r) - 1 END END END END TwinPos; ÿÿÿÿ€8ÀÔ7,ûÿÿ€8ÀÔbSyntax10.Scn.Fntt÷ýÿÿ€8ÀÔFoldElemsNew#Syntax10.Scn.Fntçç VAR r: Texts.Reader; ch: CHAR; pos: LONGINT; i: INTEGER; BEGIN Texts.WriteLn(w); Texts.WriteString(w, s); pos := e.menu.len-1; Texts.OpenReader(r, e.menu, pos); Texts.Read(r, ch); IF ch # 0DX THEN INC(pos) END; Texts.Insert(e.menu, pos, w.buf); PopupElems.MeasureMenu(e); i := 0; WHILE (i < maxVersions) & (e.vers[i] # "") DO INC(i) END; IF i < maxVersions THEN COPY(s, e.vers[i]); NEW(e.buf[i]); Texts.OpenBuf(e.buf[i]) ELSE i := -1 END; RETURN i END NewVersion; ÿÿÿÿ€8ÀÔýs VAR t: Texts.Text; beg, end: LONGINT; i, j: INTEGER; PROCEDURE NewVersion (e: Beg; s: ARRAY OF CHAR): INTEGER;  BEGIN e.CheckMenu; IF version # e.cur THEN i := e.IndexOf(version); IF i < 0 THEN i := NewVersion(e, version) END; j := e.IndexOf(e.cur); IF i >= 0 THEN t := Texts.ElemBase(e); beg := Texts.ElemPos(e) + 1; end := e.TwinPos(); IF end >= 0 THEN Texts.Delete(t, beg, end); Texts.Insert(t, beg, e.buf[i]); IF j >= 0 THEN Texts.Recall(e.buf[j]) END; COPY(version, e.cur) END ELSE Out.F("-- more than max. no. of versions at pos #$", Texts.ElemPos(e)) END END END SwitchTo; ÿÿÿÿ€8ÀÔ Iýÿÿ€8ÀÔCSyntax10.Scn.FntÁSyntax10m.Scn.Fnt­u VAR version, s: ARRAY 32 OF CHAR; ch: CHAR; t: Texts.Text; v: Viewers.Viewer; BEGIN In.Open; Read(version); IF ~In.Done THEN Out.String("-- argument syntax: version ['IN' file {file}]$"); RETURN END; In.Name(s); IF s = "IN" THEN Read(curFileName); WHILE In.Done DO t := TextFrames.Text(curFileName); IF t.len = 0 THEN Out.String("-- file "); Out.String(curFileName); Out.String(" not found$"); RETURN END; P(t, version); Texts.Close(t, curFileName); Read(curFileName) END ELSE curFileName := "*"; v := Oberon.MarkedViewer(); t := v.dsc.next(TextFrames.Frame).text; P(t, version) END END Do; ÿÿÿÿ€8ÀÔ8eúÿÿ€8ÀÔ[Syntax10.Scn.Fnt²ÿÿÿ€8ÀÔFoldElemsNew#Syntax10.Scn.FntÀÀ VAR ch: CHAR; i: INTEGER; BEGIN beg := Texts.Pos(r); i := 0; REPEAT Texts.Read(r, ch); s[i] := ch; INC(i) UNTIL r.eot OR (ch = 0DX); end := Texts.Pos(r); s[i-1] := 0X END ReadEntry;ÿÿÿÿ€8ÀÔ!Syntax10m.Scn.Fnt bA VAR r, r1: Texts.Reader; e: Beg; i: INTEGER; s: ARRAY 32 OF CHAR; beg, end: LONGINT; PROCEDURE ReadEntry (VAR r: Texts.Reader; VAR s: ARRAY OF CHAR; VAR beg, end: LONGINT);  BEGIN Texts.OpenReader(r, t, 0); Texts.ReadElem(r); WHILE ~r.eot DO IF r.elem IS Beg THEN e := r.elem(Beg); IF e.cur = version THEN Out.String("-- cannot delete the current version "); Out.String(version); Out.String(" in file "); Out.String(curFileName); Out.Ln; RETURN END; i := e.IndexOf(version); IF i < 0 THEN Out.F("-- pos # in ", Texts.ElemPos(e)); Out.String(curFileName); Out.String(": not allowed to delete the current version$") ELSE FOR i := i TO maxVersions - 2 DO COPY(e.vers[i+1], e.vers[i]); e.buf[i] := e.buf[i+1]; END; e.vers[maxVersions - 1] := ""; e.buf[maxVersions - 1] := NIL; Texts.OpenReader(r1, e.menu, 0); REPEAT ReadEntry(r1, s, beg, end) UNTIL (s = "") OR (s = version); IF s = version THEN Texts.Delete(e.menu, beg, end); PopupElems.MeasureMenu(e) END END END; Texts.ReadElem(r) END END Del; ÿÿÿÿ€8ÀÔ Syntax10m.Scn.Fnt +ˆýÿÿ€8ÀÔ#Syntax10.Scn.FntVV VAR r: Texts.Reader; pos: LONGINT; e: Beg; fe: FoldElems.Elem; t1: Texts.Text; BEGIN Texts.OpenReader(r, t, 0); LOOP Texts.ReadElem(r); IF r.eot THEN EXIT ELSIF r.elem IS Beg THEN pos := Texts.Pos(r) + 1; e := r.elem(Beg); e.SwitchTo(version); Texts.OpenReader(r, t, pos) ELSIF r.elem IS FoldElems.Elem THEN fe := r.elem(FoldElems.Elem); IF fe.mode = FoldElems.colLeft THEN NEW(t1); Texts.Open(t1, ""); t1.notify := NoNotify; Texts.Append(t1, fe.hidden); SwitchAll(t1, version); Texts.Delete(t1, 0, t1.len); Texts.Recall(fe.hidden) END END END END SwitchAll; ÿÿÿÿ€8ÀÔ  )²÷ÿÿ€8ÀÔ·Syntax10.Scn.FntgSyntax10m.Scn.FntˆG ;<· ¥Syntax10i.Scn.Fnt O¼˜ VAR e1: Beg; i: INTEGER; version: ARRAY 32 OF CHAR; r: Texts.Reader; BEGIN WITH e: Beg DO WITH m: TextFrames.DisplayMsg DO e.W := 7*pixel; IF ~m.prepare THEN Display.CopyPattern(Display.white, begIcon, m.X0, m.Y0+3, Display.paint) END | m: TextPrinter.PrintMsg DO IF m.prepare THEN e.W := 1 ELSE e.W := 7*pixel END | m: Texts.CopyMsg DO IF m.e = NIL THEN NEW(e1); m.e := e1 ELSE e1 := m.e(Beg) END; COPY(e.cur, e1.cur); i := 0; WHILE (i < maxVersions) & (e.vers[i] # "") DO COPY(e.vers[i], e1.vers[i]); NEW(e1.buf[i]); Texts.OpenBuf(e1.buf[i]); Texts.Copy(e.buf[i], e1.buf[i]); INC(i) END; PopupElems.Handle(e, m) | m: Texts.IdentifyMsg DO m.mod := "VersionElems"; m.proc := "AllocBeg" | m: TextFrames.TrackMsg DO IF m.keys = {MM} THEN e.CheckMenu; i := maxVersions-1; WHILE (i >= 0) & (e.vers[i] # e.cur) DO DEC(i) END; e.def := i END; PopupElems.Handle(e, m) | m: Texts.FileMsg DO PopupElems.Handle(e, m); IF m.id = Texts.load THEN Files.ReadString(m.r, e.cur); Files.ReadString(m.r, version); i := 0; WHILE version # "" DO COPY(version, e.vers[i]); Texts.Load(m.r, scratch); Texts.Delete(scratch, 0, scratch.len); NEW(e.buf[i]); Texts.Recall(e.buf[i]); INC(i); Files.ReadString(m.r, version) END; IF i < maxVersions THEN e.vers[i] := "" END ELSE (*Texts.store*) Files.WriteString(m.r, e.cur); i := 0; WHILE (i < maxVersions) & (e.vers[i] # "") DO Files.WriteString(m.r, e.vers[i]); Texts.Append(scratch, e.buf[i]); Texts.Store(m.r, scratch); Texts.Delete(scratch, 0, scratch.len); Texts.Recall(e.buf[i]); INC(i) END; Files.WriteString(m.r, "") END | m: PopupElems.ExecMsg DO Texts.OpenReader(r, e.menu, m.pos); ReadLine(r, version); IF version # "" THEN SwitchAll(Texts.ElemBase(e), version) END ELSE PopupElems.Handle(e, m) END END END HandleBeg; ÿÿÿÿ€8ÀÔ  )íüÿÿ€8ÀÔ{Syntax10.Scn.FntISyntax10m.Scn.Fntˆ e<¶™ VAR e1: End; keys: SET; x, y: INTEGER; BEGIN WITH e: End DO WITH m: TextFrames.DisplayMsg DO e.W := 7*pixel; IF ~m.prepare THEN Display.CopyPattern(Display.white, endIcon, m.X0, m.Y0+3, Display.paint) END | m: TextPrinter.PrintMsg DO e.W := 1 | m: Texts.CopyMsg DO IF m.e = NIL THEN NEW(e1); m.e := e1 ELSE e1 := m.e(End) END; Texts.CopyElem(e, e1) | m: Texts.IdentifyMsg DO m.mod := "VersionElems"; m.proc := "AllocEnd" | m: TextFrames.TrackMsg DO IF m.keys = {MM} THEN REPEAT Input.Mouse(keys, x, y); Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, x, y) UNTIL keys = {} END ELSE END END END HandleEnd; ÿÿÿÿ€8ÀÔ ÿÿÿ€8ÀÔ#Syntax10.Scn.FntQQ VAR e: Beg; BEGIN NEW(e); e.handle := HandleBeg; Texts.new := e END AllocBeg; ÿÿÿÿ€8ÀÔ ÿÿÿ€8ÀÔ#Syntax10.Scn.FntQQ VAR e: End; BEGIN NEW(e); e.handle := HandleEnd; Texts.new := e END AllocEnd; ÿÿÿÿ€8ÀÔ õüÿÿ€8ÀÔ#Syntax10.Scn.Fntéé VAR a: Beg; b: End; t: Texts.Text; beg, end, time: LONGINT; version: ARRAY 32 OF CHAR; BEGIN Oberon.GetSelection(t, beg, end, time); IF time >= 0 THEN In.Open; Read(version); IF In.Done THEN NEW(a); a.W := 7*pixel; a.H := 11*pixel; a.handle := HandleBeg; COPY(version, a.cur); a.vers[0] := ""; a.menu := TextFrames.Text(""); Texts.WriteString(w, version); Texts.Append(a.menu, w.buf); PopupElems.MeasureMenu(a); Texts.WriteElem(w, a); Texts.Insert(t, beg, w.buf); NEW(b); b.W := 7*pixel; b.H := 11*pixel; b.handle := HandleEnd; Texts.WriteElem(w, b); Texts.Insert(t, end+1, w.buf); SwitchAll(t, version) ELSE Out.String("-- invalid version name$") END ELSE Out.String("-- no selection$") END END Insert; ÿÿÿÿ€8ÀÔ ¿ÿÿÿ€8ÀÔ#Syntax10.Scn.Fnt BEGIN Do(SwitchAll) END Set; ÿÿÿÿ€8ÀÔ Âÿÿÿ€8ÀÔ#Syntax10.Scn.Fnt BEGIN Do(Del) END Delete; ÿÿÿÿ€8ÀÔ¿MODULE VersionElems;  (* HM 14 Sep 95 /  *)  IMPORT Display, Files, Input, Viewers, Texts, TextFrames, TextPrinter, Oberon, PopupElems, FoldElems, In, Out; CONST maxVersions = 4; pixel = LONG(10000); ML = 2; MM = 1; MR = 0; TYPE Beg* = POINTER TO BegDesc; BegDesc* = RECORD (PopupElems.ElemDesc) cur: ARRAY 32 OF CHAR; (*current version*) vers-: ARRAY maxVersions, 32 OF CHAR; (*version names*) buf: ARRAY maxVersions OF Texts.Buffer (*version texts*) END;  End* = POINTER TO EndDesc; EndDesc* = RECORD (Texts.ElemDesc) END; ActionProc = PROCEDURE (t: Texts.Text; version: ARRAY OF CHAR); VAR begIcon, endIcon: Display.Pattern; (* x = 0, y = 3, w = 6, h = 9 *) scratch: Texts.Text; curFileName: ARRAY 128 OF CHAR; (* current file in iterator Do *) w: Texts.Writer; PROCEDURE InitIcons;  PROCEDURE NoNotify (t: Texts.Text; op: INTEGER; beg, end: LONGINT);  PROCEDURE Read (VAR s: ARRAY OF CHAR);  PROCEDURE ReadLine (VAR r: Texts.Reader; VAR line: ARRAY OF CHAR);  PROCEDURE (e: Beg) IndexOf (version: ARRAY OF CHAR): INTEGER;  PROCEDURE (e: Beg) CheckMenu;  PROCEDURE (e: Beg) TwinPos (): LONGINT;  PROCEDURE (e: Beg) SwitchTo (version: ARRAY OF CHAR);  PROCEDURE Do (P: ActionProc);  PROCEDURE Del (t: Texts.Text; version: ARRAY OF CHAR);  PROCEDURE SwitchAll* (t: Texts.Text; version: ARRAY OF CHAR);  PROCEDURE HandleBeg* (e: Texts.Elem; VAR m: Texts.ElemMsg);  PROCEDURE HandleEnd* (e: Texts.Elem; VAR m: Texts.ElemMsg);  PROCEDURE AllocBeg*;  PROCEDURE AllocEnd*;  PROCEDURE Insert*;  PROCEDURE Set*;  PROCEDURE Delete*;  BEGIN InitIcons; Texts.OpenWriter(w); NEW(scratch); Texts.Open(scratch, ""); scratch.notify := NoNotify END VersionElems.