DIRECTORY
Directory USING [Error, Lookup, ignore],
IO USING [PutF, Flush, RIS, ROPE, rope, STREAM, UserAborted, GetSequence, CharProc],
MessageWindow USING [Append],
Resource USING [AbortProc, Acquire, Release],
Rope USING [Cat, Concat, Fetch, Find, IsEmpty, Length, Replace, ROPE, Substr, ToRefText],
Spell USING [AbortProc, ConfirmProc, defaultModes, Filter, GetMatchingFileList, GetMatchingList, GetTheFile, GetTheOne, InformProc, IsAPattern, Modes, SpellingGenerator, SpellingList],
SpellExtras USING [GetFileExtension],
TiogaOps USING [RegisterFileNameProc],
UserExec USING [CheckForFile, HistoryEvent, ExecHandle, CheckForAbort, UserAbort, UserAborted, Confirm, GetExecHandle, GetUserResponse, SetupAskUser, FinishAskUser, GetTheOne, GetTheFile, RopeSubst, Viewer, AcquireStreams, ReleaseStreams],
UserExecExtras USING [CorrectionDisabled],
UserExecPrivate USING [],
UserProfile USING [Boolean, ProfileChangedProc, CallWhenProfileChanges],
ViewerAbort USING [UserAbort],
ViewerTools USING [GetSelectedViewer]
;
GetTheOne, GetTheFile, etc.
terminateCorrection: ERROR = CODE;
GetTheOne:
PUBLIC
PROCEDURE[
unknown: ROPE,
spellingList: Spell.SpellingList ← NIL,
generator: Spell.SpellingGenerator ← NIL,
event: HistoryEvent,
exec: ExecHandle,
viewer: Viewer ← NIL,
filter: Spell.Filter ← NIL,
modes: Spell.Modes ← NIL
]
RETURNS [correct:
ROPE ←
NIL] = {
Abort: Spell.AbortProc = {
hasResponded: BOOL;
value: ATOM;
UserExec.CheckForAbort[exec];
IF viewer # NIL AND ViewerAbort.UserAbort[viewer] THEN IO.UserAborted[viewer];
IF viewer # NIL THEN [hasResponded, value] ← UserExec.GetUserResponse[viewer];
IF hasResponded AND value = $No THEN ERROR terminateCorrection;
};
Confirm: Spell.ConfirmProc
-- [msg: ROPE, timeout: INT, defaultConfirm: BOOL] RETURNS[yes: BOOL] -- = {
RETURN[
UserExec.Confirm[msg: msg, timeout: timeout, defaultConfirm: defaultConfirm, exec: exec, viewer: viewer]
]
};
Inform: Spell.InformProc
--[msg: ROPE] -- = {
IF exec #
NIL
THEN
{out ← UserExec.AcquireStreams[exec].out; -- since this can be called from random place, must acquire and release streams rather than using GetStreams
out.PutF["*n*m%g*s\n", rope[msg]];
}
ELSE MessageWindow.Append[message: msg, clearFirst: TRUE];
};
out: IO.STREAM;
IF Rope.IsEmpty[unknown] OR UserExecExtras.CorrectionDisabled[event] THEN RETURN[NIL];
{ENABLE UNWIND => Finish[exec, viewer, out];
IF exec # NIL THEN viewer ← exec.viewer;
IF viewer # NIL THEN UserExec.SetupAskUser[viewer];
correct ← Spell.GetTheOne[unknown: unknown, spellingList: spellingList, generator: generator, filter: filter, abort: Abort, confirm: Confirm, inform: Inform, modes: modes ! terminateCorrection => CONTINUE];
IF exec # NIL THEN FixCommandLine[old: unknown, new: correct, event: event, exec: exec];
Finish[exec, viewer, out];
};
};
GetMatchingList:
PUBLIC
PROCEDURE[
unknown: ROPE,
spellingList: Spell.SpellingList ← NIL,
generator: Spell.SpellingGenerator ← NIL,
event: HistoryEvent,
exec: ExecHandle,
viewer: Viewer ← NIL,
filter: Spell.Filter ← NIL,
modes: Spell.Modes ← NIL
]
RETURNS [matching:
LIST
OF
ROPE ←
NIL] = {
Abort: Spell.AbortProc = {
hasResponded: BOOL;
value: ATOM;
UserExec.CheckForAbort[exec];
IF viewer # NIL AND ViewerAbort.UserAbort[viewer] THEN IO.UserAborted[viewer];
IF viewer # NIL THEN [hasResponded, value] ← UserExec.GetUserResponse[viewer];
IF hasResponded AND value = $No THEN ERROR terminateCorrection;
};
Confirm: Spell.ConfirmProc
-- [msg: ROPE, timeout: INT, defaultConfirm: BOOL] RETURNS[yes: BOOL] -- = {
RETURN[
UserExec.Confirm[msg: msg, timeout: timeout, defaultConfirm: defaultConfirm, exec: exec, viewer: viewer]
]
};
Inform: Spell.InformProc
--[msg: ROPE] -- = {
IF exec #
NIL
THEN
{out ← UserExec.AcquireStreams[exec].out; -- since this can be called from random place, must acquire and release streams rather than using GetStreams
out.PutF["*n*m%g*s\n", rope[msg]];
}
ELSE MessageWindow.Append[message: msg, clearFirst: TRUE];
};
out: IO.STREAM;
IF Rope.IsEmpty[unknown] THEN RETURN[NIL];
IF
NOT Spell.IsAPattern[unknown]
THEN
{val: ROPE ← UserExec.GetTheOne[unknown: unknown, spellingList: spellingList, generator: generator, event: event, exec: exec, filter: filter, modes: modes];
IF val # NIL THEN RETURN[LIST[val]]
ELSE RETURN[NIL];
};
{ENABLE UNWIND => Finish[exec, viewer, out];
IF exec # NIL THEN viewer ← exec.viewer;
IF viewer #
NIL
THEN {
IF Spell.defaultModes.confirm >= patternMatch THEN UserExec.SetupAskUser[viewer]
ELSE viewer ← NIL; -- no point in putting up yes/no if confirmation won't be needed
};
matching ← Spell.GetMatchingList[pattern: unknown, spellingList: spellingList, generator: generator, filter: filter, abort: Abort, confirm: Confirm, inform: Inform, modes: modes ! terminateCorrection => CONTINUE];
Finish[exec, viewer, out];
};
};
CheckForFile:
PUBLIC
PROC [file:
ROPE]
RETURNS [found:
BOOLEAN] =
TRUSTED
{
-- Directory
fName: LONG STRING;
fName ← LOOPHOLE[Rope.ToRefText[file]];
found ← TRUE;
IF Rope.Length[file] = 0 THEN RETURN[FALSE];
[] ← Directory.Lookup[fileName: fName, permissions: Directory.ignore
! Directory.Error =>
{found ← FALSE; CONTINUE}
];
GetTheFile:
PUBLIC
PROC [file:
ROPE, defaultExt:
ROPE ←
NIL, event: HistoryEvent, exec: ExecHandle, viewer: Viewer ←
NIL, modes: Spell.Modes ←
NIL]
RETURNS [name:
ROPE ←
NIL] = {
i: INT;
out: IO.STREAM;
IF Rope.IsEmpty[file] THEN RETURN[NIL];
{ENABLE UNWIND => Finish[exec, viewer, out];
{
IF (i ← Rope.Find[s1: file, s2: "/"]) # -1
THEN
{IF i # 0 THEN file ← Rope.Substr[base: file, len: i] -- ignore switches
ELSE IF Rope.Find[s1: file, s2: "/", pos1: 1] = -1 THEN GOTO FullPath
ELSE RETURN[NIL];
};
IF Rope.Find[file, "["] # -1 OR Rope.Find[file, "<"] # -1 THEN GOTO FullPath;
EXITS
FullPath => RETURN[NIL];
};
IF CheckForFile[file] THEN RETURN[file];
IF (i ← Rope.Find[file, "."]) = -1 AND Rope.Length[defaultExt] # 0 THEN name ← Rope.Cat[file, ".", defaultExt]
ELSE name ← file;
IF CheckForFile[name] THEN RETURN[name];
IF UserExecExtras.CorrectionDisabled[event] THEN RETURN[NIL];
{
Abort: Spell.AbortProc = {
hasResponded: BOOL;
value: ATOM;
UserExec.CheckForAbort[exec];
IF viewer # NIL AND ViewerAbort.UserAbort[viewer] THEN IO.UserAborted[viewer];
IF viewer # NIL THEN [hasResponded, value] ← UserExec.GetUserResponse[viewer];
IF hasResponded AND value = $No THEN ERROR terminateCorrection;
};
Confirm: Spell.ConfirmProc
-- [msg: ROPE, timeout: INT, defaultConfirm: BOOL] RETURNS[yes: BOOL] -- = {
RETURN[
UserExec.Confirm[msg: msg, timeout: timeout, defaultConfirm: defaultConfirm, exec: exec, viewer: viewer]
]
};
Inform: Spell.InformProc
-- [msg: ROPE] -- = {
IF exec #
NIL
THEN
{out ← UserExec.AcquireStreams[exec].out; -- since this can be called from random place, must acquire and release streams rather than using GetStreams
out.PutF["*n*m%g*s\n", rope[msg]];
}
ELSE MessageWindow.Append[message: msg, clearFirst: TRUE];
};
IF exec # NIL THEN viewer ← exec.viewer;
IF viewer # NIL THEN UserExec.SetupAskUser[viewer];
name ← Spell.GetTheFile[unknown: file, defaultExt: defaultExt, abort: Abort, confirm: Confirm, inform: Inform, modes: modes ! terminateCorrection => CONTINUE];
IF name #
NIL
THEN {
i: INT;
new: ROPE = IF (i ← Rope.Find[file, "."]) = -1 AND (i ← Rope.Find[name, "."]) # -1 THEN Rope.Substr[base: name, len: i] ELSE name; -- if original file did not have an extension and name does, strip it off for purposes of correcting history.
IF exec #
NIL
THEN
{FixCommandLine[old: file, new: new, event: event, exec: exec];
};
};
Finish[exec, viewer, out];
};
};
};
GetMatchingFileList:
PUBLIC
PROC [file:
ROPE, defaultExt:
ROPE ←
NIL, event: HistoryEvent, exec: ExecHandle, viewer: Viewer ←
NIL, modes: Spell.Modes ←
NIL]
RETURNS [fileList:
LIST
OF
ROPE ←
NIL] = {
out: IO.STREAM;
IF Rope.IsEmpty[file] THEN RETURN[NIL];
IF
NOT Spell.IsAPattern[file]
THEN
{val: ROPE = UserExec.GetTheFile[file: file, defaultExt: defaultExt, event: event, exec: exec];
IF val # NIL THEN RETURN[LIST[val]]
ELSE RETURN[NIL];
};
{
ENABLE UNWIND => Finish[exec, viewer, out];
Abort: Spell.AbortProc = {
hasResponded: BOOL;
value: ATOM;
UserExec.CheckForAbort[exec];
IF viewer # NIL AND ViewerAbort.UserAbort[viewer] THEN IO.UserAborted[viewer];
IF viewer # NIL THEN [hasResponded, value] ← UserExec.GetUserResponse[viewer];
IF hasResponded AND value = $No THEN ERROR terminateCorrection;
};
Confirm: Spell.ConfirmProc
-- [msg: ROPE, timeout: INT, defaultConfirm: BOOL] RETURNS[yes: BOOL] -- = {
RETURN[
UserExec.Confirm[msg: msg, timeout: timeout, defaultConfirm: defaultConfirm, exec: exec, viewer: viewer]
]
};
Inform: Spell.InformProc
--[msg: ROPE] -- = {
IF exec #
NIL
THEN
{out ← UserExec.AcquireStreams[exec].out; -- since this can be called from random place, must acquire and release streams rather than using GetStreams
out.PutF["*n*m%g*s\n", rope[msg]];
}
ELSE MessageWindow.Append[message: msg, clearFirst: TRUE];
};
IF exec # NIL THEN viewer ← exec.viewer;
IF viewer #
NIL
THEN {
IF Spell.defaultModes.confirm >= patternMatch THEN UserExec.SetupAskUser[viewer]
ELSE viewer ← NIL; -- no point in putting up yes/no if confirmation won't be needed
};
fileList ← Spell.GetMatchingFileList[unknown: file, defaultExt: defaultExt, abort: Abort, inform: Inform, confirm: Confirm, modes: modes ! terminateCorrection => CONTINUE];
Finish[exec, viewer, out];
};
};
Finish:
PROCEDURE [exec: UserExec.ExecHandle, viewer: Viewer, out:
STREAM] = {
IF out # NIL THEN UserExec.ReleaseStreams[exec];
IF viewer # NIL THEN UserExec.FinishAskUser[viewer];
};
FixCommandLine:
PROC [old, new:
ROPE, event: HistoryEvent, exec: UserExec.ExecHandle] = {
IF event #
NIL
AND new #
NIL
THEN {
event.input ← UserExec.RopeSubst[old, new, event.input];
event.commandLine ← UserExec.RopeSubst[old, new, event.commandLine];
[] ← IO.RIS[UserExec.RopeSubst[old, new, GetRestOfStream[event.commandLineStream]], event.commandLineStream];
};
};
GetRestOfStream:
PROC [in:
STREAM]
RETURNS[
ROPE] =
{charProc: IO.CharProc = {RETURN[FALSE, TRUE]};
RETURN[IO.GetSequence[in, charProc]];
};
RopeSubst:
PUBLIC
PROC [old, new, base:
ROPE, case:
BOOLEAN ←
FALSE, allOccurrences:
BOOLEAN ←
TRUE]
RETURNS[
ROPE] = {
lenOld: INT = Rope.Length[old];
lenNew: INT = Rope.Length[new];
i: INT ← 0;
WHILE (i ← Rope.Find[s1: base, s2: old, case: case, pos1: i]) # -1
DO
base ← Rope.Replace[base: base, start: i, len: Rope.Length[old], with: new];
IF ~allOccurrences THEN EXIT;
i ← i + lenNew;
ENDLOOP;
RETURN[base];
};