DIRECTORY Ascii, BridgeComm, BridgeDriver, BridgeExec, BridgeFTPOps, Convert, IO, Menus, MessageWindow, NetworkStream, NodeProps, Rope, TEditSplit, TextLooks, TextEdit, TextNode, Tioga, TiogaIO, TiogaMenuOps, TiogaOps, UserProfile, ViewerClasses, ViewerEvents, ViewerForkers, ViewerGroupLocks, ViewerOps, ViewerTools ; BridgeREditImpl: CEDAR PROGRAM IMPORTS Ascii, BridgeComm, BridgeDriver, BridgeExec, BridgeFTPOps, Convert, IO, Menus, MessageWindow, NetworkStream, NodeProps, Rope, TEditSplit, TextEdit, TiogaIO, TiogaMenuOps, TiogaOps, UserProfile, ViewerForkers, ViewerOps, ViewerTools, ViewerEvents, ViewerGroupLocks ~ { ROPE: TYPE ~ Rope.ROPE; NetworkStreamPair: TYPE ~ BridgeExec.NetworkStreamPair; Handle: TYPE ~ REF HandleRep ¬ NIL; HandleRep: TYPE ~ RECORD [ nsp: NetworkStreamPair, args: ROPE, remoteName: ROPE, overwrite: BOOL, session: BridgeExec.Session, viewer: ViewerClasses.Viewer, pendingName: ROPE, workingDirectory: ROPE, clientData: REF ]; commandName: ROPE ~ "REdit"; handleProperty: ATOM ~ $REditHandle; overwriteKey: ROPE ¬ "Bridge.REdit.overwrite"; overwriteDefault: BOOL ¬ FALSE; HasPWD: PROC[nsp: NetworkStreamPair] RETURNS [hasIt: BOOL ¬ FALSE] ~ { ansMsg: CHAR; ansArg: ROPE; [ansMsg, ansArg] ¬ BridgeComm.PutMsgWithReply[nsp~nsp, msg~'X, arg~"D"]; IF ansMsg = 'Y THEN hasIt ¬ TRUE; }; GetCurDir: PROC[nsp: NetworkStreamPair] RETURNS [curDir: ROPE ¬ NIL] ~ { ENABLE BridgeComm.Error => CONTINUE; ansMsg: CHAR; ansArg: ROPE; list: LIST OF ROPE; IF NOT HasPWD[nsp] THEN RETURN; [ansMsg, ansArg] ¬ BridgeComm.PutMsgWithReply[nsp~nsp, msg~'D, arg~NIL]; IF ansMsg # 'Y THEN RETURN; list ¬ BridgeDriver.ListOfRopeFromCmd[ansArg]; curDir ¬ list.first; }; SetCurDir: PROC[nsp: NetworkStreamPair, newDir: ROPE] RETURNS [curDir: ROPE ¬ NIL] ~ { ENABLE BridgeComm.Error => CONTINUE; ansMsg: CHAR; ansArg: Rope.ROPE; list: LIST OF ROPE; IF NOT HasPWD[nsp] THEN RETURN; [ansMsg, ansArg] ¬ BridgeComm.PutMsgWithReply[nsp~nsp, msg~'D, arg~newDir]; IF ansMsg # 'Y THEN RETURN; list ¬ BridgeDriver.ListOfRopeFromCmd[ansArg]; curDir ¬ list.first; }; Init: PROCEDURE [] RETURNS [] ~ { BridgeExec.Register[ name: commandName, createProc: Create, clientData: NIL, destroyProc: Destroy]; }; Create: BridgeExec.CreateProc ~ { argsList: LIST OF ROPE; remoteName: ROPE; handle: Handle; contentRope, excuse: ROPE; argsList ¬ BridgeDriver.ListOfRopeFromCmd[args]; remoteName ¬ IF argsList = NIL THEN NIL ELSE argsList.first; handle ¬ NEW[HandleRep ¬ [ nsp~nsp, args~args, remoteName~remoteName, overwrite~GetOverwriteMode[NIL], session~session, viewer~NIL, pendingName~NIL, workingDirectory~NIL, clientData: clientData]]; handle.workingDirectory ¬ GetCurDir[nsp: handle.nsp]; -- may be NIL IF Rope.IsEmpty[remoteName] THEN { contentRope ¬ ""; excuse ¬ NIL } ELSE { [result~contentRope, excuse~excuse] ¬ NamedFileToRope[handle.nsp, handle.remoteName]; }; IF Rope.IsEmpty[excuse] THEN { handle.viewer ¬ NewREditViewer[addWD: (handle.workingDirectory # NIL)]; ViewerOps.AddProp[viewer: handle.viewer, prop: handleProperty, val: handle]; handle.viewer ¬ RopeToViewer[viewer: handle.viewer, rope: contentRope, extensionRope: ExtensionFromFileName[remoteName]]; REditCaption[handle: handle]; ViewerOps.OpenIcon[icon: handle.viewer]; } ELSE { ExcuseMe[Rope.Concat["REdit couldn't open viewer: ", excuse]]; }; RETURN [instance: handle]; }; Destroy: BridgeExec.DestroyProc ~ { handle: Handle ¬ NARROW[instance]; IF handle.viewer = NIL THEN RETURN; FOR viewer: ViewerClasses.Viewer ¬ handle.viewer.link, viewer.link WHILE viewer # NIL DO { IF viewer = handle.viewer THEN EXIT; ViewerOps.DestroyViewer[viewer: viewer]; } ENDLOOP; ViewerOps.DestroyViewer[viewer: handle.viewer]; }; RopeToViewer: PROCEDURE [viewer: ViewerClasses.Viewer, rope: ROPE, extensionRope: ROPE ¬ NIL] RETURNS [result: ViewerClasses.Viewer] ~ { root: Tioga.Node ~ TiogaIO.FromRope[rope: rope]; AddFileExtensionProp[root, extensionRope]; viewer.class.set[viewer, root, TRUE, $TiogaDocument]; RETURN [result: viewer]; }; NamedFileToRope: PROC [nsp: NetworkStreamPair, remoteName: ROPE] RETURNS [result: ROPE ¬ NIL, success: BOOLEAN ¬ TRUE, excuse: ROPE ¬ NIL] ~ { ENABLE BridgeComm.Error => { result ¬ NIL; excuse ¬ msg; success ¬ FALSE; GOTO Done}; actionCalled: BOOLEAN ¬ FALSE; unwound: BOOLEAN ¬ FALSE; StreamToRopeActionProc: BridgeFTPOps.ActionProc ~ { ENABLE UNWIND => unwound ¬ TRUE; actionCalled ¬ TRUE; result ¬ RopeFromStream[nsp: nsp, bytes: bytesReported]; RETURN [quit: FALSE]; }; IF Rope.IsEmpty[remoteName] THEN RETURN [success: FALSE, excuse: "Null remote name"]; BridgeComm.PutMsgWithAck[nsp: nsp, msg: 'X, arg: "x"]; -- don't translate CR-LF excuse ¬ BridgeFTPOps.RetrieveStream[ nsp: nsp, remoteName: remoteName, action: StreamToRopeActionProc]; IF unwound AND excuse = NIL THEN excuse ¬ "something happened to the stream."; IF NOT actionCalled AND excuse = NIL THEN result ¬ NIL; IF excuse # NIL THEN success ¬ FALSE; RETURN [result: result, success: success, excuse: excuse]; EXITS Done => NULL; }; NamedFileToViewer: PROCEDURE [ nsp: NetworkStreamPair, viewer: ViewerClasses.Viewer, remoteName: ROPE] RETURNS [ result: ViewerClasses.Viewer ¬ NIL, success: BOOLEAN ¬ TRUE, excuse: ROPE ¬ NIL] ~ { r: ROPE; [r, success, excuse] ¬ NamedFileToRope[nsp, remoteName]; IF success THEN result ¬ RopeToViewer[viewer~viewer, rope~r, extensionRope~ExtensionFromFileName[remoteName]]; }; RopeFromStream: PROCEDURE [nsp: NetworkStreamPair, bytes: INT] RETURNS [rope: ROPE ¬ NIL] ~ { rope ¬ BridgeComm.GetRopeToEOM[nsp]; }; NewREditViewer: PROCEDURE [addWD: BOOL] RETURNS [viewer: ViewerClasses.Viewer ¬ NIL] ~ { viewer ¬ ViewerOps.CreateViewer[flavor: $Text]; viewer ¬ REditMenu[viewer: viewer, addWD: addWD]; }; REditCaption: PROCEDURE [handle: Handle] RETURNS [] ~ { sessionName: ROPE ~ BridgeExec.SessionNameFromSession[session: handle.session]; transportClass: ATOM ~ NetworkStream.GetStreamInfo[handle.nsp.in].protocolFamily; dirRope: ROPE ~ IF handle.workingDirectory # NIL THEN Rope.Concat[" WD = ", handle.workingDirectory] ELSE NIL; viewerName: ROPE; ChangeCaption: PROCEDURE [] RETURNS [] ~ { FOR split: ViewerClasses.Viewer ¬ handle.viewer, split.link WHILE split # NIL DO { split.name ¬ viewerName; ViewerOps.PaintViewer[viewer: split, hint: ViewerClasses.PaintHint.caption]; IF split.link = handle.viewer THEN EXIT; } ENDLOOP; }; viewerName ¬ Rope.Cat[handle.remoteName, " (", sessionName, ")"]; ViewerGroupLocks.CallRootAndLinksUnderWriteLock[ChangeCaption, handle.viewer]; }; LineFeedRope: ROPE ~ "\l"; SetNewLine: PROC [root: Tioga.Node] ~ { IF NodeProps.GetProp[root, $NewlineDelimiter] = NIL THEN NodeProps.PutProp[root, $NewlineDelimiter, LineFeedRope]; }; SetOverwriteMode: PROC [handle: Handle, overwrite: BOOL] ~ { IF handle # NIL THEN handle.overwrite ¬ overwrite; }; GetOverwriteMode: PROC [handle: Handle] RETURNS [overwrite: BOOL] ~ { IF handle # NIL THEN overwrite ¬ handle.overwrite ELSE overwrite ¬ UserProfile.Boolean[key~overwriteKey, default~overwriteDefault]; }; RopeFromViewer: PROC [viewer: ViewerClasses.Viewer] RETURNS [rope: ROPE] ~ { isTioga: BOOL; [isTioga, rope] ¬ IsThisViewerTioga[viewer]; IF isTioga THEN { root: Tioga.Node ~ TiogaOps.ViewerDoc[viewer]; SetNewLine[root]; rope ¬ TiogaIO.ToRope[root]; }; }; ViewerToNamedFile: PROCEDURE [ nsp: NetworkStreamPair, remoteName: ROPE, overwrite: BOOL, viewer: ViewerClasses.Viewer] RETURNS [ success: BOOLEAN ¬ TRUE, excuse: ROPE ¬ NIL] ~ { ENABLE BridgeComm.Error => { excuse ¬ msg; success ¬ FALSE; CONTINUE }; unwound: BOOLEAN ¬ FALSE; actionCalled: BOOLEAN ¬ FALSE; ropeFromViewer: ROPE; RopeToStreamActionProc: BridgeFTPOps.ActionProc ~ { ENABLE UNWIND => unwound ¬ TRUE; success: BOOLEAN ¬ TRUE; actionCalled ¬ TRUE; success ¬ RopeToStream[nsp~nsp, rope~ropeFromViewer]; RETURN [quit: NOT success]; }; IF Rope.IsEmpty[remoteName] THEN RETURN [success~FALSE, excuse~"null remote name"]; ropeFromViewer ¬ RopeFromViewer[viewer]; BridgeComm.PutMsgWithAck[nsp~nsp, msg~'X, arg~"x"];-- don`t translate CR-LF excuse ¬ BridgeFTPOps.StoreStream[nsp, remoteName, overwrite, RopeToStreamActionProc]; IF unwound AND excuse = NIL THEN { excuse ¬ "communication failure."; }; IF NOT actionCalled AND excuse = NIL THEN { excuse ¬ "never asked to write."; }; IF excuse # NIL THEN { success ¬ FALSE; }; RETURN [success: success, excuse: excuse]; }; RopeToStream: PROCEDURE [ nsp: NetworkStreamPair, rope: ROPE] RETURNS [success: BOOLEAN ¬ TRUE] ~ { IO.PutRope[self: nsp.out, r: rope]; RETURN [success: TRUE]; }; REditMenu: PROCEDURE [viewer: ViewerClasses.Viewer, addWD: BOOL] RETURNS [result: ViewerClasses.Viewer ¬ NIL] ~ { menu: Menus.Menu ¬ Menus.CreateMenu[]; CopyEntry: PROC [name: Rope.ROPE] = { old: Menus.MenuEntry ~ Menus.FindEntry[menu: TiogaMenuOps.tiogaMenu, entryName: name]; IF old#NIL THEN { Menus.AppendMenuEntry[menu: menu, entry: Menus.CopyEntry[old], line: 0]; }; }; Menus.AppendMenuEntry[ menu: menu, entry: Menus.CreateEntry[ name: "Clear", proc: ClearProc]]; Menus.AppendMenuEntry[ menu: menu, entry: Menus.CreateEntry[ name: "Reset", proc: ResetProc, guarded: TRUE, documentation: preResetProc]]; Menus.AppendMenuEntry[ menu: menu, entry: Menus.CreateEntry[ name: "Get", proc: GetProc]]; Menus.AppendMenuEntry[ menu: menu, entry: Menus.CreateEntry[ name: "RemoteStore", proc: RemoteStoreProc, guarded: TRUE, documentation: preRemoteStoreProc]]; Menus.AppendMenuEntry[ menu: menu, entry: Menus.CreateEntry[ name: "RemoteSave", proc: RemoteSaveProc]]; Menus.AppendMenuEntry[ menu: menu, entry: Menus.CreateEntry[name: "Split", proc: SplitProc], line: 0]; CopyEntry["Places"]; CopyEntry["Levels"]; CopyEntry["Line"]; IF addWD THEN Menus.AppendMenuEntry[ menu: menu, entry: Menus.CreateEntry[name: "WD", proc: DirectoryProc], line: 0]; CopyEntry["Plain"]; CopyEntry["Cedar"]; [] ¬ ViewerOps.SetMenu[viewer: viewer, menu: menu]; [] ¬ TiogaMenuOps.DefaultMenus[viewer: viewer]; [] ¬ ViewerEvents.RegisterEventProc[ proc: ViewerEventDestroyProc, event: ViewerEvents.ViewerEvent.destroy, filter: viewer, before: TRUE ]; RETURN [result: viewer]; }; ViewerEventDestroyProc: ViewerEvents.EventProc ~ { handle: Handle ¬ NARROW[ViewerOps.FetchProp[viewer: viewer, prop: handleProperty]]; IF event # destroy OR before # TRUE THEN ERROR; IF handle # NIL THEN { IF viewer.link = NIL OR viewer.link = viewer THEN { BridgeExec.DestroyInstance[handle.session, handle]; } ELSE { handle.viewer ¬ viewer.link; }; }; RETURN [abort: FALSE]; }; ClearProc: Menus.ClickProc ~ { handle: Handle ~ NARROW[ViewerOps.FetchProp[viewer: parent, prop: handleProperty]]; SELECT mouseButton FROM Menus.MouseButton.red => { IF (IF ViewerOpsGetNewVersion[viewer: parent] THEN NOT handle.remoteName.Equal[NIL] ELSE FALSE) THEN { UnsavedEdits[]; } ELSE { WHILE parent.link # NIL AND parent.link # parent DO { ViewerOps.DestroyViewer[viewer: parent.link]; } ENDLOOP; [] ¬ RopeToViewer[viewer: parent, rope: NIL]; handle.remoteName ¬ NIL; }; }; Menus.MouseButton.yellow, Menus.MouseButton.blue => { handle: Handle ~ NARROW[ViewerOps.FetchProp[ viewer: parent, prop: handleProperty]]; excuse: ROPE ¬ NIL; excuse ¬ BridgeDriver.StartSession[ sessionName~BridgeExec.SessionNameFromSession[session: handle.session], nameAndPasswordProc~NIL, cmd~BridgeDriver.CmdFromListOfRope[LIST[commandName]] ]; IF NOT excuse.IsEmpty[] THEN { ExcuseMe[excuse]; }; IF mouseButton = Menus.MouseButton.blue THEN { ViewerOps.CloseViewer[viewer: parent]; }; }; ENDCASE => ERROR; REditCaption[handle: handle]; }; preResetProc: REF Menus.ClickProc ~ NEW[Menus.ClickProc ¬ PreResetProc]; PreResetProc: Menus.ClickProc ~ { handle: Handle ~ NARROW[ViewerOps.FetchProp[viewer: parent, prop: handleProperty]]; MessageWindow.Append[message: "Confirm reset store of ", clearFirst: TRUE]; MessageWindow.Append[message: handle.remoteName, clearFirst: FALSE]; }; ResetProc: Menus.ClickProc ~ { handle: Handle ~ NARROW[ViewerOps.FetchProp[viewer: parent, prop: handleProperty]]; success: BOOLEAN ¬ FALSE; excuse: ROPE ¬ NIL; WHILE parent.link # NIL AND parent.link # parent DO { ViewerOps.DestroyViewer[viewer: parent.link]; } ENDLOOP; [success: success, excuse: excuse] ¬ NamedFileToViewer[ nsp: handle.nsp, viewer: parent, remoteName: handle.remoteName]; IF success THEN { MessageWindow.Clear[]; parent ¬ ViewerOpsSetNewVersion[viewer: parent, newVersion: FALSE]; } ELSE { ExcuseMe[IO.PutFR["Reset of %g failed: %g", IO.rope[handle.remoteName], IO.rope[excuse]]]; }; }; FileNameFromOldAndNewNames: PROC [old: ROPE, new: ROPE] RETURNS [shortName: ROPE] ~ { slashPos: INT; IF Rope.IsEmpty[new] THEN RETURN [NIL]; IF Rope.IsEmpty[old] THEN RETURN [new]; IF Rope.Find[new, "/"] >= 0 THEN RETURN [new]; IF (slashPos ¬ Rope.FindBackward[old, "/"]) < 0 THEN RETURN [new]; RETURN [Rope.Concat[Rope.Substr[old, 0, 1+slashPos], new]]; }; GetProc: Menus.ClickProc ~ { excuse: ROPE ¬ NIL; { fileName: ROPE ~ ViewerTools.GetSelectionContents[]; handle: Handle ~ NARROW[ViewerOps.FetchProp[viewer: parent, prop: handleProperty]]; success: BOOLEAN ¬ TRUE; fileNameToSend: ROPE; IF Rope.IsEmpty[fileName] THEN { excuse ¬ "null file name"; GOTO NotGood }; fileNameToSend ¬ FileNameFromOldAndNewNames[handle.remoteName, fileName ]; SELECT mouseButton FROM Menus.MouseButton.red => { IF (IF ViewerOpsGetNewVersion[viewer: parent] THEN NOT handle.remoteName.Equal[NIL] ELSE FALSE) THEN { UnsavedEdits[]; } ELSE { WHILE parent.link # NIL AND parent.link # parent DO { ViewerOps.DestroyViewer[viewer: parent.link]; } ENDLOOP; [excuse: excuse, success: success] ¬ NamedFileToViewer[ nsp: handle.nsp, viewer: parent, remoteName: fileNameToSend]; IF NOT success THEN GOTO NotGood; handle.remoteName ¬ fileNameToSend; REditCaption[handle: handle]; }; }; Menus.MouseButton.yellow, Menus.MouseButton.blue => { cmd: ROPE; IF Rope.Fetch[fileNameToSend, 0] # '/ THEN fileNameToSend ¬ Rope.Cat[handle.workingDirectory, "/", fileNameToSend]; cmd ¬ BridgeDriver.CmdFromListOfRope[ LIST[commandName, fileNameToSend] ]; excuse ¬ BridgeDriver.StartSession[ sessionName: BridgeExec.SessionNameFromSession[session: handle.session], nameAndPasswordProc: NIL, cmd: cmd]; IF excuse # NIL THEN GOTO NotGood; IF mouseButton = Menus.MouseButton.blue THEN { ViewerOps.CloseViewer[viewer: parent]; }; }; ENDCASE => ERROR; EXITS NotGood => ExcuseMe[excuse: excuse]; }}; preRemoteStoreProc: REF Menus.ClickProc ~ NEW[Menus.ClickProc ¬ PreRemoteStoreProc]; PreRemoteStoreProc: Menus.ClickProc ~ { handle: Handle ~ NARROW[ViewerOps.FetchProp[viewer: parent, prop: handleProperty]]; handle.pendingName ¬ ViewerTools.GetSelectionContents[]; MessageWindow.Append[message: "Confirm remote store of ", clearFirst: TRUE]; MessageWindow.Append[message: handle.pendingName, clearFirst: FALSE]; }; RemoteStoreProc: Menus.ClickProc ~ { handle: Handle ~ NARROW[ViewerOps.FetchProp[viewer: parent, prop: handleProperty]]; success: BOOLEAN ¬ FALSE; excuse: ROPE ¬ NIL; [success: success, excuse: excuse] ¬ ViewerToNamedFile[ nsp: handle.nsp, remoteName: handle.pendingName, overwrite: GetOverwriteMode[handle], viewer: parent]; IF success THEN { MessageWindow.Clear[]; handle.remoteName ¬ handle.pendingName; handle.pendingName ¬ NIL; REditCaption[handle]; parent ¬ ViewerOpsSetNewVersion[viewer: parent, newVersion: FALSE]; } ELSE { ExcuseMe[IO.PutFR["Remote store of %g failed: %g", IO.rope[handle.pendingName], IO.rope[excuse]]]; }; }; RemoteSaveProc: Menus.ClickProc ~ { handle: Handle ~ NARROW[ViewerOps.FetchProp[viewer: parent, prop: handleProperty]]; success: BOOLEAN ¬ FALSE; excuse: ROPE ¬ NIL; [success: success, excuse: excuse] ¬ ViewerToNamedFile[ nsp: handle.nsp, remoteName: handle.remoteName, overwrite: GetOverwriteMode[handle], viewer: parent]; IF success THEN { parent ¬ ViewerOpsSetNewVersion[viewer: parent, newVersion: FALSE]; } ELSE { ExcuseMe[IO.PutFR["Remote save of %g failed: %g", IO.rope[handle.remoteName], IO.rope[excuse]]]; }; }; SplitProc: Menus.ClickProc ~ { handle: Handle ~ NARROW[ViewerOps.FetchProp[viewer: parent, prop: handleProperty]]; CopyHandleProp: PROCEDURE [] RETURNS [] ~ { FOR split: ViewerClasses.Viewer ¬ parent.link, split.link WHILE split # NIL DO { IF split = parent THEN EXIT; ViewerOps.AddProp[viewer: split, prop: handleProperty, val: handle]; } ENDLOOP; }; TEditSplit.Split[viewer: parent]; ViewerGroupLocks.CallRootAndLinksUnderWriteLock[ proc: CopyHandleProp, viewer: parent]; }; DirectoryProc: Menus.ClickProc ~ { handle: Handle ~ NARROW[ViewerOps.FetchProp[viewer: parent, prop: handleProperty]]; newWDir: ROPE; SELECT mouseButton FROM red => { selectionRope: ROPE ~ ViewerTools.GetSelectionContents[]; newWDir ¬ SetCurDir[handle.nsp, selectionRope]; IF newWDir # NIL THEN { handle.workingDirectory ¬ newWDir; REditCaption[handle]; } ELSE { ExcuseMe[IO.PutFR1["Can't set WD to %g", IO.rope[newWDir]]]; }; }; yellow => { newWDir ¬ GetCurDir[nsp: handle.nsp]; IF newWDir # NIL THEN { handle.workingDirectory ¬ newWDir; MessageWindow.Append[message: "Working Directory is ", clearFirst: TRUE]; MessageWindow.Append[message: handle.workingDirectory, clearFirst: FALSE]; REditCaption[handle]; } ELSE { ExcuseMe["Can't get WD"]; }; }; blue => RETURN; ENDCASE => ERROR; }; IsThisViewerTioga: PROC [viewer: ViewerClasses.Viewer] RETURNS [isTioga: BOOL, plainRope: ROPE] ~ { root: Tioga.Node ~ TiogaOps.ViewerDoc[viewer]; rope: ROPE ~ TiogaIO.RopeFromSimpleDoc[root]; RETURN[isTioga: rope=NIL, plainRope: rope]; }; ViewerOpsGetNewVersion: PROCEDURE [viewer: ViewerClasses.Viewer] RETURNS [newVersion: BOOLEAN ¬ FALSE] ~ { RETURN [newVersion: viewer.newVersion]; }; ViewerOpsSetNewVersion: PUBLIC PROCEDURE [ viewer: ViewerClasses.Viewer, newVersion: BOOLEAN ¬ TRUE] RETURNS [set: ViewerClasses.Viewer ¬ NIL] ~ { FOR v: ViewerClasses.Viewer ¬ viewer, v.link WHILE v # NIL DO { v.newVersion ¬ newVersion; ViewerForkers.ForkPaint[ viewer: v, hint: ViewerClasses.PaintHint.caption, tryShortCuts: TRUE]; IF v.link = viewer THEN EXIT; } ENDLOOP; RETURN [set: viewer]; }; LowerCaseRopeFromRope: PROC [rope: ROPE] RETURNS [lowerCaseRope: ROPE] ~ { ToLower: Rope.TranslatorType -- [old: CHAR] RETURNS [CHAR] -- ~ { RETURN [Ascii.Lower[old]]; }; lowerCaseRope ¬ Rope.Translate[base~rope, translator~ToLower]; }; ExtensionFromFileName: PROC [fileName: ROPE] RETURNS [extensionRope: ROPE] ~ { dotPos: INT; IF Rope.IsEmpty[fileName] THEN RETURN [NIL]; IF (dotPos ¬ Rope.FindBackward[fileName, "."]) < 0 THEN RETURN [NIL]; RETURN [LowerCaseRopeFromRope[Rope.Substr[fileName, 1+dotPos]]]; }; AddFileExtensionProp: PROC [root: TextNode.Ref, extensionRope: ROPE] ~ { extensionAtom: ATOM ~ IF Rope.IsEmpty[extensionRope] THEN $null ELSE Convert.AtomFromRope[extensionRope]; TextEdit.PutProp[node: root, name: $FileExtension, value: extensionAtom]; }; ExcuseMe: PROCEDURE [excuse: ROPE] RETURNS [] ~ { MessageWindow.Append[message: excuse, clearFirst: TRUE]; MessageWindow.Blink[]; }; UnsavedEdits: PROCEDURE [] RETURNS [] ~ { ExcuseMe["DANGER: that viewer contains unsaved edits."]; }; Init[]; }. | BridgeREditImpl.mesa Copyright Σ 1987, 1988, 1989, 1990, 1991, 1992, 1993 by Xerox Corporation. All rights reserved. Peter B. Kessler, February 29, 1988 5:55:38 pm PST Bill Jackson (bj) October 28, 1987 11:24:15 pm PST Bloomenthal, November 25, 1987 3:02:11 pm PST Eduardo Pelegri-Llopart March 9, 1989 8:51:58 am PST Demers, October 14, 1990 11:00 pm PDT Tim Diebert: September 13, 1989 8:31:59 am PDT Chauser, April 10, 1991 9:40 am PDT Willie-s, January 29, 1992 6:46 pm PST Michael Plass, March 10, 1992 4:22 pm PST Doug Wyatt, April 14, 1992 5:07 pm PDT Christian Jacobi, March 19, 1993 12:17 pm PST An implementation of a Bridge REdit server using Tioga as the editor. Types Constants Bridge Procedures Queries C-bridge on its ability to set/query working directory. May raise BridgeComm.Error Get the current directory associated with a control stream Check whether the C-bridge supports it Set the current directory associated with a control stream Check whether the C-bridge supports it PROCEDURE [ nsp: BridgeExec.NetworkStreamPair, -- stream for communication with host. args: ROPE, -- as sent from host, with leading blanks stripped but no other processing performed. The command name is not included. By convention, args are terminated (rather than separated) by CRs. session: BridgeExec.Session, -- session in which this instance is being created. clientData: REF -- the clientData that was passed to AddCommand. ] RETURNS [ instance: BridgeExec.Instance -- newly-created instance, or NIL. ]; PROCEDURE [instance: Instance, clientData: REF] REdit Procedures. Named file to viewer. [nsp: NetworkStreamPair, bytesReported: INT] RETURNS [quit: BOOLEAN _ FALSE] ! UNWIND => something happened to the stream. viewerLabel: ROPE ~ Rope.Cat[sessionName, ": ", handle.remoteName]; split.label _ viewerLabel; Viewer to named file. PROCEDURE [nsp: NetworkStreamPair, bytesReported: INT, clientData: REF] RETURNS [quit: BOOLEAN _ FALSE] ! UNWIND => something happened to the stream. Menu Procedures. --Copies a menu entry from the tioga menu PROC [viewer: Viewer, event: ViewerEvent, before: BOOL] RETURNS[abort: BOOL _ FALSE] PROC [ parent: ViewerClasses.Viewer, clientData: REF ANY _ NIL, mouseButton: MouseButton _ red, shift, control: BOOL _ FALSE] PROC [ parent: ViewerClasses.Viewer, clientData: REF ANY _ NIL, mouseButton: MouseButton _ red, shift, control: BOOL _ FALSE] PROC [ parent: ViewerClasses.Viewer, clientData: REF ANY _ NIL, mouseButton: MouseButton _ red, shift, control: BOOL _ FALSE] Clear the confirm message and the [Edited] flag. PROC [ parent: ViewerClasses.Viewer, clientData: REF ANY _ NIL, mouseButton: MouseButton _ red, shift, control: BOOL _ FALSE] PROC [ parent: ViewerClasses.Viewer, clientData: REF ANY _ NIL, mouseButton: MouseButton _ red, shift, control: BOOL _ FALSE] PROC [ parent: ViewerClasses.Viewer, clientData: REF ANY _ NIL, mouseButton: MouseButton _ red, shift, control: BOOL _ FALSE] Clear the confirm message and the [Edited] flag. PROC [ parent: ViewerClasses.Viewer, clientData: REF ANY _ NIL, mouseButton: MouseButton _ red, shift, control: BOOL _ FALSE] PROC [ parent: ViewerClasses.Viewer, clientData: REF ANY _ NIL, mouseButton: MouseButton _ red, shift, control: BOOL _ FALSE] PROC [ parent: ViewerClasses.Viewer, clientData: REF ANY _ NIL, mouseButton: MouseButton _ red, shift, control: BOOL _ FALSE] Tioga-ness checking ... Just a procedural accessor. This is just like ViewerOps.SetNewVersion if you call it with only the viewer argument. If you call it with the newVersion ~ FALSE, then this unsets the newVersion bit in the viewer, and in all the viewers that are splits from this viewer. This is grotty. The code is stolen from ViewerOpsImplB.IndicateNewVersion, except that I can't call ViewerEvents.ProcessEvent[edit, v, FALSE] to see if any of them abort, since ViewerEvents.ProcessEvent PRIVATE. -- FOR v: Viewer _ viewer, v.link WHILE v # NIL DO -- IF ViewerEvents.ProcessEvent[edit, v, TRUE].abort THEN RETURN; -- IF v.link = viewer THEN EXIT; -- ENDLOOP; -- [] _ ViewerEvents.ProcessEvent[edit, v, FALSE]; File Name Extension / Style Too bad this isn't in some public interface... Messages Initialization. ΚA–(cedarcode) style•NewlineDelimiter ™šœ™Icodešœ ΟeœU™`Kšœ2™2K™2K™-K™4K™%K™.K™#K™&K™)K™&K™-—K˜™EK™šΟk ˜ Kšœ˜Kšœ ˜ K˜ Kšœ ˜ Kšœ ˜ Kšœ˜Kšžœ˜Kšœ˜Kšœ˜K˜Kšœ ˜ K˜Kšœ ˜ Kšœ ˜ K˜ Kšœ ˜ K˜K˜Kšœ ˜ Kšœ ˜ K˜ Kšœ˜Kšœ ˜ Kšœ˜Kšœ˜Kšœ ˜ Kšœ ˜ K˜——K˜šΠlnœžœž˜KšžœFžœΑ˜Kšœ˜head™Kšžœžœžœ˜Kšœžœ ˜7Kšœžœžœ žœ˜#šœ žœžœ˜Kšœ˜Kšœžœ˜ Kšœ žœ˜Kšœ žœ˜Kšœ˜Kšœž˜Kšœ ž˜Kšœž˜Kšœ ž˜Kšœ˜——™ Kšœ žœ ˜Kšœžœ˜$K˜Kšœžœ˜.Kšœžœžœ˜—™š Οnœžœžœ žœžœ˜FJ™?J™Kšœžœ˜ Kšœžœ˜ J™K˜HKšžœ žœ žœ˜!K˜K˜—š   œžœžœ žœžœ˜HK™:Jšœ&™&šž˜Kšœžœ˜—Kšœžœ˜ Kšœžœ˜ Kšœžœžœžœ˜K˜Kšžœžœ žœžœ˜KšœCžœ˜HKšžœ žœžœ˜K˜.K˜K˜K˜—š   œžœ!žœžœ žœžœ˜VK™:Jšœ&™&šž˜Kšœžœ˜—Kšœžœ˜ Kšœ žœ˜Kšœžœžœžœ˜K˜Kšžœžœ žœžœ˜K˜KKšžœ žœžœ˜K˜.K˜K˜—L™š œž œžœ˜!šœ˜Kšœ3žœ˜N—K˜K˜—š œ˜!šž œ™ šœ"™"KšΟc&™&—–(the tabStops 2 .mul 3 sp .add restIndentšœžœ™ Kš‘Ό™Ό—šœ™Kš‘3™3—šœ žœ™Kš‘0™0—Kšœ™šžœ™ Kšœ™Kš‘"™"—K™—Kšœ žœžœžœ˜Kšœ žœ˜Kšœ˜Kšœžœ˜K˜K˜0Kš œ žœ žœžœžœžœ˜<šœ žœ˜Kšœ ˜ Kšœ ˜ Kšœ˜Kšœžœ˜ Kšœ˜Kšœžœ˜ Kšœ žœ˜Kšœžœ˜Kšœ˜—Kšœ6‘ ˜Cšžœ˜Kšžœžœ˜'Kšžœ[˜_—šžœ˜šžœ˜KšœAžœ˜GKšœL˜LK˜yKšœ˜K˜(K˜—šžœ˜Kšœ>˜>Kšœ˜——Kšžœ˜K˜K˜—š œ˜#Kšž œ"žœ™/Kšœžœ ˜"Kšžœžœžœžœ˜#šžœ@žœ žœžœ˜ZKšžœžœžœ˜$Kšœ(˜(Kšœžœ˜ —Kšœ/˜/K˜——™™š   œž œ&žœžœžœžœ#˜ˆK˜0K˜*Kšœžœ˜5Kšžœ˜K˜K˜—š œžœ&žœžœ žœžœ žœžœ žœžœ˜Kšžœ žœžœžœ˜UKšœžœžœ˜Kšœ žœžœ˜š œ˜3š œ(žœžœžœžœ™LKšœžœ%™-—Kšžœžœžœ˜ Kšœžœ˜K˜8Kšžœžœ˜Kšœ˜K˜—Kšžœžœžœ žœ˜UKšœ7‘˜O˜%Kšœ ˜ Kšœ˜Kšœ ˜ —Kšžœ žœ žœžœ.˜NKš žœžœžœ žœžœ žœ˜7Kšžœ žœžœ žœ˜%Kšžœ4˜:šž˜Kšœžœ˜ —K˜K˜—š œž œGžœžœ"žœ žœžœ žœžœ˜ΙKšœžœ˜ K˜8Kšžœ žœ_˜nK˜K˜—š  œž œ!žœžœžœžœ˜^K˜$K˜K˜—š  œž œ žœžœ!žœ˜XK˜/K˜1K˜K˜—š  œž œžœ˜7Kšœ žœ>˜OKšœžœ=˜QKš œ žœžœžœžœ0žœžœ˜nKšœ žœ˜Kšœ žœ2™CK˜š  œž œžœ˜*šžœ9žœ žœžœ˜RK˜Kšœ™KšœL˜LKšžœžœžœ˜(Kšœžœ˜ —K˜K˜—K˜AKšœN˜NK˜K˜——™Kš  œžœ˜K˜š  œžœ˜'šžœ.žœž˜8Kšœ9˜9—K˜K˜—š œžœžœ˜<šžœ ž˜Kšžœ˜"—K˜K˜—š œžœžœ žœ˜Ešžœ ž˜Kšžœ˜!KšžœM˜Q—K˜K˜—š œžœ žœžœ˜LKšœ žœ˜K˜,šžœžœ˜K˜.Kšœ˜K˜K˜—Kšœ˜K˜—š œž œ(žœ žœ žœ žœžœ žœžœ˜³šžœ˜Kšœžœžœ˜,—Kšœ žœžœ˜Kšœžœžœ˜šœžœ˜K˜—š œ˜3šž œ?žœžœžœ™gKšœžœ%™-—Kšžœžœžœ˜ Kšœ žœžœ˜Kšœžœ˜K˜5Kšžœžœ ˜Kšœ˜K˜—Kšžœžœžœ žœ˜SK˜(Kšœ3‘˜KK˜Všžœ žœ žœžœ˜"K˜"K˜—š žœžœžœ žœžœ˜+K˜!K˜—šžœ žœžœ˜Kšœ žœ˜K˜—Kšžœ$˜*K˜K˜—š   œž œ!žœžœ žœžœ˜cK•StartOfExpansionF[self: STREAM, r: ROPE, start: INT _ 0, len: INT _ 2147483647]šžœ!˜#Kšžœ žœ˜K˜K˜———™š   œž œ'žœžœ!žœ˜rK˜&š  œžœ žœ˜%K™)K˜Všžœžœžœ˜K˜HK˜—K˜—šœ˜Kšœ ˜ šœ˜Kšœ˜Kšœ˜——šœ˜Kšœ ˜ šœ˜Kšœ˜Kšœ˜Kšœ žœ˜Kšœ˜——šœ˜Kšœ ˜ šœ˜Kšœ ˜ Kšœ˜——šœ˜Kšœ ˜ šœ˜Kšœ˜Kšœ˜Kšœ žœ˜Kšœ$˜$——šœ˜Kšœ ˜ šœ˜Kšœ˜Kšœ˜——šœ˜Kšœ ˜ Kšœ9˜9Kšœ ˜ —K˜K˜K˜šžœž˜ šœ˜Kšœ ˜ Kšœ:˜:K˜ ——K˜K˜K˜K˜3K˜/˜$Kšœ_ž˜cK˜—K˜Kšžœ˜K˜K˜—š œ˜2Kš žœ.žœžœžœžœ™TKšœžœ<˜SKš žœžœ žœžœžœ˜/šžœ ž˜šžœ˜šžœžœžœ˜-šžœ˜Kšœ3˜3K˜—šžœ˜K˜K˜——K˜——Kšžœ žœ˜Kšœ˜K˜—š  œ˜Kš žœ.žœžœžœ4žœžœ™€Kšœžœ<˜SK˜šžœ ž˜˜šžœžœ(žœžœžœžœžœ˜_šžœ˜K˜K˜—šžœ˜šžœžœžœžœ˜5K˜-Kšœžœ˜ —Kšœ(žœ˜-Kšœžœ˜K˜——K˜—K˜˜šœžœ˜,Kšœ'˜'—Kšœžœžœ˜K˜˜#K˜GKšœžœ˜Kšœ#žœ˜8—šžœžœžœ˜K˜K˜—šžœ&žœ˜.K˜&K˜—K˜—Kšžœžœ˜—Kšœ˜K˜K˜—Kšœžœžœ!˜Hš  œ˜!šžœ™Kšœ™Kšœ žœžœžœ™Kšœ ™ Kšœžœžœ™—Kšœžœ<˜SK˜KšœEžœ˜KKšœ=žœ˜DK˜K˜—š  œ˜Kš žœ.žœžœžœ4žœžœ™€Kšœžœ<˜SKšœ žœžœ˜Kšœžœžœ˜K˜šžœžœžœžœ˜5K˜-Kšœžœ˜ —˜7Kšœ@˜@—šžœ ˜ šžœ˜K™0K˜Kšœ<žœ˜CK˜—šžœ˜Kšœ žœ!žœžœ˜ZK˜——K˜K˜—š  œžœžœžœžœ žœ˜UKšœ žœ˜Kšžœžœžœžœ˜'Kšžœžœžœ˜'Kšžœžœžœ˜.Kšžœ.žœžœ˜BKšžœ5˜;K˜K˜—š œ˜Kš žœ.žœžœžœ4žœžœ™€Kšœžœžœ˜K˜Kšœ žœ&˜4Kšœžœ<˜SKšœ žœžœ˜Kšœžœ˜K˜Kšžœžœžœ ˜KK˜K˜JK˜šžœ ž˜˜šžœžœ(žœžœžœžœžœ˜`šžœ˜K˜K˜—šžœ˜šžœžœžœžœ˜5K˜-Kšœžœ˜ —˜7Kšœ=˜=—Kšžœžœ žœžœ ˜!K˜#K˜K˜——K˜—K˜˜Kšœžœ˜ šžœ#˜%KšžœI˜M—Kšœ&žœ ˜J˜#K˜HKšœžœ˜Kšœ ˜ —Kšžœ žœžœžœ ˜"šžœ&žœ˜.K˜&K˜—K˜—Kšžœžœ˜—šž˜K˜$—K˜—K˜K˜Kšœ Οtœžœžœ'˜Tš œ˜'šžœ™Kšœ™Kšœ žœžœžœ™Kšœ ™ Kšœžœžœ™—Kšœžœ<˜SK˜K˜8KšœFžœ˜LKšœ>žœ˜EK˜K˜—š Πnt œ˜$Kš žœ.žœžœžœ4žœžœ™€Kšœžœ<˜SKšœ žœžœ˜Kšœžœžœ˜K˜K˜˜7Kšœf˜f—šžœ ˜ šžœ˜K™0K˜K˜'Kšœžœ˜Kšœ˜Kšœ<žœ˜CK˜—šžœ˜Kšœ žœ(žœžœ˜bK˜——K˜K˜—š £ œ˜#Kš žœ.žœžœžœ4žœžœ™€Kšœžœ<˜SKšœ žœžœ˜Kšœžœžœ˜K˜˜7Kšœe˜e—K˜šžœ ˜ šžœ˜Kšœ<žœ˜CK˜—šžœ˜Kš œ žœ’œžœžœ˜`K˜——K˜K˜—š  œ˜Kš žœ.žœžœžœ4žœžœ™€Kšœžœ<˜Sš œž œžœ˜+šžœ7žœ žœžœ˜PKšžœžœžœ˜KšœD˜DKšœžœ˜ —K˜—K˜K˜!šœ0˜0Kšœ&˜&—K˜K˜—š  œ˜"Kš žœ.žœžœžœ4žœžœ™€Kšœžœ<˜SKšœ žœ˜K˜šžœ ž˜˜Kšœžœ&˜9K˜/šžœ ž˜šžœ˜K˜"K˜K˜—šžœ˜Kšœ žœžœ˜K˜K˜—š  œžœ žœžœžœ˜NKšœžœ˜ K˜Kšžœžœžœžœ˜,Kšžœ1žœžœžœ˜EKšžœ:˜@K˜—K˜–[node: TextEdit.RefTextNode, name: ATOM, value: REF ANY, event: TextEdit.Event _ NIL, root: TextEdit.RefTextNode _ NIL]š œžœ%žœ˜HKš œžœžœžœžœ%˜iK˜IK˜K˜——™š œž œ žœžœ˜1Kšœ2žœ˜8K˜K˜K˜—š  œž œžœ˜)Kšœ8˜8K˜K˜——™K˜—Kšœ˜K˜——…—JtΥ