DIRECTORY JunoProcViewer, Rope USING [ROPE, Length, Equal], ViewerClasses USING [Viewer], ViewerOps USING [CreateViewer, DestroyViewer], TiogaOps USING [Ref, CallWithLocks, ViewerDoc, LastWithin, SelectNodes, Break, UnNest, InsertRope, Nest, SelectBranches, Location, FirstChild, SelectPoint, SetSelection, AddLooks, GetRope, GoToNextCharacter, Next]; JunoProcViewerImpl: CEDAR PROGRAM IMPORTS Rope, ViewerOps, TiogaOps EXPORTS JunoProcViewer = BEGIN OPEN Rope, JunoProcViewer; TiogaNode: TYPE = TiogaOps.Ref; NewViewer: PUBLIC PROC RETURNS [viewer: Viewer] = BEGIN viewer _ ViewerOps.CreateViewer [flavor: $Text, info: [column: right, iconic: FALSE], paint: TRUE]; -- !! register tioga procs to detect when the contents is edited END; DoInsertText: PROC [viewer: Viewer, n: TiogaNode, text1, text2: ROPE, errBeg, errEnd: INT _ -1] = {TiogaOps.SelectBranches [viewer: viewer, start: n, end: n, level: char, pendingDelete: TRUE]; TiogaOps.InsertRope[text1]; TiogaOps.Break[]; TiogaOps.Nest[]; TiogaOps.InsertRope[text2]; IF errBeg >= 0 THEN {m: TiogaNode _ TiogaOps.FirstChild[n]; nLen: INT = text1.Length; Loc: PROC [pos: INT] RETURNS [TiogaOps.Location] = {RETURN[IF pos < nLen THEN [n, pos] ELSE [m, pos-nLen]]}; locBeg: TiogaOps.Location = Loc[errBeg]; TiogaOps.SelectPoint[viewer, Loc[errEnd]]; TiogaOps.InsertRope["\n"]; TiogaOps.SelectPoint[viewer, locBeg]; TiogaOps.InsertRope["\nERROR: "]; TiogaOps.SetSelection[viewer, [locBeg.node, locBeg.where+1], [locBeg.node, locBeg.where+5]]; TiogaOps.AddLooks[looks: "b"]}}; ParseViewer: PUBLIC PROC [viewer: Viewer, Proc: BranchVisitProc] RETURNS [nerrors: INTEGER] = BEGIN DoParseViewer: PROC [root: TiogaNode] = {n: TiogaNode _ TiogaOps.FirstChild[root]; nok: INT _ 0; -- number of correct nodes firstError: TiogaOps.Location; nerrors _ 0; IF viewer.destroyed THEN RETURN; -- Should test whether the viewer has been edited since last call WHILE n # NIL DO m: TiogaNode = TiogaOps.FirstChild[n]; text1: ROPE = TiogaOps.GetRope[n]; text2: ROPE = TiogaOps.GetRope[m]; new1, new2: ROPE; errBeg, errEnd: INT; TRUSTED {[new1, new2, errBeg, errEnd] _ Proc[text1, text2]}; IF NOT Rope.Equal[text1, new1] OR NOT Rope.Equal[text2, new2] OR errBeg >= 0 THEN {DoInsertText[viewer, n, new1, new2, errBeg, errEnd]}; IF errBeg >=0 THEN {nerrors _ nerrors+1; IF nerrors = 1 THEN firstError _ [n, errBeg]; IF nerrors > 10 AND nerrors > nok/5 THEN {TiogaOps.SelectPoint[viewer: viewer, caret: [firstError.node, 0]]; TiogaOps.GoToNextCharacter[firstError.where]; RETURN}; n _ TiogaOps.Next[n]}; ENDLOOP}; TiogaOps.CallWithLocks[DoParseViewer, TiogaOps.ViewerDoc[viewer]] END; AddBranch: PUBLIC PROC [viewer: Viewer, text1, text2: ROPE] = BEGIN DoAddText: SAFE PROC[root: TiogaOps.Ref] = CHECKED {nd: TiogaOps.Ref; IF viewer.destroyed THEN RETURN; nd _ TiogaOps.LastWithin[TiogaOps.ViewerDoc[viewer]]; TiogaOps.SelectNodes[viewer: viewer, start: nd, end: nd, level: node, caretBefore: FALSE]; TiogaOps.Break[]; TiogaOps.UnNest[]; DoInsertText[viewer, nd, text1, text2]}; TiogaOps.CallWithLocks[DoAddText, TiogaOps.ViewerDoc[viewer]] END; CondDestroyViewer: PROC [viewer: Viewer] = {-- Maybe we should we lock the viewer before testing newVersion IF NOT viewer.newVersion THEN ViewerOps.DestroyViewer[viewer]}; END. PN2: PROC [n: TiogaNode, pw: Handle] RETURNS [success: BOOL, tree: REF ANY, text1: ROPE, text2: ROPE] = {r: Rope.ROPE; vc: VerdictAndCulprit; errorMessage: ROPE _ NIL; text1 _ TiogaOps.GetRope[n]; text2 _ TiogaOps.GetRope[TiogaOps.FirstChild[n]]; -- next three lines try to skip parsing if old parsed result is present in pw.contents: { l: LIST OF NodeContent _ pw.content ; WHILE l # NIL AND NOT(Rope.Equal[l.first.text1, text1] AND Rope.Equal[l.first.text2, text2]) DO l _ l.rest ENDLOOP ; IF l # NIL THEN { success _ TRUE ; tree _ l.first.tree ; text1 _ l.first.text1; text2 _ l.first.text2 ; RETURN } }; IF ~ pw.contentValid THEN RETURN; pw.ph.in.in _ IO.RIS[Rope.Cat[text1, text2, " "]]; pw.ph.in.eof _ FALSE; pw.ph.in.error _ NIL; pw.ph.in.Lex[]; IF pw.ph.in.eof THEN {success _ TRUE; tree _ text1 _ text2 _ NIL; RETURN}; pw.ph.Parse[]; pw.ph.result _ tree _ CONS[pw.ph.result, NIL]; -- necessary because WellFormed and Unparse work on the CAR of their argument -- and ignore the cdr. IF pw.ph.error = NIL AND pw.ph.eof THEN {vc _ pw.WellFormed[pw.ph.result]; IF vc.verdict # Yes THEN errorMessage _ "Not a WFF" ELSE {vc.culprit _ NIL; errorMessage _ NIL}} ELSE {vc.culprit _ NIL; errorMessage _ IF pw.ph.error # NIL THEN pw.ph.error ELSE "Bad Syntax"}; r _ Unparser.Unparse[pw.ph.result, vc.culprit, 57, pw.ph.table, pw.ph.openCount]; --! change "57" to "width of window" tree _ NARROW[pw.ph.result, LIST OF REF ANY].first; IF pw.ph.error # NIL OR ~pw.ph.eof THEN {r _ Rope.Cat[r, " \000", Rope.FromRefText[pw.ph.in.buf], "\000"]; WHILE ~ IO.EndOf[pw.ph.in.in] DO r _ Rope.Cat[r, Rope.FromChar[IO.GetChar[pw.ph.in.in]]] ENDLOOP}; {i: INT _ r.SkipTo[0, "\000"]; j: INT; endOfHeader: INT = r.SkipTo[0, "\n"]; firstLine: Rope.ROPE = r.Substr[0, endOfHeader]; restOfLines: Rope.ROPE = IF endOfHeader = r.Length THEN NIL ELSE r.Substr[endOfHeader + 1]; Foo: SAFE PROC[root: TiogaOps.Ref] = TRUSTED {m: TiogaNode = IF TiogaOps.FirstChild[n] = NIL THEN n ELSE TiogaOps.FirstChild[n]; TiogaOps.SelectNodes[viewer: pw.viewer, start:n, end:m, pendingDelete: TRUE, level:char]; IF i = r.Length[] THEN {TiogaOps.InsertRope[firstLine]; TiogaOps.Break[]; TiogaOps.Nest[]; TiogaOps.InsertRope[restOfLines]} ELSE {j _ r.SkipTo[i + 1, "\000"]; TiogaOps.InsertRope[Rope.Cat[r.Substr[0, i], r.Substr[i+1, j - i - 1], r.Substr[j+1]]]; TiogaOps.SetSelection[pw.viewer, [n, i], [n, j - 1]]}}; TiogaOps.CallWithLocks[Foo, TiogaOps.ViewerDoc[pw.viewer]]; success _ (errorMessage = NIL); text1 _ firstLine; text2 _ restOfLines}}; æ JunoProcViewerImpl.mesa (ex OldParseWindowImpl.mesa) Coded September 6, 1982 12:26 am Last Edited by: Gnelson, January 17, 1984 11:56 am Last Edited by: Stolfi June 13, 1984 11:17:30 am PDT Maintains a text viewer containing the current set of Juno procedures. Exports procedures that search this list and that append new procedures to it. The viewer has two extra menu buttons: Parse: parses the viewer contents, saves the result as the "current global alist",unparses it, and stuffs the unparsed text back into the viewer. NewProc: Appends a new node to the viewer, with the skeleton of a procedure declaration (to be edited by the user). NewProc: Appends a new node to the viewer, with the skeleton of a procedure declaration (to be edited by the user). TO FIX: Everything. - - - - PUBLIC PROCEDURES To be called through TiogaOps.CallWithLocks. Inserts text1, text2, (and error flag, if errBeg >= 0) at current selection (which should include all of the level Parses the contents of the viewer and rebuilds AList. Resets the notParsed flag. To be called by the top level program before refreshing the image Adds a new branch (with one nested child) at the end of the viewer. Destroys a viewer if contents is safe. - - - - JUNK Ê„˜šœ5™5™Jšœ ™ Jšœ2™2Jšœ6™6—™˜™'J™‘J™s—J™s——JšœÏbœ ™šœÏk ˜ Jš œžœžœ žœžœ)žœÓ˜á—šœœž ˜"šœž˜Jšœ˜—šœž˜Jšœ˜——šœž˜šœž˜Jšœ˜——šœ™Jšœ žœ˜ š œÏn œžœžœžœ˜2šœž˜šœ ˜ Jšœ:žœ žœ˜Q—JšœB˜B—Jšœžœ˜—š œŸ œžœ0žœžœ˜dJšœ¢™¢Jšœ]žœcžœ žœ7žœŸœžœžœžœžœžœ žœ žœî˜ö—š œŸ œžœžœ+žœ žœ˜`J™PJ™Cšœž˜šœŸ œžœ˜(Jš;œ2žœÏcœ/žœžœžœ Bœžœžœžœ7žœ#žœ(žœžœžœ:žœžœžœžœžœ žœCžœ žœ&žœ žœ#žœžœžœ–žœ žœ˜ß—JšœB˜B—Jšœžœ˜—š œŸ œžœžœ žœ˜>J™Dšœž˜šœŸ œžœžœž˜4Jš œžœžœžœ‘žœS˜—Jšœ>˜>—Jšœžœ˜—šœŸœžœ˜+J™&Jš œ 5œ  œžœžœžœ"˜‚——Jšœžœ˜šœ ™ šœŸœžœžœ žœžœžœ žœ žœ˜kJš­œ žœ-žœžœZ Xœžœžœžœžœ žœžœ"žœ-žœ žœžœžœžœ žœHžœ žœžœžœžœžœ1žœžœžœžœ žœžœžœ/žœžœ  Nœ œžœžœžœžœ2žœ žœ*žœžœžœžœžœžœžœžœ žœo %œ žœžœžœžœžœ žœžœžœžœPžœžœ"žœžœ&žœ žœžœžœ*žœ3žœ žœžœžœžœ Ÿœžœžœžœžœžœžœžœgžœžœžœ¡žœ°žœ8˜é———…— "v