DIRECTORY ConvertUnsafe USING [ToRope], ExecOps USING [Outcome], Directory USING [Lookup], Feedback USING [BeginItemProc, CreateProc, DestroyProc, FinishItemProc, NoteProgressProc, Procs], File USING [Capability], IconRegistry USING [GetIcon, RegisterIcon], Icons USING [IconFlavor], InputFocus USING [GetInputFocus], IO USING [char, Error, GetToken, IDProc, noWhereStream, Put, PutF, PutRope, ROPE, rope, ResetUserAbort, SkipOver, STREAM, string, TokenProc, UserAborted, WhiteSpace], List USING [Nconc1], Menus USING [AppendMenuEntry, MenuEntry, ReplaceMenuEntry, FindEntry, ClickProc, CreateEntry, Menu], MessageWindow USING [Append, Blink], Process USING [Detach, GetPriority, MsecToTicks, Pause, Priority, priorityBackground, SetPriority, Ticks], Rope USING [Cat, Concat, Equal, Fetch, Find, IsEmpty, Length, Letter, ROPE, Substr, ToRefText], Runtime USING [IsBound, RunConfig], TemporarySpecialExecOps USING [BindUsingFeedback, CompileUsingFeedback], TiogaMenuOps USING [Open], TiogaOps USING [CommandProc, RegisterCommand], UserExec USING [AcquireResource, CheckForFile, CommandProc, ExecHandle, GetExecHandle, GetStreams, GetTheFile, HistoryEvent, RegisterCommand, RegisterTransformation, TransformProc, ReleaseResource, RopeSubst, UserAborted], UserExecExtras USING [], UserExecPrivate USING [ForAllSplitViewers, ExecPrivateRecord, HistoryEventPrivateRecord, RenameFile, SplitViewerProc, WaitUntilSaved], UserProfile USING [Boolean, CallWhenProfileChanges, ProfileChangedProc, Token], ViewerClasses USING [Column, Viewer], ViewerEvents USING [RegisterEventProc, EventProc], ViewerOps USING [BlinkIcon, CreateViewer, DestroyViewer, FindViewer, OpenIcon, RestoreViewer, PaintViewer], ViewerTools USING [GetSelectedViewer] ; CompilerExecOpsImpl: CEDAR MONITOR IMPORTS ConvertUnsafe, Directory, IconRegistry, InputFocus, IO, List, Menus, MessageWindow, Process, Rope, Runtime, TemporarySpecialExecOps, TiogaMenuOps, TiogaOps, UserExec, UserExecPrivate, UserProfile, ViewerEvents, ViewerOps, ViewerTools EXPORTS UserExec, UserExecPrivate SHARES UserProfile = BEGIN OPEN IO; ExecHandle: TYPE = UserExec.ExecHandle; HistoryEvent: TYPE = UserExec.HistoryEvent; Viewer: TYPE = ViewerClasses.Viewer; ClickProc: TYPE = Menus.ClickProc; ExecPrivateRecord: PUBLIC TYPE = UserExecPrivate.ExecPrivateRecord; HistoryEventPrivateRecord: PUBLIC TYPE = UserExecPrivate.HistoryEventPrivateRecord; Bind: UserExec.CommandProc -- [exec: ExecHandle] RETURNS[ok: BOOLEAN _ TRUE] -- = { ENABLE FailedToLoad => GOTO Failed; -- so don't get log, which contains result of last binding.. outCome: ExecOps.Outcome _ RunBinder[event, exec]; [] _ ShowLog["Binder.log", outCome = ok, exec]; RETURN[outCome = ok]; EXITS Failed => RETURN[FALSE]; }; RunBinder: PROC [event: HistoryEvent, exec: ExecHandle] RETURNS[outCome: ExecOps.Outcome] = TRUSTED { -- Process.SetPriority, BindUsingFeedback, RunConfig, Lookup priority: Process.Priority = Process.GetPriority[]; out: STREAM ; Release: PROC = TRUSTED {[] _ UserExec.ReleaseResource[$Binder]; Process.SetPriority[priority]}; { ENABLE UNWIND => Release[]; someMissing: BOOLEAN _ FALSE; line: ROPE; [] _ UserExec.AcquireResource[resource: $Binder, owner: "Binder", exec: exec]; binderRec.exec _ exec; [binderRec.in, binderRec.out] _ UserExec.GetStreams[exec]; out _ binderRec.out; Process.SetPriority[Process.priorityBackground]; IF NOT Runtime.IsBound[TemporarySpecialExecOps.BindUsingFeedback] THEN { ENABLE ANY => GOTO FailedToLoad; out.PutF["*mLoading Binder.bcd...\n*s"]; Runtime.RunConfig[Directory.Lookup["Binder.bcd"L], 1, TRUE]; }; [line, , someMissing] _ ProcessLine[ext: "config", event: event, exec: exec]; binderRec.cmdText _ LOOPHOLE[Rope.ToRefText[Rope.Concat[binderSwitches, line]], REF StringBody]; binderRec.cmd _ LOOPHOLE[@(binderRec.cmdText.text)]; binderRec.abort _ FALSE; outCome _ TemporarySpecialExecOps.BindUsingFeedback[binderRec.cmd, @binderProcs]; IF someMissing THEN outCome _ errors; EXITS FailedToLoad => {UserExec.GetStreams[exec].out.PutF["*eBinder Failed to load.*s\n"]; Release[]; ERROR FailedToLoad}; }; Release[]; IF outCome = aborted THEN UserExec.UserAborted[exec]; }; BCreate: Feedback.CreateProc = {RETURN[NIL]}; BDestroy: Feedback.DestroyProc = { binderRec.out.Put[string[trailer] ! IO.Error => IF ec = StreamClosed THEN {binderRec.abort _ TRUE; CONTINUE}; IO.UserAborted, ABORTED => {binderRec.abort _ TRUE; CONTINUE}; ]; }; BBeginItem: Feedback.BeginItemProc = { binderRec.out.Put[string[item] ! IO.Error => IF ec = StreamClosed THEN {binderRec.abort _ TRUE; CONTINUE}; IO.UserAborted, ABORTED => {binderRec.abort _ TRUE; CONTINUE}; ]; }; BNoteProgress: Feedback.NoteProgressProc = { binderRec.out.PutRope[" ." ! IO.Error => IF ec = StreamClosed THEN {binderRec.abort _ TRUE; CONTINUE}; IO.UserAborted, ABORTED => {binderRec.abort _ TRUE; CONTINUE}; ]; IF binderRec.abort THEN { binderRec.in.ResetUserAbort[]; ERROR IO.UserAborted; }; }; BFinishItem: Feedback.FinishItemProc = { binderRec.out.PutF[" %g\n", string[trailer] ! IO.Error => IF ec = StreamClosed THEN {binderRec.abort _ TRUE; CONTINUE}; IO.UserAborted, ABORTED => {binderRec.abort _ TRUE; CONTINUE}; ]; }; binderProcs: Feedback.Procs _ [BCreate, BDestroy, BBeginItem, BNoteProgress, BFinishItem]; BinderRec: TYPE = RECORD[ cmdText: REF StringBody _ NIL, cmd: LONG POINTER TO PACKED ARRAY [0..0) OF CHARACTER _ NIL, exec: ExecHandle _ NIL, in, out: STREAM _ NIL, separateLogs: BOOL _ FALSE, openLogs: BOOL _ TRUE, abort: BOOL _ FALSE, numberOfFiles: INT _ 0, thisFile, warnings, errors: ROPE _ NIL ]; FailedToLoad: ERROR = CODE; binderRec: REF BinderRec _ NEW[BinderRec _ []]; needsToBeCompiled, errorsOrWarnings: LIST OF ROPE _ NIL; saveOldLog: BOOL _ TRUE; compilerRec: REF BinderRec _ NEW[BinderRec _ []]; compilerSwitches, binderSwitches: ROPE _ NIL; SetDefaultSwitches: UserProfile.ProfileChangedProc = { compilerSwitches _ UserProfile.Token["Compiler.Switches"]; IF UserProfile.Boolean["Compiler.SeparateLogs", FALSE] THEN compilerSwitches _ Rope.Concat["/-g", compilerSwitches]; IF NOT Rope.IsEmpty[compilerSwitches] THEN compilerSwitches _ Rope.Concat[compilerSwitches, ";"]; --for Ed's parser binderSwitches _ UserProfile.Token["Binder.Switches"]; IF NOT Rope.IsEmpty[binderSwitches] THEN binderSwitches _ Rope.Concat[binderSwitches, ";"]; --for Ed's parser destroyLogOnSuccess _ UserProfile.Boolean["Compiler.DestroyLogOnSuccess", TRUE]; }; Compile: UserExec.CommandProc = { ENABLE FailedToLoad => GOTO Failed; outCome: ExecOps.Outcome; IF saveOldLog THEN [] _ UserExecPrivate.RenameFile[oldName: "Compiler.log", newName: "Compiler.log$", out: IO.noWhereStream]; IO.SkipOver[event.commandLineStream, IO.WhiteSpace]; outCome _ RunCompiler[event, exec]; SELECT outCome FROM ok, warnings => RETURN[TRUE]; -- so user can write compile ... ; bind ... and not have it stop because of warnings. ENDCASE => RETURN[FALSE]; EXITS Failed => RETURN[FALSE]; }; CompileBadGuys: UserExec.TransformProc = { IF errorsOrWarnings = NIL THEN { UserExec.GetStreams[exec].out.PutF["*n*mEverybody's cool.*u\n"]; RETURN[NIL]; }; result _ NIL; FOR l: LIST OF ROPE _ errorsOrWarnings, l.rest UNTIL l = NIL DO result _ Rope.Cat[result, " ", l.first]; ENDLOOP; RETURN[Rope.Cat["Compile", result, "\n"]]; }; -- of CompileBadGuys CompileAll: UserExec.TransformProc = { IF needsToBeCompiled = NIL THEN { UserExec.GetStreams[exec].out.PutF["*n*mEverybody's cool.*u\n"]; RETURN[NIL]; }; result _ NIL; FOR l: LIST OF ROPE _ needsToBeCompiled, l.rest UNTIL l = NIL DO result _ Rope.Cat[result, " ", l.first]; ENDLOOP; RETURN[Rope.Cat["Compile", result, "\n"]]; }; -- of CompileBadGuys RunCompiler: PROC [event: HistoryEvent, exec: ExecHandle] RETURNS[outCome: ExecOps.Outcome] = TRUSTED { priority: Process.Priority = Process.GetPriority[]; out: STREAM; Release: PROC = TRUSTED {[] _ UserExec.ReleaseResource[$Compiler]; Process.SetPriority[priority]}; { ENABLE UNWIND => Release[]; someMissing: BOOLEAN _ FALSE; line: ROPE; files: LIST OF ROPE; i: INT; [] _ UserExec.AcquireResource[resource: $Compiler, owner: "Compiler", exec: exec]; compilerRec.exec _ exec; [compilerRec.in, compilerRec.out] _ UserExec.GetStreams[exec]; out _ compilerRec.out; Process.SetPriority[Process.priorityBackground]; IF NOT Runtime.IsBound[TemporarySpecialExecOps.CompileUsingFeedback] THEN { ENABLE ANY => GOTO FailedToLoad; out.PutF["*mLoading Compiler.bcd...\n*s"]; Runtime.RunConfig[Directory.Lookup["Compiler.bcd"L], 1, TRUE]; }; [line, files, someMissing] _ ProcessLine[ext: "mesa", event: event, exec: exec]; line _ Rope.Concat[compilerSwitches, line]; compilerRec.separateLogs _ ((i _ Rope.Find[line, "/-g"]) # -1 AND Rope.Find[s1: line, s2: "/g", pos1: i] = -1); compilerRec.openLogs _ TRUE; compilerRec.abort _ FALSE; compilerRec.cmdText _ LOOPHOLE[Rope.ToRefText[line], REF StringBody]; compilerRec.cmd _ LOOPHOLE[@(compilerRec.cmdText.text)]; compilerRec.errors _ compilerRec.warnings _ NIL; compilerRec.numberOfFiles _ 0; outCome _ TemporarySpecialExecOps.CompileUsingFeedback[compilerRec.cmd, @compilerProcs]; IF compilerRec.warnings # NIL THEN out.PutF["*n*m-- Warnings in --*s%g", rope[compilerRec.warnings]]; IF compilerRec.errors # NIL THEN out.PutF["*n*e-- Errors in --*s%g", rope[compilerRec.errors]]; IF NOT Rope.Find[s1: line, s2: "/-g", case: FALSE] # -1 THEN [] _ ShowLog["Compiler.log", outCome = ok, exec] EXITS FailedToLoad => {out.PutF["*eCompiler Failed to load.*s\n"]; Release[]; ERROR FailedToLoad}; }; Release[]; IF outCome = aborted THEN UserExec.UserAborted[exec]; }; CCreate: Feedback.CreateProc = {RETURN[NIL]}; CDestroy: Feedback.DestroyProc = { compilerRec.out.Put[string[trailer] ! IO.Error => IF ec = StreamClosed THEN {compilerRec.abort _ TRUE; CONTINUE}; IO.UserAborted, ABORTED => {compilerRec.abort _ TRUE; CONTINUE}; ]; }; CBeginItem: Feedback.BeginItemProc = { compilerRec.out.Put[string[item] ! IO.Error => IF ec = StreamClosed THEN {compilerRec.abort _ TRUE; CONTINUE}; IO.UserAborted, ABORTED => {compilerRec.abort _ TRUE; CONTINUE}; ]; TRUSTED { thisFile: ROPE _ ConvertUnsafe.ToRope[item]; i: INT; thisFile _ Rope.Substr[base: thisFile, start: 11]; -- to strip off the "Compiling: " i _ Rope.Find[thisFile, "/"]; IF i # -1 THEN thisFile _ Rope.Substr[base: thisFile, len: i]; compilerRec.thisFile _ thisFile; }; }; CNoteProgress: Feedback.NoteProgressProc = { compilerRec.out.PutRope[" ." ! IO.Error => IF ec = StreamClosed THEN {compilerRec.abort _ TRUE; CONTINUE}; IO.UserAborted, ABORTED => {compilerRec.abort _ TRUE; CONTINUE}; ]; IF compilerRec.abort THEN { compilerRec.in.ResetUserAbort[]; ERROR IO.UserAborted; }; }; CFinishItem: Feedback.FinishItemProc = { name: ROPE = Rope.Concat[compilerRec.thisFile, ".mesa"]; viewer: Viewer _ ViewerOps.FindViewer[name]; space: ROPE = " "; compilerRec.numberOfFiles _ compilerRec.numberOfFiles + 1; compilerRec.out.Put[char[' ], string[trailer], char['\n] ! IO.Error => IF ec = StreamClosed THEN {compilerRec.abort _ TRUE; CONTINUE}; IO.UserAborted, ABORTED => {compilerRec.abort _ TRUE; CONTINUE}; ]; SELECT outcome FROM warnings, errors, errorsAndWarnings => { IF outcome = warnings THEN compilerRec.warnings _ Rope.Cat[compilerRec.warnings, space, compilerRec.thisFile] ELSE compilerRec.errors _ Rope.Cat[compilerRec.errors, space, compilerRec.thisFile]; AddIt[compilerRec.thisFile, TRUE]; IF compilerRec.separateLogs THEN { createIconic: BOOLEAN _ TRUE; exec: UserExec.ExecHandle = compilerRec.exec; log: Viewer; IF exec # NIL AND NOT exec.viewer.iconic AND (InputFocus.GetInputFocus[].owner = exec.viewer) AND compilerRec.openLogs THEN createIconic _ FALSE; -- this test is also in ShowLog, but that isn't being called now IF UserProfile.Boolean["Compiler.IconicLogs", FALSE] THEN createIconic _ TRUE; IF viewer = NIL THEN { IF createIconic THEN viewer _ ViewerOps.CreateViewer[flavor: $Text, info: [name: name, file: name, iconic: TRUE, icon: IconRegistry.GetIcon[iconName: "NeedsToBeCompiled", default: document]]] ELSE viewer _ TiogaMenuOps.Open[name]; -- the icon will be changed below } ELSE IF viewer.iconic AND NOT createIconic THEN [] _ ViewerOps.OpenIcon[viewer]; compilerRec.openLogs _ FALSE; -- only open at most one icon IF (log _ ViewerOps.FindViewer[Rope.Concat[compilerRec.thisFile, ".errlog"]]) # NIL THEN ViewerOps.RestoreViewer[log]; }; IF viewer # NIL THEN { -- this code is exercised even if compiler.separateLogs is FALSE. proc: UserExecPrivate.SplitViewerProc = { IF compilerRec.separateLogs THEN { entry: Menus.MenuEntry _ Menus.FindEntry[viewer.menu, "ErrorLog"]; IF entry = NIL THEN { Menus.AppendMenuEntry[menu: viewer.menu, line: 0, entry: Menus.CreateEntry[name: "ErrorLog", proc: OpenErrorLog, fork: FALSE]]; IF NOT viewer.iconic THEN ViewerOps.PaintViewer[viewer, menu]; }; }; }; [] _ ThisNeedsToBeCompiled[viewer]; -- to change the icon UserExecPrivate.ForAllSplitViewers[viewer, proc]; IF viewer.iconic AND UserProfile.Boolean["Compiler.BlinkLogs", TRUE] THEN BlinkIcon[viewer]; -- do this outside of ForAllSplitViewers so that if more than one icon, only blink one }; }; ENDCASE => { -- successful IF compilerRec.separateLogs THEN -- restore or destroy log -- [] _ ShowLog[Rope.Concat[compilerRec.thisFile, ".errlog"], TRUE, compilerRec.exec]; RemoveIt[compilerRec.thisFile]; IF viewer # NIL THEN { proc: UserExecPrivate.SplitViewerProc = { IF viewer.icon = IconRegistry.GetIcon[iconName: "NeedsToBeCompiled", default: document] THEN { viewer.icon _ document; IF viewer.iconic THEN ViewerOps.PaintViewer[viewer, all]; }; IF compilerRec.separateLogs THEN { entry: Menus.MenuEntry _ Menus.FindEntry[viewer.menu, "ErrorLog"]; IF entry # NIL THEN Menus.ReplaceMenuEntry[viewer.menu, entry]; IF NOT viewer.iconic THEN ViewerOps.PaintViewer[viewer, menu]; }; }; UserExecPrivate.ForAllSplitViewers[viewer, proc]; }; }; }; compilerProcs: Feedback.Procs _ [CCreate, CDestroy, CBeginItem, CNoteProgress, CFinishItem]; ProcessLine: PROC [ext: ROPE, event: HistoryEvent, exec: ExecHandle] RETURNS[line: ROPE, files: LIST OF ROPE, someMissing: BOOLEAN _ FALSE] = { commandLineStream: STREAM = event.commandLineStream; id, nextId, lastId: ROPE; length, pos: INT _ 0; files _ NIL; id _ IO.GetToken[commandLineStream]; WHILE id # NIL DO file: ROPE; { -- to provide an exits clause IF Rope.Equal[id, "/"] THEN {[] _ IO.GetToken[commandLineStream, IO.IDProc]; -- skip over switches GOTO GetNext; }; nextId _ IO.GetToken[commandLineStream]; IF Rope.Equal[nextId, "_"] OR Rope.Equal[nextId, ":"] THEN {id _ nextId; GOTO GetNext}; IF NOT Rope.Letter[Rope.Fetch[id, 0]] THEN NULL-- e.g. skip ,' ELSE IF (file _ UserExec.GetTheFile[file: id, defaultExt: IF Rope.Equal[lastId, ":"] THEN "bcd" ELSE ext, event: event, exec: exec]) = NIL THEN someMissing _ TRUE ELSE TRUSTED { files _ LOOPHOLE[List.Nconc1[LOOPHOLE[files], file]]; UserExecPrivate.WaitUntilSaved[file, exec]; }; lastId _ id; id _ nextId; LOOP; EXITS GetNext => {lastId _ id; id _ IO.GetToken[commandLineStream]}; }; ENDLOOP; line _ event.commandLine; length _ Rope.Length[line]; IF (pos _ Rope.Find[s1: line, s2: "\n"]) # -1 AND pos # length -1 THEN -- embedded CR's, which must be changed to spaces. line _ UserExec.RopeSubst[old: "\n", new: " ", base: line]; IF (pos _ Rope.Find[s1: line, s2: "\n"]) = -1 THEN line _ Rope.Concat[line, "\n"]; -- no trailing CR. must be added because of way binder/compiler scanner works. }; destroyLogOnSuccess: BOOLEAN; ShowLog: PROC [name: ROPE, ok: BOOLEAN, exec: ExecHandle, blinkIt: BOOL _ TRUE] RETURNS[log: Viewer] = { log _ ViewerOps.FindViewer[name]; IF NOT ok THEN { createIconic: BOOLEAN _ TRUE; IF exec # NIL AND NOT exec.viewer.iconic AND (InputFocus.GetInputFocus[].owner = exec.viewer) THEN createIconic _ FALSE; IF UserProfile.Boolean["Compiler.IconicLogs", FALSE] THEN createIconic _ TRUE; IF log # NIL THEN ViewerOps.RestoreViewer[log] ELSE IF UserExec.CheckForFile[name] THEN log _ CreateLog[name: name, iconic: createIconic]; -- log not there in case of no such source IF log # NIL AND log.iconic AND blinkIt AND UserProfile.Boolean["Compiler.BlinkLogs", TRUE] THEN BlinkIcon[log]; } ELSE IF log # NIL THEN { IF destroyLogOnSuccess THEN {ViewerOps.DestroyViewer[log]; log _ NIL} ELSE ViewerOps.RestoreViewer[log]; }; }; CreateLog: PROC [name: ROPE, iconic: BOOL _ TRUE] RETURNS[viewer: Viewer] = { IF iconic THEN viewer _ ViewerOps.CreateViewer[flavor: $Text, info: [name: name, file: name, iconic: iconic, icon: typescript]] ELSE {viewer _ TiogaMenuOps.Open[name]; viewer.icon _ typescript}; }; BlinkIcon: PUBLIC PROC [icon: Viewer, n: INT _ 10] = TRUSTED { Process.Detach[FORK Blink[icon, n]]; }; Blink: PROC [viewer: Viewer, rate: INT _ 10] = TRUSTED { halfSecond: Process.Ticks = Process.MsecToTicks[500]; DO ViewerOps.BlinkIcon[viewer]; rate _ MIN[(rate * 3)/2, 3600]; -- gradually slow down rate of blinking FOR i: INT IN [0..2*rate) DO -- blink every n seconds, but wake up every half second. Process.Pause[halfSecond]; IF viewer.destroyed OR NOT viewer.iconic OR viewer = ViewerTools.GetSelectedViewer[] THEN RETURN; ENDLOOP; ENDLOOP; }; ResetProc: TiogaOps.CommandProc = { icon: Icons.IconFlavor; proc: UserExecPrivate.SplitViewerProc = { viewer.icon _ icon; }; IF NOT IsAMesaFile[viewer.name] THEN RETURN; icon _ IF DoesThisNeedToBeCompiled[viewer.name] THEN IconRegistry.GetIcon["NeedsToBeCompiled", document] ELSE document; UserExecPrivate.ForAllSplitViewers[viewer, proc]; }; CloseProc: ViewerEvents.EventProc = { needsToBeCompiledIcon: Icons.IconFlavor = IconRegistry.GetIcon["NeedsToBeCompiled", unInit]; IF viewer.newVersion THEN RETURN; -- should already have the dirtyDocument icon by virtue of the edit event registration IF IsAMesaFile[viewer.name] THEN viewer.icon _ IF DoesThisNeedToBeCompiled[viewer.name] THEN IconRegistry.GetIcon["NeedsToBeCompiled", document] -- necessary to do this to handle the case where you opened a new viewer on a needstobecompiled file ELSE document ELSE IF viewer.icon = IconRegistry.GetIcon["NeedsToBeCompiled", document] THEN viewer.icon _ document; -- necessary if you reloaded a non mesa file into a viewer that previously contained a needstobecompiled file. }; DoesThisNeedToBeCompiled: ENTRY PROC [name: Rope.ROPE] RETURNS[yes: BOOL] = { ENABLE UNWIND => NULL; FOR l: LIST OF ROPE _ needsToBeCompiled, l.rest UNTIL l = NIL DO IF Rope.Equal[l.first, name, FALSE] THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; }; ThisNeedsToBeCompiled: TiogaOps.CommandProc = { -- called for a save, and from CFinishProc when errors or warnings name: ROPE = viewer.name; IF IsAMesaFile[name] THEN { proc: UserExecPrivate.SplitViewerProc = { icon: Icons.IconFlavor = IconRegistry.GetIcon["NeedsToBeCompiled", viewer.icon]; IF icon # viewer.icon THEN { viewer.icon _ icon; IF viewer.iconic THEN ViewerOps.PaintViewer[viewer, all]; }; }; AddIt[name]; UserExecPrivate.ForAllSplitViewers[viewer, proc]; }; }; UseDirtyDocumentIcon: ViewerEvents.EventProc = { -- called when the first edit is made IF NOT IsAMesaFile[viewer.name] THEN RETURN; IF viewer.icon = IconRegistry.GetIcon["NeedsToBeCompiled", document] THEN viewer.icon _ dirtyDocument; }; IsAMesaFile: PROC [name: ROPE] RETURNS[BOOL] = INLINE { i: INT = Rope.Find[s1: name, s2: ".mesa", case: FALSE]; RETURN[i # -1 AND i = Rope.Length[name] - 5]; }; AddIt: ENTRY PROC[name: ROPE, addBoth: BOOL _ FALSE] = { IF Rope.Find[name, "."] = -1 THEN name _ Rope.Concat[name, ".mesa"]; FOR l: LIST OF ROPE _ needsToBeCompiled, l.rest UNTIL l = NIL DO IF Rope.Equal[l.first, name, FALSE] THEN EXIT; REPEAT FINISHED => needsToBeCompiled _ CONS[name, needsToBeCompiled]; ENDLOOP; IF addBoth THEN FOR l: LIST OF ROPE _ errorsOrWarnings, l.rest UNTIL l = NIL DO IF Rope.Equal[l.first, name, FALSE] THEN EXIT; REPEAT FINISHED => errorsOrWarnings _ CONS[name, errorsOrWarnings]; ENDLOOP; }; RemoveIt: ENTRY PROC[name: ROPE] = { lag: LIST OF ROPE; IF Rope.Find[name, "."] = -1 THEN name _ Rope.Concat[name, ".mesa"]; FOR l: LIST OF ROPE _ needsToBeCompiled, l.rest UNTIL l = NIL DO IF Rope.Equal[l.first, name, FALSE] THEN { IF lag = NIL THEN needsToBeCompiled _ l.rest ELSE lag.rest _ l.rest; EXIT; }; lag _ l; ENDLOOP; FOR l: LIST OF ROPE _ errorsOrWarnings, l.rest UNTIL l = NIL DO IF Rope.Equal[l.first, name, FALSE] THEN { IF lag = NIL THEN errorsOrWarnings _ l.rest ELSE lag.rest _ l.rest; EXIT; }; lag _ l; ENDLOOP; }; OpenErrorLog: ClickProc = { log: Viewer; viewer: Viewer = NARROW[parent]; name: ROPE = Rope.Concat[Rope.Substr[base: viewer.name, len: Rope.Find[viewer.name, "."]], ".errlog"]; IF (log _ ViewerOps.FindViewer[name]) # NIL THEN { IF log.iconic THEN ViewerOps.OpenIcon[log] ELSE { MessageWindow.Append[Rope.Concat[name, " is already open."], TRUE]; MessageWindow.Blink[]; }; } ELSE IF UserExec.CheckForFile[name] THEN { log: Viewer = TiogaMenuOps.Open[name]; log.icon _ typescript; } ELSE { MessageWindow.Append["Error log not found.", TRUE]; MessageWindow.Blink[]; }; }; UserExec.RegisterCommand["Bind", Bind, "Bind a list of configurations."]; UserExec.RegisterCommand["Binder", Bind, "Bind a list of configurations."]; -- do it this way, rather than as an alias, so I can redefine Bind to do a rename, etc. and then call binder UserExec.RegisterCommand["Compile", Compile, "Compile a list of modules."]; UserExec.RegisterCommand["Compiler", Compile, "Compile a list of modules."]; UserExec.RegisterTransformation["CompileAll", CompileAll, "Compiles everybody that needs to be compiled, i.e. all files that have been edited or whose compilation caused errors or warnings."]; UserExec.RegisterTransformation["CompileBadGuys", CompileBadGuys, "Compiles those files whose most recent compilation caused errors or warnings."]; UserProfile.CallWhenProfileChanges[SetDefaultSwitches]; IconRegistry.RegisterIcon["NeedsToBeCompiled", "UserExec.Icons", 9]; TiogaOps.RegisterCommand[name: $RedSave, proc: ThisNeedsToBeCompiled, before: FALSE]; TiogaOps.RegisterCommand[name: $BlueSave, proc: ThisNeedsToBeCompiled, before: FALSE]; TiogaOps.RegisterCommand[name: $YellowSave, proc: ThisNeedsToBeCompiled, before: FALSE]; -- takes care of changing the icon to needs to be compiled, and adding file to needsToBeCompiled. Note that the viewer might be split and one of its splittees be iconic, so can't rely on noticing the icon change when you close the viewer. TiogaOps.RegisterCommand[name: $RedReset, proc: ResetProc]; TiogaOps.RegisterCommand[name: $YellowReset, proc: ResetProc]; TiogaOps.RegisterCommand[name: $BlueReset, proc: ResetProc]; -- takes care of changing the icon back to needs to be compiled, where necessary.. [] _ ViewerEvents.RegisterEventProc[proc: UseDirtyDocumentIcon, filter: $Text, event: edit]; -- takes care of changing a NeedsToBeCompiled icon to a dirtydocument icon. [] _ ViewerEvents.RegisterEventProc[proc: CloseProc, filter: $Text, event: close]; END. nedited by Teitelman June 20, 1983 4:34 pm Type Definitions connecting concrete and opaque types to access evalMode in CreateExecProc, CreateExec, and ChangeAreaMode, and historyList in GetEventsFromSelection to access eventNum in RedoButton Running the Binder Running the Compiler the old way of doing business was to create both the source viewer and the log for each file that had errors or warnings. The log and viewer were opened if a variety of checks were satisfied, e.g. if the input focus was in the exec, the exec was opened, the user profile did not indicate otherwise, etc., otherwise iconic. If iconic, the log would blink unless profile said otherwise. log: Viewer _ ShowLog[name: Rope.Concat[compilerRec.thisFile, ".errlog"], ok: FALSE, exec: IF compilerRec.openLogs THEN compilerRec.exec ELSE NIL]; compilerRec.openLogs _ FALSE; -- only open at most one icon IF log # NIL THEN { -- we opened the errlog, open the source too. IF viewer = NIL THEN { -- [] _ CreateLog[name: name, iconic: log.iconic] should be able to just call TiogaMenuOps here (Reason we dont call CreateLog is because that might use a different icon). IF log.iconic THEN viewer _ ViewerOps.CreateViewer[flavor: $Text, info: [name: name, file: name, iconic: TRUE]] ELSE viewer _ TiogaMenuOps.Open[name]; } ELSE IF viewer.iconic AND NOT log.iconic THEN [] _ ViewerOps.OpenIcon[viewer]; }; IF viewer.ww <= Menus.FindEntry[viewer.menu, "ErrorLog"].xpos THEN -- not visible, do it old way. The new way of doing business is to open only the viewer and to post a menu button for opening the log. The viewer blinks if it is iconic and the profie says so. Changing icons for files that need to be compiled Initialization the above comprise those operations which can be performed to a single viewer, but which may also affect the state of other iconic viewers in the case where a viewer has been split. The other things to worry about are where a viewer is cleared, or reloaded, in which case its icon needs to be rechecked, or where a new viewer is created via Open, or middle clicking get, getimpl. Rather than register separate events for Load, Open, CloseAndOpen, LoadImpl, etc. simply notice that the icon needs to be changed when the viewer is closed, via the following: Note that if there were a single event which corresponded to all of the above, e.g. if create did the right thing, then we should use that. Κ…– "Cedar" style˜JšΟcœ™+J˜šΟk ˜ Jšœžœ ˜Jšœžœ ˜Jšœ žœ ˜Jšœ žœS˜aJšœžœ˜Jšœ žœ˜+Jšœžœ˜Jšœ žœ˜!JšžœžœDžœ"žœ.˜¦Jšœžœ ˜JšœžœY˜dJšœžœ˜$Jšœžœ]˜jJšœžœ<žœ˜_Jšœžœ˜#Jšœžœ+˜HJšœ žœ˜Jšœ žœ ˜.Jšœ žœΠ˜ήJšœžœ˜Jšœžœq˜†Jšœ žœ>˜OJšœžœ˜%Jšœ žœ ˜2Jšœ žœ^˜mJšœ žœ˜%J˜—J˜JšΠblœžœžœ˜&J˜Jšžœ5žœ΅˜σJ˜Jšžœ˜!J˜Jšžœ ˜J˜Jšœžœžœžœ˜head™JšΟn œžœ˜'Jš Πkn œ˜+Jš œžœ˜$Jš  œžœ˜"Kšœ$™$š œžœžœ%˜CJ™o—š œžœžœ-˜SJ™ ——™š œ4œ˜UJšžœžœ <˜aJ˜2J˜/Jšžœ˜šž˜Jšœ žœžœ˜—J˜J˜—š   œžœ)žœžœ<˜’J˜3Jšœžœ˜ Jš œžœžœI˜`šž˜Jšžœžœ˜Jšœ žœžœ˜Jšœžœ˜ J˜NJ˜Jšœ:˜:Jšœ˜Jšœ0˜0šžœžœ<žœ˜Gšž˜Jšžœžœžœ˜ Jšœ(˜(Jšœ6žœ˜<—Jšžœ˜—J˜MJšœžœ4žœ ˜`Jšœžœ˜4Jšœžœ˜J˜QJšžœ žœ˜%Jšž˜Jšœ`žœ˜tJšžœ˜—J˜ Jšžœžœ˜5J˜J˜—Jš œžœžœ˜-š œ˜"šœ#˜#Jšžœ žœžœžœ˜IJšœž œžœžœ˜@Jšœ˜—J˜J˜—š  œ˜&šœ ˜ Jšžœ žœžœžœ˜IJšœž œžœžœ˜@Jšœ˜—J˜J˜—š  œ˜,šœ˜Jšžœ žœžœžœ˜IJšœž œžœžœ˜@Jšœ˜—šžœžœž˜Jšœ˜Jšžœžœ ˜J˜—Jšœ˜J˜—š  œ˜(šœ-˜-Jšžœ žœžœžœ˜IJšœž œžœžœ˜@Jšœ˜—J˜J˜—Jš  œO˜Zš  œžœžœ˜Jšœ žœžœ˜Jšœžœžœžœžœžœžœž œžœ˜˜>J˜J˜0šžœžœ?ž˜Išž˜Jšžœžœžœ˜ Jšœ*˜*Jšœ8žœ˜>Jšžœ˜——J˜QJšœ+˜+Jšœ>žœ.˜oJšœžœ˜Jšœžœ˜Jšœžœžœ ˜EJšœžœ˜8Jšœ,žœ˜0J˜J˜XJšžœžœžœC˜eJšžœžœžœ>˜_Jšžœžœ&žœžœ1˜mšž˜JšœHžœ˜\—Jšžœ˜—J˜ Jšžœžœ˜5J˜J˜Jš œžœžœ˜-š œ˜"šœ%˜%Jšžœ žœžœžœ˜KJšœž œžœžœ˜BJšœ˜—J˜J˜—š  œ˜&šœ"˜"Jšžœ žœžœžœ˜KJšœž œžœžœ˜BJšœ˜—šž ˜ Jšœ žœ˜,Jšœžœ˜Jšœ3!˜TJšœ˜Jšžœžœ0˜>Jšœ"˜"J˜—J˜J˜—š  œ˜,šœ˜Jšžœ žœžœžœ˜KJšœž œžœžœ˜BJšœ˜—šžœžœž˜Jšœ ˜ Jšžœžœ ˜J˜—J˜J˜—š  œ˜(Jšœžœ/˜9J˜,Jšœžœ˜J˜:šœ:˜:Jšžœ žœžœžœ˜KJšœž œžœžœ˜BJšœ˜—šžœ ž˜J˜˜(JšžœžœS˜mJšžœP˜TJšœžœ˜"šžœžœ˜"Jšœ€™€Jš œNžœžœžœžœžœ™“Jšœžœ™J˜—Jšœ˜—Jšœ˜—Jšœ$˜9J˜1Jš žœžœ+žœžœW˜΄Jšœ˜—J˜J˜—šžœ ˜šžœžœ˜?Jšœ;žœ˜S—Jšœ˜šžœ žœžœ˜š œ%˜)šžœVžœ˜^Jšœ˜Jšžœžœ$˜9J˜—šžœžœ˜"JšœB˜BJšžœ žœžœ,˜?Jšžœžœžœ%˜>Jšœ˜—Jšœ˜—J˜1J˜—J˜——J˜J˜—Jš  œO˜\—š  œžœžœ)žœžœ žœžœžœžœžœ˜Jšœžœ˜4Jšœžœ˜Jšœ žœ˜Jšœžœ˜ Jšœ$˜$šžœžœž˜Jšœžœ˜ šž˜šžœž˜Jšœ2˜GJšžœ ˜ J˜J˜—Jšœ(˜(Jšžœžœžœžœ ˜WJšžœžœ ž ž˜?Jšžœžœ3žœžœžœ#žœžœž˜’šžœžœ˜Jšœžœ žœ˜5Jšœ,˜,J˜—J˜ J˜ Jšžœ˜Jšž˜Jšœ>˜>Jšžœ˜—Jšžœ˜—Jšœ˜J˜šžœ,žœžœ2˜yJ˜<—Jšžœ,žœ"N˜’J˜J˜—J˜Jš œžœ˜š œžœžœžœžœžœžœ˜iJ˜!šžœžœž˜šœ˜Jšœž˜Jšžœžœžœžœžœ2žœžœ˜xJšžœ,žœžœžœ˜NJšžœžœžœ˜/Jšžœžœžœ5*˜‡Jšžœžœžœ žœ žœ+žœžœ˜qJ˜——šžœžœžœž˜Jšžœžœ&žœ˜EJšžœ˜"J˜—J˜J˜—š   œžœžœ žœžœžœ˜MJšžœžœq˜Jšžœ?˜CJ˜—J˜š  œž œžœ ž ˜>Jšœžœ˜$J˜J˜—š œžœžœ žœ˜9Jšœ5˜5šž˜J˜Jšœžœ'˜Hš žœžœžœ žœ8˜VJšœ˜Jš žœžœžœžœ*žœžœ˜aJšžœ˜——Jšžœ˜J˜J˜——šœ2™2J˜š  œ˜#Jšœ˜š œ%˜)Jšœ˜Jšœ˜—Jšžœžœžœžœ˜,Jšœžœ'žœ5žœ ˜wJ˜1Jšœ˜—J˜š  œ˜%Jšœ\˜\Jš žœžœžœIœ ˜xšžœžœ˜!Jšœžœ'žœ6d˜ΥJšžœ ˜ —JšžœžœCžœp˜ΨJšœ˜—J˜š  œžœžœ žœžœžœ˜MJšžœžœžœ˜š žœžœžœžœžœžœž˜@Jš žœžœžœžœžœ˜6Jšžœ˜—Jšžœžœ˜Jšœ˜J˜—š œB˜rJšœžœ˜šžœžœ˜š œ%˜)J˜Pšžœžœ˜Jšœ˜Jšžœžœ$˜9J˜—Jšœ˜—J˜ J˜1J˜—Jšœ˜J˜—š’œ%˜WJšžœžœžœž˜,JšžœCžœ˜fJ˜J˜—š   œžœžœžœžœžœ˜7Jšœžœ$ž œ˜7Jšžœžœ˜-Jšœ˜J˜—š  œžœžœžœ ž œ˜8Jšžœžœ#˜Dš žœžœžœžœžœžœž˜@Jšžœžœžœžœ˜.Jšž˜Jšžœžœ˜>Jšžœ˜—šžœ žœžœžœžœžœžœžœž˜OJšžœžœžœžœ˜.Jšž˜Jšžœžœ˜˜>Jšœ<˜