<<>> <> <> <> <> <> <> <<>> DIRECTORY Commander, CommanderOps, FileViewerOps, FileViewerOpsBackdoor, Menus USING [MouseButton], MessageWindow USING [Append, Blink, Clear], NodeAddrs USING [PutTextAddr, GetTextAddr, TextAddrNotFound], RefTab USING [Fetch, Create, Ref, Store], Rope, TEditSelectionOps USING [ShowGivenPositionRange], TextNode USING [BadArgs, Location, LocWithin, Ref, LocOffset], TiogaOps USING [FirstChild, Location, SetSelection, SelectionError, ViewerDoc], TiogaMenuOps, ViewerClasses USING [Viewer], ViewerTools USING [GetContents]; CycleThruErrorLog: CEDAR PROGRAM IMPORTS Commander, CommanderOps, FileViewerOps, FileViewerOpsBackdoor, MessageWindow, NodeAddrs, RefTab, Rope, TEditSelectionOps, TextNode, TiogaOps, TiogaMenuOps, ViewerTools = BEGIN OPEN FileViewerOpsBackdoor; ROPE: TYPE = Rope.ROPE; Viewer: TYPE = ViewerClasses.Viewer; ErrorLocRec: TYPE = RECORD[node: TextNode.Ref, uniq: REF INT, start, end: TiogaOps.Location, nxt, prev: ErrorLoc]; ErrorLoc: TYPE = REF ErrorLocRec; ErrListRec: TYPE = RECORD[root: TextNode.Ref, headLoc, curLoc: ErrorLoc]; ErrList: TYPE = REF ErrListRec; -- ErrList is a pointer to a doubly linked list of ErrLoc's <> CycleThruErrorLog: ErrorLogProc = { <> any: REF ANY; errList: ErrList; found: BOOLEAN; viewer: Viewer = NARROW[parent]; count: INT; loc: TextNode.Location; <> FOR v: ViewerClasses.Viewer ¬ parent, v.link UNTIL v = NIL DO [found, any] ¬ RefTab.Fetch[viewerTable, v]; IF found OR v.link = parent THEN EXIT; ENDLOOP; IF ~found OR ~repeat THEN { errList ¬ NEW[ErrListRec]; MakeErrList[errList, log, viewer]; [] ¬ RefTab.Store[viewerTable, parent, errList]; } ELSE { errList ¬ NARROW[any]; }; IF control THEN IF mouseButton = red THEN { FileViewerOps.RemoveErrorLog[viewer.file]; RETURN; } ELSE { -- new errlog file errList ¬ NEW[ErrListRec]; MakeErrList[errList, log, viewer]; [] ¬ RefTab.Store[viewerTable, parent, errList]; }; WHILE TRUE DO { ENABLE { NodeAddrs.TextAddrNotFound, TextNode.BadArgs => { IF mouseButton = yellow THEN { MessageWindow.Append["Position of first error has been erased!", TRUE]; MessageWindow.Blink[]; GOTO done } ELSE LOOP; }; }; IF errList = NIL OR errList.headLoc = NIL THEN RETURN; IF mouseButton = red THEN { IF errList.curLoc = NIL THEN errList.curLoc ¬ errList.headLoc ELSE IF errList.curLoc.nxt # NIL THEN errList.curLoc ¬ errList.curLoc.nxt ELSE {MessageWindow.Append["At last error", TRUE]; MessageWindow.Blink[]; RETURN;}; } ELSE IF mouseButton = blue THEN { IF errList.curLoc = NIL THEN errList.curLoc ¬ errList.headLoc ELSE IF errList.curLoc.prev # NIL THEN errList.curLoc ¬ errList.curLoc.prev ELSE {MessageWindow.Append["At first error", TRUE]; MessageWindow.Blink[]; RETURN;}; } ELSE errList.curLoc ¬ errList.headLoc; MessageWindow.Clear[]; [loc.node, loc.where] ¬ NodeAddrs.GetTextAddr[errList.curLoc.node, errList.curLoc.uniq]; count ¬ TextNode.LocOffset[TextNode.LocWithin[errList.root, 0, 1, TRUE], loc, 1, TRUE]; TiogaOps.SetSelection[log, errList.curLoc.start, errList.curLoc.end ! TiogaOps.SelectionError => { MakeErrList[errList, log, viewer]; GOTO done; } ]; TiogaMenuOps.Normalize[log]; TEditSelectionOps.ShowGivenPositionRange[ viewer: viewer, selectionId: feedback, posI: count, posF: count+2, skipCommentNodes: TRUE, pendingDelete: FALSE] EXITS done => RETURN; }; RETURN; ENDLOOP; }; MakeErrList: PROC[errList: ErrList, log, viewer: ViewerClasses.Viewer] = { i, prevStart: INT ¬ 0; pos, this: INT; vRope: ROPE; prevloc, curloc: ErrorLoc; loc: TextNode.Location; root, vRopeNode: TextNode.Ref; TiogaMenuOps.Reset[log]; vRope ¬ ViewerTools.GetContents[log]; root ¬ TiogaOps.ViewerDoc[viewer]; vRopeNode ¬ TiogaOps.FirstChild[TiogaOps.ViewerDoc[log]]; errList.root ¬ root; errList.headLoc ¬ NIL; DO ch: CHAR; this ¬ Rope.Find[vRope, "[", i]; IF this < 0 THEN EXIT; pos ¬ 0; i ¬ this; DO ch ¬ Rope.Fetch[vRope, i ¬ i + 1]; IF ch IN ['0 .. '9] THEN pos ¬ (pos *10 ) + ORD[ch] - ORD['0] ELSE EXIT; ENDLOOP; IF ( ch # '] ) OR ( i = this + 1 ) THEN LOOP; -- skip [] curloc ¬ NEW[ErrorLocRec]; curloc.start ¬ [vRopeNode, this]; curloc.end ¬ [vRopeNode, i]; prevStart ¬ this; loc ¬ TextNode.LocWithin[n: root, count: pos, break: 1, skipCommentNodes: TRUE]; IF errList.headLoc = NIL THEN { errList.headLoc ¬ curloc; prevloc ¬ NIL }; curloc.prev ¬ prevloc; curloc.nxt ¬ NIL; curloc.node ¬ loc.node; curloc.uniq ¬ NEW[INT ¬ i]; -- This could be new of anything NodeAddrs.PutTextAddr[loc.node, curloc.uniq, loc.where]; IF prevloc # NIL THEN prevloc.nxt ¬ curloc; prevloc ¬ curloc; ENDLOOP; errList.curLoc ¬ NIL; }; <> ActivateErrorLogProc: Commander.CommandProc = { <<[cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL]>> sourceFileName: Rope.ROPE; <> args: LIST OF Rope.ROPE ¬ CommanderOps.ParseToList[cmd: cmd].list; IF args = NIL THEN RETURN [$Failure, "Usage: ActivateErrorLog filename"]; IF args.rest # NIL THEN RETURN [$Failure, "Usage: ActivateErrorLog filename"]; sourceFileName ¬ Rope.Concat[args.first, ".mesa"]; FileViewerOps.ShowLog[sourceFileName]; FileViewerOps.AttachErrorLog[sourceFileName]; }; UnRegisterErrorLogProc: Commander.CommandProc ~ { UnregisterErrorLogProc[CycleThruErrorLog] }; <> viewerTable: RefTab.Ref; viewerTable ¬ RefTab.Create[]; RegisterErrorLogProc[CycleThruErrorLog, NIL]; Commander.Register[ key: "ActivateErrorLog", proc: ActivateErrorLogProc, doc: "Brings up a file and adds an errlog button."]; Commander.Register[ key: "ErrorLogParsers.UnRegister", proc: UnRegisterErrorLogProc]; END.