TEditInputImpl.mesa
Copyright Ó 1985, 1986, 1987, 1989, 1991, 1992 by Xerox Corporation. All rights reserved.
Paxton on December 28, 1982 2:21 pm
Maxwell, January 4, 1983 3:53 pm
Russ Atkinson, July 25, 1983 7:02 pm
Bier, April 22, 1990 1:14 pm PDT
Michael Plass, March 23, 1989 2:43:33 pm PST
Doug Wyatt, April 23, 1992 11:39 am PDT
DIRECTORY
Atom, EditSpan, EditSpanSupport, InputFocus, MessageWindow, NodeAddrs, RefTab, Rope,
TEditDisplay USING [EstablishLine],
TEditDocument USING [LineTable, maxClip, Selection, SelectionId, SelectionRec, SpinAndLock, TEditDocumentData, Unlock],
TEditInput USING [CloseEvent, closeEvent, CloseEventNow, ComIndex, CommandProc, EditState, RecordChar, RecordRef],
TEditInputBackdoor USING [EditObject, SelState, PDelState, MouseColor],
TEditInputExtras USING [CommandClosure, CommandClosureProc],
TEditInputOps USING [BackSpace, BackWord, Break, BufferedInsertChar, BufferedInsertText, CallWithLocks, Capitalise, ChangeCaretLooks, ChangeLooks, Copy, CopyFormat, CopyLooks, Delete, DeleteNextChar, DeleteNextWord, DoPendingDelete, ExpandAbbreviation, FindPlaceholders, GetFormat, GoToNextChar, GoToNextNode, GoToNextWord, GoToPreviousChar, GoToPreviousNode, GoToPreviousWord, InsertBrackets, InsertChar, InsertLineBreak, InsertRope, InsertTime, Join, LoadAbbreviations, MakeControlCharacter, MakeOctalCharacter, ModifyCaretLook, ModifyLook, Move, Nest, NextViewer, Paste, ReloadStyle, SaveForPaste, SelectMatchingBrackets, SetCommentProp, SetFormat, SetStyle, Transpose, TransposeFormat, TransposeLooks, UnMakeControlCharacter, UnMakeOctalCharacter, WaitForInsertToFinish, UnNest],
TEditInputPrivate USING [InternalCommandCounts, InternalCommandCountsRep, InternalID, TraceProcs],
TEditOps USING [CopyLoadHistory, CopyPositionHistory, RememberCurrentPosition],
TEditPrivate USING [ReloadReadonlyTipTable, ReloadTipTable, ReloadTypeScriptTipTable],
TEditProfile USING [CategoryOfUser, ReadProfile, userCategory],
TEditScrolling USING [ScrollToPosition],
TEditSelection USING [CallWithSelAndDocAndTddLocks, CancelPrimary, CancelSecondary, CaretAfterSelection, CaretBeforeSelection, Copy, Create, Extend, FakeSecondary, Find, fSel, GrowSelection, GrowSelectionToBlanks, InsertionPoint, LevelChange, LockSel, MakePointSelection, MakePrimary, MakeSecondary, MakeSelection, NotPendingDeleteSelection, oldSel, PendingDeleteSelection, pSel, SelectBranch, SelectChar, SelectEverything, SelectNode, SelectWord, ShowPosition, sSel, UnlockSel, Update],
TEditSelectionOpsExtras USING [CurrentPositionMessage, GoToEndOfNode],
TEditSplit USING [],
TEditTouchup USING [LockAfterRefresh, UnlockAfterRefresh],
TextEdit USING [Size, GetNewlineDelimiter],
TextLooks USING [allLooks, noLooks],
TextNode USING [FirstChild, ForwardClipped, Level, Location, NodeItself, Offset, Parent, Ref, RefTextNode, Root],
TiogaOps USING [],
TIPUser USING [TIPScreenCoords, TIPScreenCoordsRec],
UserProfile USING [CallWhenProfileChanges, ProfileChangedProc],
ViewerClasses USING [NotifyProc, Viewer],
ViewerForkers,
ViewerLocks,
ViewerOps USING [AddProp, ComputeColumn, CreateViewer, DestroyViewer, FetchProp, MoveBelowViewer, OpenIcon, SetMenu],
ViewersWorld,
ViewersWorldInstance,
WindowManager USING [UnWaitCursor, WaitCursor];
TEditInputImpl: CEDAR MONITOR
IMPORTS Atom, EditSpan, EditSpanSupport, InputFocus, MessageWindow, NodeAddrs, RefTab, Rope, TEditDisplay, TEditDocument, TEditInput, TEditInputOps, TEditOps, TEditPrivate, TEditProfile, TEditScrolling, TEditSelection, TEditSelectionOpsExtras, TEditTouchup, TextEdit, TextNode, UserProfile, ViewerForkers, ViewerLocks, ViewerOps, ViewersWorld, ViewersWorldInstance, WindowManager
EXPORTS TEditInput, TEditInputBackdoor, TEditInputExtras, TEditInputPrivate, TEditPrivate, TEditSplit, TiogaOps
= BEGIN OPEN TEditInput;
ROPE: TYPE ~ Rope.ROPE;
Documentation: Tioga's Input Format
This section was written on October 23, 1987, by Michael Plass
Michael Plass, October 23, 1987 5:28:55 pm PDT
This module handles the input that comes from TIP, menu clicks, EditTool ops, etc. The input is a LIST OF REF, where the actual REFs must be one of:
ATOM => The name of a registered operation
ROPE, REF CHAR, REF TEXT => Treated as user typein (but see $PARAM, below)
TIP.TIPScreenCoords => Mouse position info
REF INT => A numeric parameter used by some of the ops in this interface. (ugh, global state)
(New as of October 23, 1987) The ATOM $PARAM is treated specially, in that the immediately following item is coerced to a ROPE, and not treated as user typein, but instead is passed to the CommandClosureProc of the immediately following operation. Note that this param cannot be accessed from a CommandProc, because of interface restrictions.
Instrumentation
traceProcs: TEditInputPrivate.TraceProcs ¬ NIL;
SetTraceProcs: PUBLIC PROC [procs: TEditInputPrivate.TraceProcs] ~ { traceProcs ¬ procs };
InternalCommandCounts: TYPE ~ TEditInputPrivate.InternalCommandCounts;
InternalCommandCountsRep: TYPE ~ TEditInputPrivate.InternalCommandCountsRep;
internalCommandCounts: InternalCommandCounts ~ NEW[InternalCommandCountsRep ¬ ALL[0]];
GetInternalCommandCounts: PUBLIC PROC RETURNS [InternalCommandCounts] ~ {
RETURN[internalCommandCounts];
};
Input handling
commandTable: RefTab.Ref ¬ RefTab.Create[mod: 101];
my, mx: INTEGER; -- global Coord param for ops below
set by SaveCoords (called by InterpInput)
used by SelChar, SelWord, SelNode, SelBranch, SelUpdate, Extend
SelState: TYPE ~ TEditInputBackdoor.SelState; -- {reset, primary, secondary}
selState: PUBLIC -- TEditInputBackdoor -- SelState ¬ reset;
set by SelPrimary, SelSecondary
reset by DoEdit, EditReset
used by SelPrimary, SelSecondary (to decide whether to change sel)
SelectionId: TYPE ~ TEditDocument.SelectionId; -- {primary, secondary, feedback}
sel: PUBLIC -- TEditInputBackdoor -- SelectionId ¬ primary;
set by SelPrimary, SelSecondary
reset by DoEdit
used by Sel*, Copy, Move, Transpose
PDelState: TYPE ~ TEditInputBackdoor.PDelState; -- {reset, pending, not}
pdelState: PUBLIC -- TEditInputBackdoor -- PDelState ¬ reset;
set by SelPendDel, SelNotPendDel, ForceSelPendDel, ForceSelNotPendDel
reset by DoEdit, EditReset
used by SelPendDel, SelNotPendDel (to decide whether to change pDel)
pDel: PUBLIC -- TEditInputBackdoor -- BOOL ¬ FALSE;
set by SelPendDel, SelNotPendDel, ForceSelPendDel, ForceSelNotPendDel
reset by DoEdit
used by SelChar, SelWord, SelNode, SelBranch, SelUpdate, Extend
LevelChange: TYPE ~ TEditSelection.LevelChange; -- {reduce, expand, same}
changeLevel: LevelChange;
set by SelExpand, SelReduce
reset by ResetInputStuff
used by Extend
EditState: TYPE ~ TEditInput.EditState; -- {reset, abort, tolimbo, toprimary, tosecondary, toboth}
editState: PUBLIC EditState ¬ reset;
set by ToPrimary, ToSecondary, ToBoth, ToLimbo, EditAbort, AbortSecondary
reset by DoEdit, EditReset
used by Sel*, EditMessage, DoEdit
EditObject: TYPE ~ TEditInputBackdoor.EditObject; -- {text, looks, format}
editObject: PUBLIC -- TEditInputBackdoor -- EditObject ¬ text;
set by EditText, EditLooks, EditFormat
reset by DoEdit, EditReset, EditAbort
used by EditMessage, DoEdit
MouseColor: TYPE ~ TEditInputBackdoor.MouseColor; -- {red, yellow, blue, dead}
mouseColor: PUBLIC -- TEditInputBackdoor -- MouseColor ¬ red;
set by RedMouse, YellowMouse, BlueMouse, Extend, EditAbort, AbortSecondary
reset by DoEdit
used by RedDown, YellowDown, BlueDown
prevPSel: TEditDocument.Selection ~ NEW[TEditDocument.SelectionRec];
set by RedMouse, YellowMouse, BlueMouse, Extend
used by EditAbort
interrupt: PUBLIC REF BOOL ¬ NEW[BOOL ¬ FALSE];
set by EditAbort
positionMessage: ROPE ¬ NIL;
saved message for StuffPosition
editMessage: PUBLIC -- TEditInputBackdoor -- ROPE ¬ NIL;
EditMessage: PROC = {
pPendingDelete: BOOL ~ TEditSelection.pSel.pendingDelete;
sPendingDelete: BOOL ~ TEditSelection.sSel.pendingDelete;
msg: ROPE ~ SELECT editState FROM
tolimbo => "Select for delete",
toprimary => SELECT editObject FROM
text => SELECT TEditSelection.pSel.pendingDelete FROM
FALSE => SELECT TEditSelection.sSel.pendingDelete FROM
FALSE => "Select for copy to caret",
TRUE => "Select for move to caret",
ENDCASE => NIL,
TRUE => SELECT TEditSelection.sSel.pendingDelete FROM
FALSE => "Select replacement",
TRUE => "Select for move onto",
ENDCASE => NIL,
ENDCASE => NIL,
looks => "Select looks to copy",
format => "Select format to copy",
ENDCASE => NIL,
tosecondary => SELECT editObject FROM
text => SELECT TEditSelection.pSel.pendingDelete FROM
FALSE => SELECT TEditSelection.sSel.pendingDelete FROM
FALSE => "Select destination for copy",
TRUE => "Select for replacement",
ENDCASE => NIL,
TRUE => SELECT TEditSelection.sSel.pendingDelete FROM
FALSE => "Select destination for move",
TRUE => "Select destination for move onto",
ENDCASE => NIL,
ENDCASE => NIL,
looks => "Select destination for copy looks",
format => "Select destination for copy format",
ENDCASE => NIL,
toboth => SELECT editObject FROM
text => "Select for transpose",
looks => "Select for transpose looks",
format => "Select for transpose format",
ENDCASE => NIL,
ENDCASE => NIL;
IF msg = NIL OR msg = editMessage THEN RETURN;
MessageWindow.Append[msg,TRUE];
editMessage ¬ msg
};
Interpret: PUBLIC PROC [viewer: ViewerClasses.Viewer, params: LIST OF REF ANY] = {
InterpInput[viewer,params]
};
InterpretAtom: PUBLIC PROC [viewer: ViewerClasses.Viewer, atom: ATOM] = {
InterpAtom[viewer: viewer, atom: atom, param: NIL];
};
TEditNotifyProc: PUBLIC ViewerClasses.NotifyProc = {
InterpInput[self, input];
};
InterpAtom: PROC [viewer: ViewerClasses.Viewer, atom: ATOM, param: REF] = {
closureList: LIST OF CommandClosure ~ NARROW[RefTab.Fetch[commandTable,atom].val];
IF traceProcs#NIL THEN traceProcs.TraceAtom[viewer, atom, param, closureList];
IF closureList=NIL
THEN MessageWindow.Append[Rope.Concat["Unknown atom given to Tioga: ", Atom.GetPName[atom]], TRUE]
ELSE {
recordAtom: BOOL ¬ FALSE;
TEditInputOps.WaitForInsertToFinish[]; -- make sure previous characters have gone in
FOR list: LIST OF CommandClosure ¬ closureList, list.rest UNTIL list=NIL DO
record, quit: BOOL;
[record, quit] ¬ list.first.proc[list.first.data, viewer, param];
IF record THEN recordAtom ¬ TRUE;
IF quit THEN EXIT;
ENDLOOP;
IF recordAtom THEN RecordRef[atom]
}
};
ResetInputStuff: PUBLIC PROC = { changeLevel ¬ same };
SaveCoords: PUBLIC PROC [x, y: INTEGER] = { mx ¬ x; my ¬ y };
interpreterNesting: PUBLIC INTEGER ¬ 0;
InterpInput: PUBLIC PROC [viewer: ViewerClasses.Viewer, params: LIST OF REF ANY, increaseNestingCount: BOOL ¬ TRUE] = {
NormaliseSelection: PROC = INLINE --gfi saver-- {
IF NOT TEditSelection.pSel.pendingDelete THEN RETURN;
TEditSelection.LockSel[primary, "InterpInput"];
{ ENABLE UNWIND => TEditSelection.UnlockSel[primary];
IF TEditSelection.pSel.pendingDelete THEN TEditInputOps.DoPendingDelete[];
IF NOT InsSel[] THEN TEditSelection.MakePointSelection[TEditSelection.pSel, TEditSelection.InsertionPoint[]];
}; TEditSelection.UnlockSel[primary];
};
InsSel: PROC RETURNS [BOOL] = INLINE --gfi saver-- { RETURN[TEditSelection.pSel.granularity=point AND TEditSelection.pSel.insertion=before
AND TEditSelection.sSel.viewer=NIL]
};
BumpNesting: ENTRY PROC = INLINE --gfi saver-- {
IF (interpreterNesting ¬ interpreterNesting+1) <= 1 THEN {
interpreterNesting ¬ 1;
closeEvent ¬ FALSE
}
};
DecrementNesting: ENTRY PROC RETURNS [BOOL] = INLINE --gfi saver-- {
RETURN [(interpreterNesting ¬ interpreterNesting-1) <= 0]
};
AllText: PROC [LIST OF REF ANY] RETURNS [BOOL] = INLINE --gfi saver-- {
FOR input: LIST OF REF ANY ¬ params, input.rest UNTIL input=NIL DO
WITH input.first SELECT FROM
z: REF CHAR => NULL;
z: ROPE => NULL;
z: REF TEXT => NULL;
ENDCASE => RETURN [FALSE];
ENDLOOP;
RETURN [TRUE]
};
IF traceProcs#NIL THEN traceProcs.TraceInput[viewer, params, increaseNestingCount];
ResetInputStuff[];
IF interpreterNesting=0 AND NOT TEditSelection.pSel.pendingDelete AND AllText[params]
THEN {
hand it off to buffered input routines
FOR input: LIST OF REF ANY ¬ params, input.rest UNTIL input=NIL DO
NormaliseSelection[];
WITH input.first SELECT FROM
z: REF CHAR => {
TEditInputOps.BufferedInsertChar[z­]; RecordChar[z­]
};
z: ROPE => {
TEditInputOps.BufferedInsertText[z]; RecordRef[z]
};
z: REF TEXT => {
TEditInputOps.BufferedInsertText[Rope.FromRefText[z]]; RecordRef[z]
};
ENDCASE => ERROR;
ENDLOOP;
}
ELSE {
param: REF ¬ NIL;
paramIsNext: BOOL ¬ FALSE;
IF increaseNestingCount THEN BumpNesting[];
FOR input: LIST OF REF ANY ¬ params, input.rest UNTIL input=NIL DO
thisIsParam: BOOL = paramIsNext;
IF thisIsParam THEN param ¬ NIL;
paramIsNext ¬ FALSE;
WITH input.first SELECT FROM
z: ATOM => {
IF thisIsParam
THEN { param ¬ z; RecordRef[z] }
ELSE {
IF z = $PARAM THEN { paramIsNext ¬ TRUE };
InterpAtom[viewer, z, param ! BadMouse, DontDoIt => EXIT];
};
};
z: TIPUser.TIPScreenCoords => {
IF thisIsParam
THEN RecordRef[param ¬ NEW[TIPUser.TIPScreenCoordsRec ¬ z­] ]
ELSE SaveCoords[z.mouseX, viewer.ch-z.mouseY];
};
z: REF CHAR => {
IF thisIsParam
THEN RecordRef[param ¬ NEW[CHAR ¬ z­]]
ELSE { TEditInputOps.InsertChar[z­]; RecordChar[z­] };
};
z: REF INT => {
param ¬ NEW[INT ¬ z­]; -- is the copy needed?
RecordRef[param]
};
z: ROPE => {
IF thisIsParam THEN param ¬ z ELSE TEditInputOps.InsertRope[z];
RecordRef[z]
};
z: REF TEXT => {
rope: ROPE ~ Rope.FromRefText[z];
IF thisIsParam THEN param ¬ rope ELSE TEditInputOps.InsertRope[rope];
RecordRef[rope];
};
ENDCASE => MessageWindow.Append["Unknown input given to Tioga.", TRUE];
IF thisIsParam AND param=NIL THEN MessageWindow.Append["Illegal PARAM input given to Tioga.", TRUE];
ENDLOOP;
IF increaseNestingCount AND DecrementNesting[] AND closeEvent THEN CloseEventNow[];
};
};
NumberToLook: PROC [n: INT] RETURNS [l: CHAR] = {
maps global value in n to => ['a..'z];
RETURN['a+n];
};
Public Command Procs
Normalize: PUBLIC CommandProc = {
DoIt: PROC [tdd: TEditDocument.TEditDocumentData, tSel: TEditDocument.Selection] = {
NormalizeViewer[viewer,
IF tSel.viewer=NIL THEN [NIL,0] ELSE TEditSelection.InsertionPoint[tSel], tdd, tSel]
};
TEditSelection.CallWithSelAndDocAndTddLocks[viewer, primary, DoIt]
};
savedSelA: TEditDocument.Selection ¬ TEditSelection.Create[];
savedSelB: TEditDocument.Selection ¬ TEditSelection.Create[];
RestoreSelectionA: PUBLIC CommandProc = {
IF CheckSelection[savedSelA] THEN TEditSelection.MakeSelection[selection: primary, new: savedSelA]
};
SaveSelectionA: PUBLIC CommandProc = {
IF TEditSelection.pSel # NIL THEN TEditSelection.Copy[source: TEditSelection.pSel, dest: savedSelA]
};
RestoreSelectionB: PUBLIC CommandProc = {
IF CheckSelection[savedSelB] THEN TEditSelection.MakeSelection[selection: primary, new: savedSelB]
};
SaveSelectionB: PUBLIC CommandProc = {
IF TEditSelection.pSel # NIL THEN TEditSelection.Copy[source: TEditSelection.pSel, dest: savedSelB]
};
AllLevels: PUBLIC CommandProc = {
WITH viewer.data SELECT FROM
tdd: TEditDocument.TEditDocumentData => {
IF tdd.clipLevel # TEditDocument.maxClip THEN {
[] ¬ TEditDocument.SpinAndLock[tdd, "AllLevels", TRUE];
tdd.clipLevel ¬ TEditDocument.maxClip;
ForkPaint[viewer];
TEditDocument.Unlock[tdd];
};
};
ENDCASE;
RETURN [FALSE];
};
FirstLevelOnly: PUBLIC CommandProc = {
WITH viewer.data SELECT FROM
tdd: TEditDocument.TEditDocumentData => {
IF tdd.clipLevel # 1 THEN {
[] ¬ TEditDocument.SpinAndLock[tdd, "FirstLevelOnly", TRUE];
tdd.clipLevel ¬ 1;
CheckFirstLevel[tdd];
ForkPaint[viewer];
TEditDocument.Unlock[tdd];
};
};
ENDCASE;
RETURN [FALSE];
};
MoreLevels: PUBLIC CommandProc = {
WITH viewer.data SELECT FROM
tdd: TEditDocument.TEditDocumentData => {
IF tdd.clipLevel < TEditDocument.maxClip THEN {
ENABLE UNWIND => TEditTouchup.UnlockAfterRefresh[tdd];
[] ¬ TEditDocument.SpinAndLock[tdd, "MoreLevels", TRUE];
tdd.clipLevel ¬ MaxLevelShown[tdd]+1;
ForkPaint[viewer];
TEditDocument.Unlock[tdd];
};
};
ENDCASE;
};
FewerLevels: PUBLIC CommandProc = {
WITH viewer.data SELECT FROM
tdd: TEditDocument.TEditDocumentData =>
IF tdd.clipLevel # 1 THEN {
IF TEditTouchup.LockAfterRefresh[tdd, "FewerLevels"] THEN {
ENABLE UNWIND => TEditTouchup.UnlockAfterRefresh[tdd];
level: INTEGER ¬ tdd.clipLevel;
IF level = TEditDocument.maxClip THEN level ¬ MaxLevelShown[tdd];
IF level # 1 THEN {
tdd.clipLevel ¬ level-1;
CheckFirstLevel[tdd];
ForkPaint[viewer];
};
TEditTouchup.UnlockAfterRefresh[tdd];
};
};
ENDCASE;
RETURN [FALSE];
};
DoEdit: CommandProc = {
SELECT TRUE FROM
(TEditSelection.pSel.viewer = NIL) => {
IF TEditSelection.sSel.viewer # NIL THEN TEditSelection.MakeSelection[NIL, secondary]; -- get rid of secondary
recordAtom ¬ FALSE
};
(editState = tolimbo) => {
recordAtom ¬ FALSE; RecordRef[$Delete]; TEditInputOps.Delete[TRUE];
};
(TEditSelection.sSel.viewer = NIL) => {recordAtom ¬ FALSE};
ENDCASE => {
RecordEditObject: PROC = INLINE --gfi saver-- {
RecordRef[SELECT editObject FROM text => $EditText, looks => $EditLooks, format => $EditFormat, ENDCASE => ERROR];
};
recordAtom ¬ TRUE;
SELECT editState FROM
reset, abort => recordAtom ¬ FALSE;
toprimary => {
RecordRef[$GetSecondary];
RecordRef[$ToPrimary];
RecordEditObject[];
SELECT editObject FROM
text => {
IF TEditSelection.pSel.pendingDelete THEN RecordRef[$MakePDel];
TEditInputOps.Copy[primary]
};
looks => TEditInputOps.CopyLooks[primary];
format => TEditInputOps.CopyFormat[primary];
ENDCASE => ERROR
};
tosecondary => {
RecordRef[$GetSecondary];
RecordRef[$ToSecondary];
RecordEditObject[];
SELECT editObject FROM
text => {
IF TEditSelection.pSel.pendingDelete THEN RecordRef[$MakePDel];
TEditInputOps.Copy[secondary]
};
looks => TEditInputOps.CopyLooks[secondary];
format => TEditInputOps.CopyFormat[secondary];
ENDCASE => ERROR
};
toboth => {
RecordRef[$GetSecondary];
RecordRef[$ToBoth];
RecordEditObject[];
SELECT editObject FROM
text => TEditInputOps.Transpose[];
looks => TEditInputOps.TransposeLooks[];
format => TEditInputOps.TransposeFormat[];
ENDCASE => ERROR
};
ENDCASE => ERROR
};
editState ¬ reset; editObject ¬ text;
pdelState ¬ reset; pDel ¬ FALSE; selState ¬ reset; sel ¬ primary;
mouseColor ¬ red; -- put these back to normal
IF editMessage # NIL THEN MessageWindow.Clear[];
editMessage ¬ NIL
};
MakePointSelection: PUBLIC CommandProc = {
TEditSelection.LockSel[primary, "MakePointSelection"];
IF TEditSelection.pSel.viewer#NIL THEN
TEditSelection.MakePointSelection[TEditSelection.pSel,
IF TEditSelection.pSel.insertion=before THEN TEditSelection.pSel.start.pos
ELSE [TEditSelection.pSel.end.pos.node, TEditSelection.pSel.end.pos.where+1]];
TEditSelection.UnlockSel[primary];
};
Support for Internal Commands
Split: PUBLIC PROC [old: ViewerClasses.Viewer] = { -- Export to TEditSplit
tddNew, tddOld: TEditDocument.TEditDocumentData;
new: ViewerClasses.Viewer;
paintCaption: BOOL ¬ FALSE;
selectionHistory: TEditDocument.Selection;
lines: TEditDocument.LineTable;
loc: TextNode.Location;
tddOld ¬ NARROW[old.data];
IF tddOld = NIL THEN RETURN;
new ¬ ViewerOps.CreateViewer[flavor: old.class.flavor, info: [name: old.name,
column: old.column, iconic: TRUE], paint: FALSE];
ViewerOps.OpenIcon[icon: new, paint: FALSE];
ViewerOps.MoveBelowViewer[altered: new, static: old, paint: FALSE];
tddNew ¬ NARROW[new.data];
IF tddNew = NIL THEN RETURN; -- How this could happen is beyond me, but paranoia is cheap. [McGregor]
selectionHistory ¬ NARROW[ViewerOps.FetchProp[old, $SelectionHistory]];
new.link ¬ old;
IF old.link=NIL
THEN { old.link ¬ new; paintCaption ¬ TRUE }
ELSE FOR v: ViewerClasses.Viewer ¬ old.link, v.link UNTIL v.link=old DO
REPEAT FINISHED => v.link ¬ new;
ENDLOOP;
new.newVersion ¬ old.newVersion;
new.newFile ¬ old.newFile;
new.file ¬ old.file;
ViewerOps.ComputeColumn[column: new.column, paint: FALSE]; -- to find new height
{
inner: PROC = {
[] ¬ TEditDocument.SpinAndLock[tddOld, "Split"]; -- must ComputeColumn before lock tdd
tddNew.text ¬ tddOld.text;
tddNew.tsInfo ¬ tddOld.tsInfo;
tddNew.clipLevel ¬ tddOld.clipLevel;
tddNew.commentFilter ¬ tddOld.commentFilter;
ViewerOps.SetMenu[new, old.menu, FALSE];
IF selectionHistory # NIL THEN { -- copy it
newSelectionHistory: TEditDocument.Selection ¬ NEW[TEditDocument.SelectionRec];
newSelectionHistory­ ¬ selectionHistory­;
ViewerOps.AddProp[new, $SelectionHistory, newSelectionHistory];
};
TEditOps.CopyPositionHistory[from: old, to: new];
TEditOps.CopyLoadHistory[from: old, to: new];
lines ¬ tddOld.lineTable;
loc ¬ lines[lines.lastLine].pos; -- in case loop doesn't find anything
FOR n: INTEGER IN [0..lines.lastLine] DO -- find line that goes past new bottom
IF lines[n].yOffset+lines[n].descent >= old.ch THEN {
loc ¬ lines[n].pos; EXIT };
ENDLOOP;
TEditDocument.Unlock[tddOld];
};
ViewerLocks.CallUnderWriteLocks[inner, old, new];
Must lock the viewers BEFORE trying for the document lock
};
TEditDisplay.EstablishLine[tddNew, loc];
ViewerOps.ComputeColumn[column: new.column, paint: TRUE]; -- now do the painting
FOR v: ViewerClasses.Viewer ¬ new.link, v.link WHILE v # NIL DO
IF v = new THEN EXIT;
IF v.iconic THEN { -- get rid of it -- ViewerOps.DestroyViewer[v]; EXIT };
IF paintCaption THEN
turn on [Split]
ViewerForkers.ForkPaint[viewer: v, hint: caption, tryShortCuts: TRUE];
ENDLOOP;
};
UpdateSavedSelections: PROC [
node: TextNode.RefTextNode,
new: PROC [old: TextNode.Offset] RETURNS [TextNode.Offset]] = {
Check: PROC [loc: TextNode.Location] RETURNS [TextNode.Location] = INLINE --gfi saver-- {
IF loc.node # node THEN RETURN [loc];
RETURN [[loc.node, new[loc.where]]]
};
oldSel is saved version of sSel for use in Repeat
TEditSelection.oldSel.start.pos ¬ Check[TEditSelection.oldSel.start.pos];
TEditSelection.oldSel.end.pos ¬ Check[TEditSelection.oldSel.end.pos];
savedSelA is saved by SaveSelectionA and restored by RestoreSelectionA
savedSelA.start.pos ¬ Check[savedSelA.start.pos];
savedSelA.end.pos ¬ Check[savedSelA.end.pos];
savedSelB is saved by SaveSelectionB and restored by RestoreSelectionB
savedSelB.start.pos ¬ Check[savedSelB.start.pos];
savedSelB.end.pos ¬ Check[savedSelB.end.pos];
fSel is saved feedback selection
TEditSelection.fSel.start.pos ¬ Check[TEditSelection.fSel.start.pos];
TEditSelection.fSel.end.pos ¬ Check[TEditSelection.fSel.end.pos];
};
CheckSelection: PUBLIC PROC [sel: TEditDocument.Selection] RETURNS [BOOL] = {
root, first, last: TextNode.Ref;
t1, t2: TextNode.RefTextNode;
tdd: TEditDocument.TEditDocumentData;
IF sel=NIL THEN RETURN [FALSE];
IF sel.viewer=NIL OR sel.viewer.destroyed THEN GOTO Failed;
IF (first ¬ sel.start.pos.node)=NIL OR (last ¬ sel.end.pos.node)=NIL THEN GOTO Failed;
IF (tdd ¬ NARROW[sel.viewer.data])=NIL THEN GOTO Failed;
IF (root ¬ tdd.text)=NIL THEN GOTO Failed;
IF TextNode.Root[first] # root THEN GOTO Failed; -- make sure still in the tree
IF first # last THEN {
make sure nodes in same tree and right order
IF EditSpan.CompareNodeOrder[first,last] # before THEN GOTO Failed;
};
IF sel.start.pos.where # TextNode.NodeItself THEN {
make sure start index is ok
IF (t1 ¬ first)=NIL OR sel.start.pos.where NOT IN [0..TextEdit.Size[t1]] THEN GOTO Failed;
};
IF sel.end.pos.where # TextNode.NodeItself THEN {
make sure end index is ok
IF (t2 ¬ last)=NIL OR sel.end.pos.where NOT IN [0..TextEdit.Size[t2]] THEN GOTO Failed;
};
IF t1 # NIL AND t1 = t2 THEN {
make sure start is not after end
IF sel.start.pos.where > sel.end.pos.where THEN GOTO Failed;
};
RETURN [TRUE];
EXITS Failed => { sel.viewer ¬ NIL; RETURN [FALSE] };
};
NormalizeViewer: PROC [viewer: ViewerClasses.Viewer, loc: TextNode.Location, tdd: TEditDocument.TEditDocumentData, tSel: TEditDocument.Selection] = {
IF loc.node = NIL OR tdd.text # TextNode.Root[loc.node] THEN {
scroll to start of document
loc ¬ [TextNode.FirstChild[tdd.text],0];
};
TEditOps.RememberCurrentPosition[viewer];
TEditScrolling.ScrollToPosition[viewer, loc]
};
BadMouse: PUBLIC SIGNAL = CODE;
AbortSecondary: PROC = {
MessageWindow.Append["Make a primary selection first.",TRUE];
MessageWindow.Blink[];
editState ¬ abort; mouseColor ¬ dead
};
Extend: PROC [viewer: ViewerClasses.Viewer, saveEnds: BOOL] = {
tdd: TEditDocument.TEditDocumentData ~ NARROW[viewer.data];
IF tdd = NIL THEN RETURN;
interpreterNesting ¬ 0;
IF editState=abort THEN RETURN;
IF mouseColor # blue THEN {
IF mouseColor = dead THEN SIGNAL BadMouse;
mouseColor ¬ blue;
TEditSelection.Copy[source: TEditSelection.pSel, dest: prevPSel];
saveEnds ¬ TRUE;
};
TEditSelection.Extend[viewer,tdd,mx,my,sel,pDel,changeLevel,saveEnds];
IF sel=secondary THEN EditMessage[]
ELSE IF sel=primary THEN CloseEvent[]
};
DontDoIt: PUBLIC SIGNAL = CODE; -- raised if user category is too low
CheckUser: PROC [category: TEditProfile.CategoryOfUser] = INLINE --gfi saver-- {
IF TEditProfile.userCategory < category THEN SIGNAL DontDoIt
};
ForkPaint: PROC [viewer: ViewerClasses.Viewer] = TRUSTED {
ViewerForkers.ForkPaint[viewer: viewer, hint: client, tryShortCuts: TRUE];
};
CheckFirstLevel: PROC [tdd: TEditDocument.TEditDocumentData] = {
node: TextNode.Ref;
delta: INTEGER;
pos: TextNode.Location;
[] ¬ TEditDocument.SpinAndLock[tdd, "CheckFirstLevel", TRUE]; -- ok to interrupt repaint
pos ¬ tdd.lineTable.lines[0].pos; -- the start of the first line
delta ¬ TextNode.Level[pos.node]-tdd.clipLevel; -- how much too deep it is, if any
IF delta > 0 THEN {
FOR i:INTEGER IN [0..delta) DO -- only do this if pos is too deep
pos ¬ [TextNode.Parent[pos.node],0];
ENDLOOP;
IF (node ¬ TextNode.ForwardClipped[pos.node,0].nx) # NIL THEN pos ¬ [node,0];
TEditDisplay.EstablishLine[tdd, pos] };
TEditDocument.Unlock[tdd];
};
MaxLevelShown: PUBLIC PROC [tdd: TEditDocument.TEditDocumentData] RETURNS [level: INTEGER] = {
node, n: TextNode.Ref;
max: INTEGER ¬ 0;
IF tdd = NIL THEN RETURN [0];
FOR l: INTEGER IN [0..tdd.lineTable.lastLine] DO
IF (n ¬ tdd.lineTable.lines[l].pos.node) # node THEN {
node ¬ n;
max ¬ MAX[TextNode.Level[node], max] };
ENDLOOP;
level ¬ max;
};
ReadTipTables: PUBLIC PROC = {
WindowManager.WaitCursor[];
TEditPrivate.ReloadTipTable[];
TEditPrivate.ReloadReadonlyTipTable[];
TEditPrivate.ReloadTypeScriptTipTable[];
InputFocus.SetInputFocus[]; -- kill selection; force ChangeTIPContext
WindowManager.UnWaitCursor[];
};
ComArray: TYPE = ARRAY ComIndex OF LIST OF REF ANY;
coms: REF ComArray = NEW [ComArray];
SetCommand: PUBLIC PROC [num: ComIndex, params: LIST OF REF ANY] = {
coms[num] ¬ params;
};
GetCommand: PUBLIC PROC [num: ComIndex] RETURNS [params: LIST OF REF ANY] = {
RETURN [coms[num]];
};
DoCommand: PROC [viewer: ViewerClasses.Viewer, num: ComIndex] = {
Interpret[viewer,coms[num]];
};
Internal Commands
InternalID: TYPE ~ TEditInputPrivate.InternalID;
RegisterInternal: PROC [name: ATOM, id: InternalID] ~ {
RegisterClosure[[name: name, proc: DispatchInternalCommand, data: NEW[InternalID ¬ id]]];
};
CopyToWorld: PROC [delete: BOOL ¬ FALSE] ~ {
vWorld: ViewersWorld.Ref ~ ViewersWorldInstance.GetWorld[];
rope: Rope.ROPE ¬ NIL;
DoSelChars: PROC [root: TextNode.RefTextNode, tSel: TEditDocument.Selection] = {
SelConcat: PROC [node: TextNode.RefTextNode, start, len: TextNode.Offset] RETURNS [stop: BOOL] = {
rope ¬ IF rope = NIL
THEN Rope.Substr[node.rope, start, len]
ELSE Rope.Cat[rope, "\n", Rope.Substr[node.rope, start, len]];
RETURN [FALSE];
};
IF tSel.viewer # NIL AND tSel.granularity # point THEN
EditSpanSupport.Apply[[tSel.start.pos, tSel.end.pos], SelConcat];
IF rope=NIL THEN rope ¬ "";
};
TEditInputOps.CallWithLocks[DoSelChars, read];
ViewersWorld.SetCutBuffer[vWorld, $Ascii, rope];
IF delete THEN TEditInputOps.Delete[saveForPaste: FALSE];
};
PasteFromWorld: PROC [] ~ {
vWorld: ViewersWorld.Ref ~ ViewersWorldInstance.GetWorld[];
rope: Rope.ROPE ~ ViewersWorld.GetCutBuffer[vWorld, $Ascii];
TEditInputOps.InsertRope[rope];
};
DispatchInternalCommand: PUBLIC CommandClosureProc ~ {
n: INT ~ WITH param SELECT FROM n: REF INT => n­ ENDCASE => 1;
WITH data SELECT FROM
refID: REF InternalID => {
id: InternalID ~ refID­;
internalCommandCounts[id] ¬ internalCommandCounts[id]+1;
SELECT id FROM
CopyToWorld => CopyToWorld[delete: FALSE];
CutToWorld => CopyToWorld[delete: TRUE];
PasteFromWorld => PasteFromWorld[];
CutToWorldFormatted => {
};
CopyToWorldFormatted => {
};
PasteFromWorldFormatted => {
};
ApplyCaretLook => {
TEditInputOps.ModifyCaretLook[NumberToLook[n], add]
};
ApplyLook => {
TEditInputOps.ModifyLook[NumberToLook[n], add]
};
ClearCaretLooks => {
TEditInputOps.ChangeCaretLooks[add: TextLooks.noLooks, remove: TextLooks.allLooks]
};
ClearLooks => {
TEditInputOps.ChangeLooks[add: TextLooks.noLooks, remove: TextLooks.allLooks]
};
BackSpace => { TEditInputOps.BackSpace[n] };
BackWord => { TEditInputOps.BackWord[n] };
DeleteNextChar => { TEditInputOps.DeleteNextChar[n] };
DeleteNextWord => { TEditInputOps.DeleteNextWord[n] };
GoToPreviousWord => { TEditInputOps.GoToPreviousWord[n] };
GoToNextWord => { TEditInputOps.GoToNextWord[n] };
GoToPreviousChar => { TEditInputOps.GoToPreviousChar[n] };
GoToNextChar => { TEditInputOps.GoToNextChar[n] };
GoToPreviousNode => { TEditInputOps.GoToPreviousNode[n] };
GoToNextNode => { TEditInputOps.GoToNextNode[n] };
GoToEndOfNode => { TEditSelectionOpsExtras.GoToEndOfNode[n] };
GoToBeginningOfNode => { TEditSelectionOpsExtras.GoToEndOfNode[-n] };
Copy => {
IF TEditSelection.sSel.viewer#NIL THEN {
TEditInputOps.Copy[sel];
RecordRef[$GetSecondary]
};
};
Delete => { TEditInputOps.Delete[saveForPaste: TRUE] };
ExpandAbbrev => { TEditInputOps.ExpandAbbreviation[] };
Move => {
IF TEditSelection.sSel.viewer#NIL THEN {
TEditInputOps.Move[sel];
RecordRef[$GetSecondary];
};
};
RemoveCaretLook => {
TEditInputOps.ModifyCaretLook[NumberToLook[n], remove];
};
RemoveLook => {
TEditInputOps.ModifyLook[NumberToLook[n], remove];
};
SetStyle => { TEditInputOps.SetStyle[] };
Time => { TEditInputOps.InsertTime[] };
RedSplit, YellowSplit, BlueSplit => { Split[viewer]; RETURN[FALSE] };
Transpose => {
IF TEditSelection.sSel.viewer#NIL THEN {
TEditInputOps.Transpose[sel];
RecordRef[$GetSecondary]
};
};
ToBoth => {
IF editState=reset OR editState=tolimbo THEN { editState ¬ toboth; EditMessage[] };
RETURN [FALSE]
};
ToLimbo => { IF editState=reset THEN editState ¬ tolimbo; RETURN [FALSE] };
ToPrimary => {
IF editState=reset OR editState=tolimbo THEN editState ¬ toprimary;
RETURN [FALSE]
};
ToSecondary => {
IF editState=reset OR editState=tolimbo THEN { editState ¬ tosecondary; EditMessage[] };
RETURN [FALSE]
};
EditText => { editObject ¬ text; RETURN [FALSE] };
EditLooks => { editObject ¬ looks; EditMessage[]; RETURN [FALSE] };
EditFormat => { editObject ¬ format; EditMessage[]; RETURN [FALSE] };
EditReset => {
editState ¬ reset; editObject ¬ text; selState ¬ reset; pdelState ¬ reset; RETURN [FALSE]
};
EditAbort => {
interrupt­ ¬ TRUE;
IF viewer#NIL AND TEditSelection.pSel.viewer=viewer AND TEditSelection.pSel.granularity=point
AND TEditSelection.sSel.viewer=NIL THEN
ViewerOps.AddProp[viewer, $Abort, NEW[BOOL ¬ FALSE]];
MessageWindow.Append["Cancelled",TRUE];
TEditSelection.MakeSelection[NIL,secondary];
TEditSelection.MakeSelection[IF CheckSelection[prevPSel] THEN prevPSel ELSE NIL, primary];
editState ¬ abort; editObject ¬ text;
mouseColor ¬ dead; -- stop tracking the mouse
RETURN [FALSE]
};
GetSecondary => {
IF TEditSelection.sSel.viewer=NIL AND CheckSelection[TEditSelection.oldSel] THEN TEditSelection.FakeSecondary[TEditSelection.oldSel];
RETURN [FALSE]
};
MakePDel => {
TEditSelection.pSel.pendingDelete ¬ TRUE; RETURN [FALSE]
};
NormalizeToStart => {
DoIt: PROC [tdd: TEditDocument.TEditDocumentData, tSel: TEditDocument.Selection] = {
NormalizeViewer[viewer, IF tSel.viewer=NIL THEN [NIL,0] ELSE tSel.start.pos, tdd, tSel]
};
TEditSelection.CallWithSelAndDocAndTddLocks[viewer, primary, DoIt]
};
NormalizeToEnd => {
DoIt: PROC [tdd: TEditDocument.TEditDocumentData, tSel: TEditDocument.Selection] = {
NormalizeViewer[viewer, IF tSel.viewer=NIL THEN [NIL,0] ELSE tSel.end.pos, tdd, tSel]
};
TEditSelection.CallWithSelAndDocAndTddLocks[viewer, primary, DoIt]
};
FindNext => {
TEditSelection.Find[viewer: viewer, findWhere: forwards];
CloseEvent[]; RETURN [FALSE]
};
FindAny => {
TEditSelection.Find[viewer: viewer, findWhere: anywhere];
CloseEvent[]; RETURN [FALSE]
};
FindPrev => {
TEditSelection.Find[viewer: viewer, findWhere: backwards];
CloseEvent[]; RETURN [FALSE]
};
FindNextWord => {
TEditSelection.Find[viewer: viewer, findWhere: forwards, def: FALSE, word: TRUE];
CloseEvent[]; RETURN [FALSE]
};
FindAnyWord => {
TEditSelection.Find[viewer: viewer, findWhere: anywhere, def: FALSE, word: TRUE];
CloseEvent[]; RETURN [FALSE]
};
FindPrevWord => {
TEditSelection.Find[viewer: viewer, findWhere: backwards, def: FALSE, word: TRUE];
CloseEvent[]; RETURN [FALSE]
};
FindNextDef => {
TEditSelection.Find[viewer: viewer, findWhere: forwards, def: TRUE, word: TRUE];
CloseEvent[]; RETURN [FALSE]
};
FindAnyDef => {
TEditSelection.Find[viewer: viewer, findWhere: anywhere, def: TRUE, word: TRUE];
CloseEvent[]; RETURN [FALSE]
};
FindPrevDef => {
TEditSelection.Find[viewer: viewer, findWhere: backwards, def: TRUE, word: TRUE];
CloseEvent[]; RETURN [FALSE]
};
FindNextCaseless => {
TEditSelection.Find[viewer: viewer, findWhere: forwards, case: FALSE];
CloseEvent[]; RETURN [FALSE]
};
FindAnyCaseless => {
TEditSelection.Find[viewer: viewer, findWhere: anywhere, case: FALSE];
CloseEvent[]; RETURN [FALSE]
};
FindPrevCaseless => {
TEditSelection.Find[viewer: viewer, findWhere: backwards, case: FALSE];
CloseEvent[]; RETURN [FALSE]
};
FindNextWordCaseless => {
TEditSelection.Find[viewer: viewer, findWhere: forwards, def: FALSE, word: TRUE, case: FALSE];
CloseEvent[]; RETURN [FALSE]
};
FindAnyWordCaseless => {
TEditSelection.Find[viewer: viewer, findWhere: anywhere, def: FALSE, word: TRUE, case: FALSE];
CloseEvent[]; RETURN [FALSE]
};
FindPrevWordCaseless => {
TEditSelection.Find[viewer: viewer, findWhere: backwards, def: FALSE, word: TRUE, case: FALSE];
CloseEvent[]; RETURN [FALSE]
};
FindNextDefCaseless => {
TEditSelection.Find[viewer: viewer, findWhere: forwards, def: TRUE, word: TRUE, case: FALSE];
CloseEvent[]; RETURN [FALSE]
};
FindAnyDefCaseless => {
TEditSelection.Find[viewer: viewer, findWhere: anywhere, def: TRUE, word: TRUE, case: FALSE];
CloseEvent[]; RETURN [FALSE]
};
FindPrevDefCaseless => {
TEditSelection.Find[viewer: viewer, findWhere: backwards, def: TRUE, word: TRUE, case: FALSE];
CloseEvent[]; RETURN [FALSE]
};
Position => {
CloseEvent[];
TEditSelection.ShowPosition[viewer: viewer, skipCommentNodes: TRUE];
RETURN[FALSE]
};
PositionIncludingComments => {
CloseEvent[];
TEditSelection.ShowPosition[viewer: viewer, skipCommentNodes: FALSE];
RETURN[FALSE]
};
MsgPosition => {
positionMessage ¬ TEditSelectionOpsExtras.CurrentPositionMessage[viewer, TRUE];
MessageWindow.Append[Rope.Concat["Current position is ", positionMessage], TRUE];
};
MsgPositionIncludingComments => {
positionMessage ¬ TEditSelectionOpsExtras.CurrentPositionMessage[viewer, FALSE];
MessageWindow.Append[Rope.Concat["Current position is ", positionMessage], TRUE];
};
StuffPosition => {
TEditInputOps.InsertRope[positionMessage];
};
RedMouse => {
IF mouseColor = dead THEN SIGNAL BadMouse;
mouseColor ¬ red;
TEditSelection.Copy[source: TEditSelection.pSel, dest: prevPSel];
RETURN [FALSE]
};
YellowMouse => {
IF mouseColor = dead THEN SIGNAL BadMouse;
mouseColor ¬ yellow;
TEditSelection.Copy[source: TEditSelection.pSel, dest: prevPSel];
RETURN [FALSE]
};
BlueMouse => {
IF mouseColor = dead THEN SIGNAL BadMouse;
mouseColor ¬ blue;
TEditSelection.Copy[source: TEditSelection.pSel, dest: prevPSel];
RETURN [FALSE]
};
RedDown => {
IF mouseColor # red THEN SIGNAL BadMouse; RETURN [FALSE]
};
YellowDown => {
IF mouseColor # yellow THEN SIGNAL BadMouse; RETURN [FALSE]
};
BlueDown => {
IF mouseColor # blue THEN SIGNAL BadMouse; RETURN [FALSE]
};
SelBranch => {
tdd: TEditDocument.TEditDocumentData ~ NARROW[viewer.data];
IF tdd = NIL THEN RETURN;
interpreterNesting ¬ 0;
IF editState=abort THEN RETURN;
IF sel=secondary AND TEditSelection.pSel.viewer = NIL THEN { AbortSecondary[]; RETURN };
TEditSelection.SelectBranch[viewer, tdd, mx, my, sel, pDel];
IF editState=tolimbo OR sel=secondary THEN EditMessage[];
IF sel=primary THEN CloseEvent[];
RETURN [FALSE]
};
SelChar => {
tdd: TEditDocument.TEditDocumentData ~ NARROW[viewer.data];
IF tdd = NIL THEN RETURN;
interpreterNesting ¬ 0;
IF editState=abort THEN RETURN;
IF sel=secondary AND TEditSelection.pSel.viewer = NIL THEN { AbortSecondary[]; RETURN };
TEditSelection.SelectChar[viewer, tdd, mx, my, sel, pDel];
IF editState=tolimbo OR sel=secondary THEN EditMessage[];
IF sel=primary THEN CloseEvent[];
RETURN [FALSE]
};
SelExpand => {
changeLevel ¬ expand; IF sel=primary THEN CloseEvent[]; RETURN [FALSE]
};
SelExtend => { Extend[viewer, FALSE]; RETURN [FALSE] };
SelStartExtend => { Extend[viewer, TRUE]; RETURN [FALSE] };
SelNode => {
tdd: TEditDocument.TEditDocumentData ~ NARROW[viewer.data];
IF tdd = NIL THEN RETURN;
interpreterNesting ¬ 0;
IF editState=abort THEN RETURN;
IF sel=secondary AND TEditSelection.pSel.viewer = NIL THEN { AbortSecondary[]; RETURN };
TEditSelection.SelectNode[viewer, tdd, mx, my, sel, pDel];
IF editState=tolimbo OR sel=secondary THEN EditMessage[];
IF sel=primary THEN CloseEvent[];
RETURN [FALSE]
};
SelNotPendDel => {
IF pdelState=reset THEN {
pdelState ¬ not; pDel ¬ FALSE;
IF sel=primary THEN CloseEvent[]
};
RETURN [FALSE]
};
SelPendDel => {
IF pdelState=reset THEN {
pdelState ¬ pending; pDel ¬ TRUE;
IF sel=primary THEN CloseEvent[]
};
RETURN [FALSE]
};
ForceSelPendDel => { -- force pending delete
pdelState ¬ pending; pDel ¬ TRUE;
IF sel=primary THEN CloseEvent[];
RETURN [FALSE]
};
ForceSelNotPendDel => { -- force not pending delete
pdelState ¬ not; pDel ¬ FALSE;
IF sel=primary THEN CloseEvent[];
RETURN [FALSE]
};
SelSamePendDel => {
IF sel=primary THEN CloseEvent[]; RETURN [FALSE]
};
SelPrimary => {
IF selState=reset THEN { selState ¬ primary; sel ¬ primary; CloseEvent[] };
RETURN [FALSE]
};
SelReduce => {
changeLevel ¬ reduce; IF sel=primary THEN CloseEvent[]; RETURN [FALSE]
};
SelSame => { -- this is no longer needed. delete it after release new TIP tables
};
SelSameEnd => { -- get rid of this when change Tioga.Tip
RETURN [FALSE]
};
SelSecondary => {
IF selState=reset THEN { selState ¬ secondary; sel ¬ secondary };
RETURN [FALSE]
};
SelUpdate => {
tdd: TEditDocument.TEditDocumentData ~ NARROW[viewer.data];
IF tdd = NIL THEN RETURN;
IF editState=abort THEN RETURN;
IF sel=secondary AND TEditSelection.pSel.viewer = NIL THEN { AbortSecondary[]; RETURN };
TEditSelection.Update[viewer, tdd, mx, my, sel, pDel];
IF sel=secondary THEN EditMessage[];
IF sel=primary THEN CloseEvent[];
RETURN [FALSE]
};
SelWord => {
tdd: TEditDocument.TEditDocumentData ~ NARROW[viewer.data];
IF tdd = NIL THEN RETURN;
interpreterNesting ¬ 0;
IF editState=abort THEN RETURN;
IF sel=secondary AND TEditSelection.pSel.viewer = NIL THEN { AbortSecondary[]; RETURN };
TEditSelection.SelectWord[viewer, tdd, mx, my, sel, pDel];
IF editState=tolimbo OR sel=secondary THEN EditMessage[];
IF sel=primary THEN CloseEvent[];
RETURN [FALSE]
};
IntermediateUser => { CheckUser[intermediate]; RETURN [FALSE] };
AdvancedUser => { CheckUser[advanced]; RETURN [FALSE] };
ExpertUser => { CheckUser[expert]; RETURN [FALSE] };
Break => { TEditInputOps.Break[] };
Join => { TEditInputOps.Join[] };
Nest => { TEditInputOps.Nest[] };
Paste => { TEditInputOps.Paste[] };
SaveForPaste => { TEditInputOps.SaveForPaste[] };
SetFormat => { TEditInputOps.SetFormat[] };
GetFormat => { TEditInputOps.GetFormat[] };
UnNest => { TEditInputOps.UnNest[] };
AllCaps => { TEditInputOps.Capitalise[allCaps] };
AllLower => { TEditInputOps.Capitalise[allLower] };
FirstCap => { TEditInputOps.Capitalise[firstCap] };
InitialCaps => { TEditInputOps.Capitalise[initCaps] };
CaretAfter => { TEditSelection.CaretAfterSelection[] };
CaretBefore => { TEditSelection.CaretBeforeSelection[] };
Everything => { TEditSelection.SelectEverything[] };
GrowSel => { TEditSelection.GrowSelection[] };
GrowSelToBlanks => { TEditSelection.GrowSelectionToBlanks[] };
InsertLineBreak => { TEditInputOps.InsertLineBreak[] };
InsertNewline => {
tdd: TEditDocument.TEditDocumentData ~ NARROW[viewer.data];
IF tdd = NIL THEN RETURN;
TEditInputOps.InsertRope[TextEdit.GetNewlineDelimiter[tdd.text]]
};
MakeNotPendingDelete => { TEditSelection.NotPendingDeleteSelection[] };
MakePendingDelete => { TEditSelection.PendingDeleteSelection[] };
MakeControlCharacter => { TEditInputOps.MakeControlCharacter[] };
MakeOctalCharacter => { TEditInputOps.MakeOctalCharacter[] };
UnMakeControlCharacter => { TEditInputOps.UnMakeControlCharacter[] };
UnMakeOctalCharacter => { TEditInputOps.UnMakeOctalCharacter[] };
MakePrimaryOp => { TEditSelection.MakePrimary[] };
MakeSecondaryOp => { TEditSelection.MakeSecondary[] };
CancelPrimaryOp => { TEditSelection.CancelPrimary[] };
CancelSecondaryOp => { TEditSelection.CancelSecondary[] };
Paint => { ForkPaint[viewer] };
PlaceholderBrackets => { TEditInputOps.InsertBrackets[1C,2C] };
ReadTip => { ReadTipTables[] };
ReloadStyle => { TEditInputOps.ReloadStyle[] };
SelectMatchingPlaceholderBrackets => {
TEditInputOps.SelectMatchingBrackets[1C,2C];
};
SelectMatchingSingleQuotes => {
look for 140C as left single quote
TEditInputOps.SelectMatchingBrackets['\140,''];
};
SelectMatchingDoubleQuotes => { TEditInputOps.SelectMatchingBrackets['",'"] };
SelectMatchingDashBrackets => { TEditInputOps.SelectMatchingBrackets['-,'-] };
PreviousPlaceholder => { TEditInputOps.FindPlaceholders[FALSE] };
PreviousViewer => { TEditInputOps.NextViewer[FALSE] };
NextPlaceholder => { TEditInputOps.FindPlaceholders[TRUE] };
NextViewer => { TEditInputOps.NextViewer[TRUE] };
ReadAbbreviations => { TEditInputOps.LoadAbbreviations["Default"] };
VerifyTree => {
IF pSel.viewer=NIL THEN RETURN;
TreeCheck.Verify[TextNode.Root[pSel.start.pos.node]];
MessageWindow.Append["Verified", TRUE];
MessageWindow.Blink[];
};
SelectMatchingParens => { TEditInputOps.SelectMatchingBrackets['(,')] };
SelectMatchingAngleBrackets => { TEditInputOps.SelectMatchingBrackets['<,'>] };
SelectMatchingCurlyBrackets => { TEditInputOps.SelectMatchingBrackets['{,'}] };
SelectMatchingSquareBrackets => { TEditInputOps.SelectMatchingBrackets['[,']] };
ParenBrackets => { TEditInputOps.InsertBrackets['(,')] };
DashBrackets => { TEditInputOps.InsertBrackets['-,'-] };
DoubleQuoteBrackets => { TEditInputOps.InsertBrackets['",'"] };
AngleBrackets => { TEditInputOps.InsertBrackets['<,'>] };
SingleQuoteBrackets => {
use 140C for left single quote
TEditInputOps.InsertBrackets['\140,''];
};
CurlyBrackets => { TEditInputOps.InsertBrackets['{,'}] };
SquareBrackets => { TEditInputOps.InsertBrackets['[,']] };
Command0 => { DoCommand[viewer,0] };
Command1 => { DoCommand[viewer,1] };
Command2 => { DoCommand[viewer,2] };
Command3 => { DoCommand[viewer,3] };
Command4 => { DoCommand[viewer,4] };
Command5 => { DoCommand[viewer,5] };
Command6 => { DoCommand[viewer,6] };
Command7 => { DoCommand[viewer,7] };
Command8 => { DoCommand[viewer,8] };
Command9 => { DoCommand[viewer,9] };
SetComment => { TEditInputOps.SetCommentProp[TRUE] };
SetNotComment => { TEditInputOps.SetCommentProp[FALSE] };
PARAM => { -- Already processed in dispatch loop -- };
ENDCASE => ERROR;
};
ENDCASE => ERROR;
};
Registration
DispatchCommandProc: PUBLIC CommandClosureProc ~ {
WITH data SELECT FROM
c: REF CommandProc => [recordAtom: recordAtom, quit: quit] ¬ c­[viewer];
ENDCASE => ERROR;
};
Register: PUBLIC PROC [name: ATOM, proc: CommandProc, before: BOOL ¬ TRUE] = {
RegisterClosure[commandClosure: [name: name, proc: DispatchCommandProc, data: NEW[CommandProc ¬ proc]], before: before];
};
UnRegister: PUBLIC PROC [name: ATOM, proc: CommandProc] = {
Match: PROC [data: REF] RETURNS [BOOL] ~ {
WITH data SELECT FROM
c: REF CommandProc => RETURN [c­ = proc];
ENDCASE => ERROR;
};
UnRegisterClosure[name, DispatchCommandProc, Match];
};
IsRegistered: PUBLIC ENTRY PROC [name: ATOM, proc: CommandProc] RETURNS [BOOL] = {
ENABLE UNWIND => NULL;
p: REF ANY = RefTab.Fetch[commandTable, name].val;
closureList: LIST OF CommandClosure ¬ NARROW[p];
FOR l: LIST OF CommandClosure ¬ closureList, l.rest UNTIL l=NIL DO
IF l.first.proc=DispatchCommandProc THEN {
WITH l.first.data SELECT FROM
c: REF CommandProc => IF c­ = proc THEN RETURN [TRUE];
ENDCASE => NULL;
};
ENDLOOP;
RETURN [FALSE]
};
CommandClosure: TYPE ~ TEditInputExtras.CommandClosure;
CommandClosureProc: TYPE ~ TEditInputExtras.CommandClosureProc;
RegisterClosure: PUBLIC ENTRY PROC [commandClosure: CommandClosure, before: BOOL ¬ TRUE] = {
ENABLE UNWIND => NULL;
p: REF ANY = RefTab.Fetch[commandTable, commandClosure.name].val;
list: LIST OF CommandClosure ¬ NARROW[p];
IF before OR list=NIL
THEN list ¬ CONS[commandClosure, list]
ELSE {
FOR l: LIST OF CommandClosure ¬ list, l.rest DO
IF l.rest=NIL THEN { l.rest ¬ LIST[commandClosure]; EXIT };
ENDLOOP;
};
[] ¬ RefTab.Store[commandTable, commandClosure.name, list];
};
UnRegisterClosure: PUBLIC ENTRY PROC [name: ATOM, proc: CommandClosureProc, match: PROC [REF] RETURNS [BOOL]] = {
ENABLE UNWIND => NULL;
p: REF ANY = RefTab.Fetch[commandTable, name].val;
head: LIST OF CommandClosure = CONS[[NIL, NIL, NIL], NARROW[p]];
prev: LIST OF CommandClosure ¬ head;
FOR rem: LIST OF CommandClosure ¬ prev.rest, prev.rest UNTIL rem=NIL DO
IF rem.first.name # name THEN ERROR;
IF rem.first.proc = proc AND (match=NIL OR match[rem.first.data])
THEN { prev.rest ¬ rem.rest }
ELSE { prev ¬ rem };
ENDLOOP;
IF head.rest = NIL
THEN { [] ¬ RefTab.Delete[commandTable, name] }
ELSE { [] ¬ RefTab.Store[commandTable, name, head.rest] };
};
GetCommandNames: PUBLIC ENTRY PROC RETURNS [list: LIST OF ATOM ¬ NIL] ~ {
ENABLE UNWIND => NULL;
EachPair: RefTab.EachPairAction = {
[key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOLFALSE]
list ¬ CONS[NARROW[key], list];
};
[] ¬ RefTab.Pairs[x: commandTable, action: EachPair];
};
Initialization
RegisterCommandAtoms: PROC = {
RegisterInternal[$ApplyCaretLook, ApplyCaretLook];
RegisterInternal[$ApplyLook, ApplyLook];
RegisterInternal[$ClearCaretLooks, ClearCaretLooks];
RegisterInternal[$ClearLooks, ClearLooks];
RegisterInternal[$BackSpace, BackSpace];
RegisterInternal[$BackWord, BackWord];
RegisterInternal[$DeleteNextChar, DeleteNextChar];
RegisterInternal[$DeleteNextWord, DeleteNextWord];
RegisterInternal[$GoToPreviousWord, GoToPreviousWord];
RegisterInternal[$GoToNextWord, GoToNextWord];
RegisterInternal[$GoToPreviousChar, GoToPreviousChar];
RegisterInternal[$GoToNextChar, GoToNextChar];
RegisterInternal[$GoToPreviousNode, GoToPreviousNode];
RegisterInternal[$GoToNextNode, GoToNextNode];
RegisterInternal[$GoToEndOfNode, GoToEndOfNode];
RegisterInternal[$GoToBeginningOfNode, GoToBeginningOfNode];
RegisterInternal[$Copy, Copy];
RegisterInternal[$Delete, Delete];
Register [$DoEdit, DoEdit];
RegisterInternal[$ExpandAbbrev, ExpandAbbrev];
RegisterInternal[$Move, Move];
RegisterInternal[$NormalizeToStart, NormalizeToStart];
Register [$NormalizeToCaret, Normalize];
RegisterInternal[$NormalizeToEnd, NormalizeToEnd];
RegisterInternal[$RemoveCaretLook, RemoveCaretLook];
RegisterInternal[$RemoveLook, RemoveLook];
RegisterInternal[$SetStyle, SetStyle];
RegisterInternal[$Time, Time];
RegisterInternal[$RedSplit, RedSplit];
RegisterInternal[$YellowSplit, YellowSplit];
RegisterInternal[$BlueSplit, BlueSplit];
RegisterInternal[$Transpose, Transpose];
RegisterInternal[$ToBoth, ToBoth];
RegisterInternal[$ToLimbo, ToLimbo];
RegisterInternal[$ToPrimary, ToPrimary];
RegisterInternal[$ToSecondary, ToSecondary];
RegisterInternal[$CutToWorld, CutToWorld];
RegisterInternal[$CutToWorldFormatted, CutToWorldFormatted];
RegisterInternal[$CopyToWorld, CopyToWorld];
RegisterInternal[$CopyToWorldFormatted, CopyToWorldFormatted];
RegisterInternal[$Paste, Paste];
RegisterInternal[$PasteFromWorld, PasteFromWorld];
RegisterInternal[$PasteFromWorldFormatted, PasteFromWorldFormatted];
RegisterInternal[$EditReset, EditReset];
RegisterInternal[$EditAbort, EditAbort];
RegisterInternal[$EditText, EditText];
RegisterInternal[$EditFormat, EditFormat];
RegisterInternal[$EditType, EditFormat]; -- For compatability
RegisterInternal[$EditLooks, EditLooks];
RegisterInternal[$GetSecondary, GetSecondary];
RegisterInternal[$MakePDel, MakePDel];
RegisterInternal[$FindNext, FindNext];
RegisterInternal[$FindAny, FindAny];
RegisterInternal[$FindPrev, FindPrev];
RegisterInternal[$FindNextDef, FindNextDef];
RegisterInternal[$FindAnyDef, FindAnyDef];
RegisterInternal[$FindPrevDef, FindPrevDef];
RegisterInternal[$FindNextWord, FindNextWord];
RegisterInternal[$FindAnyWord, FindAnyWord];
RegisterInternal[$FindPrevWord, FindPrevWord];
RegisterInternal[$FindNextCaseless, FindNextCaseless];
RegisterInternal[$FindAnyCaseless, FindAnyCaseless];
RegisterInternal[$FindPrevCaseless, FindPrevCaseless];
RegisterInternal[$FindNextDefCaseless, FindNextDefCaseless];
RegisterInternal[$FindAnyDefCaseless, FindAnyDefCaseless];
RegisterInternal[$FindPrevDefCaseless, FindPrevDefCaseless];
RegisterInternal[$FindNextWordCaseless, FindNextWordCaseless];
RegisterInternal[$FindAnyWordCaseless, FindAnyWordCaseless];
RegisterInternal[$FindPrevWordCaseless, FindPrevWordCaseless];
Register [$PushSelection, SaveSelectionA];
Register [$PopSelection, RestoreSelectionA];
Register [$SaveSelection, SaveSelectionA];
Register [$RestoreSelection, RestoreSelectionA];
Register [$SaveSelectionA, SaveSelectionA];
Register [$RestoreSelectionA, RestoreSelectionA];
Register [$SaveSelectionB, SaveSelectionB];
Register [$RestoreSelectionB, RestoreSelectionB];
RegisterInternal[$Position, Position];
RegisterInternal[$PositionIncludingComments, PositionIncludingComments];
RegisterInternal[$MsgPosition, MsgPosition];
RegisterInternal[$MsgPositionIncludingComments, MsgPositionIncludingComments];
RegisterInternal[$StuffPosition, StuffPosition];
RegisterInternal[$StuffPositionIncludingComments, StuffPosition];
RegisterInternal[$RedMouse, RedMouse];
RegisterInternal[$YellowMouse, YellowMouse];
RegisterInternal[$BlueMouse, BlueMouse];
RegisterInternal[$RedDown, RedDown];
RegisterInternal[$YellowDown, YellowDown];
RegisterInternal[$BlueDown, BlueDown];
RegisterInternal[$SelBranch, SelBranch];
RegisterInternal[$SelChar, SelChar];
RegisterInternal[$SelExpand, SelExpand];
RegisterInternal[$SelExtend, SelExtend];
RegisterInternal[$SelStartExtend, SelStartExtend];
RegisterInternal[$SelNode, SelNode];
RegisterInternal[$SelNotPendDel, SelNotPendDel];
RegisterInternal[$SelPendDel, SelPendDel];
RegisterInternal[$ForceSelPendDel, ForceSelPendDel];
RegisterInternal[$ForceSelNotPendDel, ForceSelNotPendDel];
RegisterInternal[$SelSamePendDel, SelSamePendDel];
RegisterInternal[$SelPrimary, SelPrimary];
RegisterInternal[$SelReduce, SelReduce];
RegisterInternal[$SelSame, SelSame];
RegisterInternal[$SelSameEnd, SelSameEnd];
RegisterInternal[$SelSecondary, SelSecondary];
RegisterInternal[$SelUpdate, SelUpdate];
RegisterInternal[$SelWord, SelWord];
RegisterInternal[$IntermediateUser, IntermediateUser];
RegisterInternal[$AdvancedUser, AdvancedUser];
RegisterInternal[$ExpertUser, ExpertUser];
RegisterInternal[$Break, Break];
RegisterInternal[$Join, Join];
RegisterInternal[$Nest, Nest];
RegisterInternal[$SaveForPaste, SaveForPaste];
RegisterInternal[$SetFormat, SetFormat];
RegisterInternal[$SetType, SetFormat]; -- For compatability
RegisterInternal[$GetFormat, GetFormat];
RegisterInternal[$GetType, GetFormat]; -- For compatability
RegisterInternal[$UnNest, UnNest];
RegisterInternal[$AllCaps, AllCaps];
RegisterInternal[$AllLower, AllLower];
RegisterInternal[$FirstCap, FirstCap];
RegisterInternal[$InitialCaps, InitialCaps];
Register [$AllLevels, AllLevels];
Register [$FewerLevels, FewerLevels];
Register [$MoreLevels, MoreLevels];
Register [$FirstLevelOnly, FirstLevelOnly];
RegisterInternal[$CaretAfter, CaretAfter];
RegisterInternal[$CaretBefore, CaretBefore];
RegisterInternal[$Everything, Everything];
RegisterInternal[$GrowSelection, GrowSel];
RegisterInternal[$GrowSelectionToBlanks, GrowSelToBlanks];
RegisterInternal[$InsertLineBreak, InsertLineBreak];
RegisterInternal[$InsertNewline, InsertNewline];
RegisterInternal[$MakeNotPendingDelete, MakeNotPendingDelete];
RegisterInternal[$MakePendingDelete, MakePendingDelete];
Register [$MakePointSelection, MakePointSelection];
RegisterInternal[$MakeControlCharacter, MakeControlCharacter];
RegisterInternal[$MakeOctalCharacter, MakeOctalCharacter];
RegisterInternal[$UnMakeControlCharacter, UnMakeControlCharacter];
RegisterInternal[$UnMakeOctalCharacter, UnMakeOctalCharacter];
RegisterInternal[$MakePrimary, MakePrimaryOp];
RegisterInternal[$MakeSecondary, MakeSecondaryOp];
RegisterInternal[$CancelPrimary, CancelPrimaryOp];
RegisterInternal[$CancelSecondary, CancelSecondaryOp];
RegisterInternal[$Paint, Paint];
RegisterInternal[$PlaceholderBrackets, PlaceholderBrackets];
RegisterInternal[$PreviousPlaceholder, PreviousPlaceholder];
RegisterInternal[$PreviousViewer, PreviousViewer];
RegisterInternal[$ReadProfile, ReadTip];
RegisterInternal[$ReloadStyle, ReloadStyle];
RegisterInternal[$SelectMatchingPlaceholderBrackets, SelectMatchingPlaceholderBrackets];
RegisterInternal[$NextPlaceholder, NextPlaceholder];
RegisterInternal[$NextViewer, NextViewer];
RegisterInternal[$ReadAbbreviations, ReadAbbreviations];
RegisterInternal[$VerifyTree, VerifyTree];
RegisterInternal[$SelectMatchingParens, SelectMatchingParens];
RegisterInternal[$SelectMatchingAngleBrackets, SelectMatchingAngleBrackets];
RegisterInternal[$SelectMatchingCurlyBrackets, SelectMatchingCurlyBrackets];
RegisterInternal[$SelectMatchingSquareBrackets, SelectMatchingSquareBrackets];
RegisterInternal[$SelectMatchingSingleQuotes, SelectMatchingSingleQuotes];
RegisterInternal[$SelectMatchingDoubleQuotes, SelectMatchingDoubleQuotes];
RegisterInternal[$SelectMatchingDashBrackets, SelectMatchingDashBrackets];
RegisterInternal[$ParenBrackets, ParenBrackets];
RegisterInternal[$DashBrackets, DashBrackets];
RegisterInternal[$AngleBrackets, AngleBrackets];
RegisterInternal[$DoubleQuoteBrackets, DoubleQuoteBrackets];
RegisterInternal[$SingleQuoteBrackets, SingleQuoteBrackets];
RegisterInternal[$CurlyBrackets, CurlyBrackets];
RegisterInternal[$SquareBrackets, SquareBrackets];
RegisterInternal[$Command0, Command0];
RegisterInternal[$Command1, Command1];
RegisterInternal[$Command2, Command2];
RegisterInternal[$Command3, Command3];
RegisterInternal[$Command4, Command4];
RegisterInternal[$Command5, Command5];
RegisterInternal[$Command6, Command6];
RegisterInternal[$Command7, Command7];
RegisterInternal[$Command8, Command8];
RegisterInternal[$Command9, Command9];
RegisterInternal[$SetComment, SetComment];
RegisterInternal[$SetNotComment, SetNotComment];
RegisterInternal[$PARAM, PARAM];
};
justRegistered: BOOL ¬ TRUE;
ProfileChanged: UserProfile.ProfileChangedProc = {
IF NOT justRegistered THEN TEditProfile.ReadProfile[];
justRegistered ¬ FALSE;
};
toPrimaryMessages[FALSE][FALSE] ← "Select for copy to caret";
toPrimaryMessages[FALSE][TRUE] ← "Select for move to caret";
toPrimaryMessages[TRUE][FALSE] ← "Select replacement";
toPrimaryMessages[TRUE][TRUE] ← "Select for move onto";
toSecondaryMessages[FALSE][FALSE] ← "Select destination for copy";
toSecondaryMessages[FALSE][TRUE] ← "Select for replacement";
toSecondaryMessages[TRUE][FALSE] ← "Select destination for move";
toSecondaryMessages[TRUE][TRUE] ← "Select destination for move onto";
RegisterCommandAtoms[];
NodeAddrs.AddNotifyProc[UpdateSavedSelections];
UserProfile.CallWhenProfileChanges[ProfileChanged];
SetCommand[9, LIST[$MakePointSelection, $ParenBrackets]];
SetCommand[0, LIST[$SelectMatchingParens, $CaretAfter]];
END.