Bridge Procedures
HasPWD:
PROC[nsp: NetworkStreamPair]
RETURNS [hasIt:
BOOL ¬
FALSE] ~ {
Queries C-bridge on its ability to set/query working directory.
May raise BridgeComm.Error
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] ~ {
Get the current directory associated with a control stream
Check whether the C-bridge supports it
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] ~ {
Set the current directory associated with a control stream
Check whether the C-bridge supports it
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 ~ {
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.
];
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 ~ {
PROCEDURE [instance: Instance, clientData: REF]
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];
};
Menu Procedures.
REditMenu:
PROCEDURE [viewer: ViewerClasses.Viewer, addWD:
BOOL]
RETURNS [result: ViewerClasses.Viewer ¬
NIL] ~ {
menu: Menus.Menu ¬ Menus.CreateMenu[];
CopyEntry:
PROC [name: Rope.
ROPE] = {
--Copies a menu entry from the tioga menu
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 ~ {
PROC [viewer: Viewer, event: ViewerEvent, before: BOOL]
RETURNS[abort: BOOL ← FALSE]
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 ~ {
PROC [
parent: ViewerClasses.Viewer,
clientData: REF ANY ← NIL,
mouseButton: MouseButton ← red,
shift, control: BOOL ← FALSE]
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)
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 ~ {
PROC [
parent: ViewerClasses.Viewer,
clientData: REF ANY ← NIL,
mouseButton: MouseButton ← red,
shift, control: BOOL ← FALSE]
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 ~ {
PROC [
parent: ViewerClasses.Viewer,
clientData: REF ANY ← NIL,
mouseButton: MouseButton ← red,
shift, control: BOOL ← FALSE]
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 {
Clear the confirm message and the [Edited] flag.
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 ~ {
PROC [
parent: ViewerClasses.Viewer,
clientData: REF ANY ← NIL,
mouseButton: MouseButton ← red,
shift, control: BOOL ← FALSE]
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)
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 ~ {
PROC [
parent: ViewerClasses.Viewer,
clientData: REF ANY ← NIL,
mouseButton: MouseButton ← red,
shift, control: BOOL ← FALSE]
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];
};
Remote
StoreProc: Menus.ClickProc ~ {
PROC [
parent: ViewerClasses.Viewer,
clientData: REF ANY ← NIL,
mouseButton: MouseButton ← red,
shift, control: BOOL ← FALSE]
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 {
Clear the confirm message and the [Edited] flag.
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]]];
};
};
Remote
SaveProc: Menus.ClickProc ~ {
PROC [
parent: ViewerClasses.Viewer,
clientData: REF ANY ← NIL,
mouseButton: MouseButton ← red,
shift, control: BOOL ← FALSE]
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 ~ {
PROC [
parent: ViewerClasses.Viewer,
clientData: REF ANY ← NIL,
mouseButton: MouseButton ← red,
shift, control: BOOL ← FALSE]
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 ~ {
PROC [
parent: ViewerClasses.Viewer,
clientData: REF ANY ← NIL,
mouseButton: MouseButton ← red,
shift, control: BOOL ← FALSE]
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;
};
Tioga-ness checking ...
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] ~ {
Just a procedural accessor.
RETURN [newVersion: viewer.newVersion];
};
ViewerOpsSetNewVersion:
PUBLIC
PROCEDURE [
viewer: ViewerClasses.Viewer,
newVersion:
BOOLEAN ¬
TRUE]
RETURNS [set: ViewerClasses.Viewer ¬
NIL] ~ {
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;
FOR v: ViewerClasses.Viewer ¬ viewer, v.link
WHILE v #
NIL
DO {
v.newVersion ¬ newVersion;
ViewerForkers.ForkPaint[
viewer: v, hint: ViewerClasses.PaintHint.caption, tryShortCuts: TRUE];
-- [] ← ViewerEvents.ProcessEvent[edit, v, FALSE];
IF v.link = viewer THEN EXIT;
} ENDLOOP;
RETURN [set: viewer];
};
}.