TEditMiscOps2Impl.mesa
Copyright © 1985, 1986 by Xerox Corporation. All rights reserved.
Paxton on December 28, 1982 2:23 pm
Maxwell, January 6, 1983 11:34 am
Russ Atkinson, July 26, 1983 11:45 am
Paul Rovner, August 10, 1983 4:41 pm
Michael Plass, March 27, 1985 4:58:13 pm PST
Rick Beach, March 28, 1985 9:59:13 am PST
Doug Wyatt, September 2, 1986 5:00:59 pm PDT
DIRECTORY
AbbrevExpand USING [Expand, Load],
Ascii USING [Lower],
Atom USING [GetPName, MakeAtom],
Basics USING [BITAND],
EditSpan USING [ChangeCaps],
FS USING [Error],
MessageWindow USING [Append, Blink],
NodeProps USING [false, true],
NodeStyleOps USING [ReloadStyle, StyleNameForNode],
NodeStyleWorks USING [ForEachAttachedStyle],
Rope USING [Concat, Fetch, FromProc, IsEmpty, ROPE, Size, Substr],
RopeEdit USING [AlphaNumericChar, Substr],
RopeReader USING [FreeRopeReader, Get, GetIndex, GetRopeReader, Ref, SetPosition],
TextEdit USING [CapChange, ChangeFormat, ChangeStyle, FetchChar, FetchLooks, GetCharPropList, GetRope, PropList, PutCharPropList, PutProp, ReplaceByChar],
TextNode USING [Location, Node, NodeItself, Root, StepForward],
TEditDocument USING [BeforeAfter, Selection, SelectionId, SelectionPoint],
TEditInput USING [currentEvent, Interpret],
TEditInputOps USING [BackSpace, CallWithBothLocked, CallWithLocks, CheckReadonly, Delete, EditFailed, FindPlaceholders, InsertChar, InsertRope],
TEditLocks USING [Lock, Unlock],
TEditSelection USING [Alloc, Copy, Free, CaretAfterSelection, Deselect, InsertionPoint, LockSel, MakePointSelection, MakeSelection, oldSel, pSel, SelectionRoot, sSel, UnlockSel],
TEditTouchup USING [fullUpdate],
ViewerClasses USING [Viewer],
ViewerOps USING [PaintViewer];
TEditMiscOps2Impl:
CEDAR
PROGRAM
IMPORTS Atom, AbbrevExpand, Ascii, FS, EditSpan, Basics, MessageWindow, NodeProps, NodeStyleOps, NodeStyleWorks, Rope, RopeEdit, RopeReader, TextEdit, TextNode, TEditInput, TEditInputOps, TEditLocks, TEditSelection, TEditTouchup, ViewerOps
EXPORTS TEditInputOps = BEGIN
Capitalise:
PUBLIC
PROCEDURE [flavor: TextEdit.CapChange] = {
DoCapitalise:
PROC [root: TextNode.Node, tSel: TEditDocument.Selection] = {
TEditSelection.Deselect[];
EditSpan.ChangeCaps[root, [tSel.start.pos, tSel.end.pos], flavor, TEditInput.currentEvent];
tSel.pendingDelete ← FALSE;
TEditSelection.MakeSelection[tSel,primary]
};
TEditInputOps.CallWithLocks[DoCapitalise]
};
ControlChar:
PROC [make:
BOOLEAN] = {
DoControlChar:
PROC [root: TextNode.Node, tSel: TEditDocument.Selection] = {
caret: TextNode.Location ← TEditSelection.InsertionPoint[tSel];
node: TextNode.Node;
where: INT ← 0;
char: CHAR;
IF caret.where=TextNode.NodeItself OR caret.where=0 THEN GOTO Bad;
IF (node ← caret.node) = NIL THEN GOTO Bad;
where ← caret.where-1;
char ← TextEdit.FetchChar[node,where].char;
IF ~make AND char > 37C THEN GOTO Bad;
char ← IF ~make THEN LOOPHOLE[char-1,CARDINAL]+'A
ELSE LOOPHOLE[Basics.BITAND[char-0C,37B],CHAR];
TEditSelection.Deselect[];
[] ← TextEdit.ReplaceByChar[
root: root, dest:node, char:char, start:where, len:1,
inherit:FALSE, looks:TextEdit.FetchLooks[node,where], event:TEditInput.currentEvent];
TEditSelection.MakePointSelection[tSel, caret];
EXITS Bad => TEditInputOps.EditFailed[]
};
TEditInputOps.CallWithLocks[DoControlChar]
};
MakeControlCharacter: PUBLIC PROC = { ControlChar[TRUE] };
UnMakeControlCharacter: PUBLIC PROC = { ControlChar[FALSE] };
UnMakeOctalCharacter:
PUBLIC
PROC = {
DoUnMakeOctalCharacter:
PROC [root: TextNode.Node, tSel: TEditDocument.Selection] = {
InsertOctal:
PROC [c:
CARDINAL] ~ {
TEditInputOps.InsertChar[c/64 + '0];
TEditInputOps.InsertChar[(c/8) MOD 8 + '0];
TEditInputOps.InsertChar[c MOD 8 + '0];
};
caret: TextNode.Location ~ TEditSelection.InsertionPoint[tSel];
node: TextNode.Node ~ caret.node;
charSet: CARDINAL;
char: CHAR;
charProps: TextEdit.PropList;
IF caret.where=TextNode.NodeItself OR caret.where=0 THEN GOTO Bad;
IF node = NIL THEN GOTO Bad;
[charSet, char] ← TextEdit.FetchChar[node, caret.where-1];
charProps ← TextEdit.GetCharPropList[node, caret.where-1];
TEditInputOps.BackSpace[1];
IF charSet = 0 THEN InsertOctal[ORD[char]]
ELSE {
TEditInputOps.InsertChar['(];
InsertOctal[charSet];
TEditInputOps.InsertChar['|];
InsertOctal[ORD[char]];
TEditInputOps.InsertChar[')];
};
IF charProps #
NIL
THEN {
TextEdit.PutCharPropList[node: node, index: caret.where-1, nChars: IF charSet = 0 THEN 3 ELSE 9, propList: charProps, event: TEditInput.currentEvent]
};
EXITS Bad => TEditInputOps.EditFailed[]
};
TEditInputOps.CallWithLocks[DoUnMakeOctalCharacter]
};
MakeOctalCharacter:
PUBLIC
PROC = {
DoMakeOctalCharacter:
PROC [root: TextNode.Node, tSel: TEditDocument.Selection] = {
caret: TextNode.Location ← TEditSelection.InsertionPoint[tSel];
node: TextNode.Node ~ caret.node;
GetOctal:
PROC [offset:
INT]
RETURNS [d:
CARDINAL ← 0] ~ {
c: CHAR; s: [0..256);
FOR i:
INT
IN [0..3)
DO
[s, c] ← TextEdit.FetchChar[node, offset+i];
IF s#0 OR c NOT IN ['0..'7] THEN RETURN [NAT.LAST];
d ← d*8 + (c-'0);
ENDLOOP;
};
len: INT ← 0;
charCode: CARDINAL ← 0;
charSet: CARDINAL ← 0;
IF caret.where=TextNode.NodeItself OR caret.where<3 THEN GOTO Bad;
IF node = NIL THEN GOTO Bad;
IF TextEdit.FetchChar[node, caret.where-1] = [charSet: 0, char: ')]
THEN {
IF caret.where<9 THEN GOTO Bad;
IF TextEdit.FetchChar[node, caret.where-5] # [charSet: 0, char: '|] THEN GOTO Bad;
IF TextEdit.FetchChar[node, caret.where-9] # [charSet: 0, char: '(] THEN GOTO Bad;
charCode ← GetOctal[caret.where-4];
charSet ← GetOctal[caret.where-8];
len ← 9;
}
ELSE {
charCode ← GetOctal[caret.where-3];
len ← 3;
};
IF charCode > 255 OR charSet >= 255 THEN GOTO Bad;
TEditSelection.Deselect[]; {
charProps: TextEdit.PropList ~ TextEdit.GetCharPropList[node, caret.where-len];
[] ← TextEdit.ReplaceByChar[
root: root, dest: node, char: VAL[charCode], start: caret.where-len, len: len,
inherit: FALSE, looks: TextEdit.FetchLooks[node, caret.where-len], charSet: charSet, event: TEditInput.currentEvent];
IF charProps # NIL THEN TextEdit.PutCharPropList[node: node, index: caret.where-len, nChars: 1, propList: charProps, event: TEditInput.currentEvent]
};
caret.where ← caret.where-len+1;
TEditSelection.MakePointSelection[tSel, caret];
EXITS Bad => TEditInputOps.EditFailed[]
};
TEditInputOps.CallWithLocks[DoMakeOctalCharacter]
};
GetWord:
PROC
RETURNS [word: Rope.
ROPE] = {
tSel: TEditDocument.Selection;
start: INT ← 0;
pos: TextNode.Location;
node: TextNode.Node;
nChars: CARDINAL ← 0;
TEditSelection.CaretAfterSelection;
pos ← TEditSelection.InsertionPoint[];
IF (node ← pos.node)=NIL THEN RETURN [NIL];
IF pos.where = TextNode.NodeItself THEN RETURN [NIL];
start ← pos.where-1;
WHILE start>=0
DO
set: NAT;
c: CHAR;
[set, c] ← TextEdit.FetchChar[node, start];
IF set#0 OR NOT RopeEdit.AlphaNumericChar[c] THEN EXIT;
start ← start - 1; nChars ← nChars + 1;
ENDLOOP;
IF nChars = 0 THEN RETURN [NIL];
start ← pos.where-nChars;
word ← RopeEdit.Substr[node.rope, start, nChars];
tSel ← TEditSelection.Alloc[];
TEditSelection.Copy[source: TEditSelection.pSel, dest: tSel];
tSel.start.pos ← [node,start];
tSel.end.pos ← [node,start+nChars-1];
tSel.granularity ← char;
TEditSelection.MakeSelection[tSel, primary];
TEditSelection.Free[tSel];
TEditInputOps.Delete[];
};
SetStyle:
PUBLIC
PROC = {
DoSetStyle:
PROC [root: TextNode.Node, tSel: TEditDocument.Selection] = {
name: Rope.ROPE ← GetWord[];
IF name=NIL THEN { TEditInputOps.EditFailed[]; RETURN };
SetStyleName[name]
};
TEditInputOps.CallWithLocks[DoSetStyle]
};
ForceLower:
PROC [r: Rope.
ROPE]
RETURNS [Rope.
ROPE] = {
Force: PROC RETURNS [c: CHAR] = { c ← Ascii.Lower[Rope.Fetch[r,i]]; i ← i+1 };
i: INT ← 0;
RETURN [Rope.FromProc[Rope.Size[r], Force]]
};
SetStyleName:
PUBLIC
PROC [name: Rope.
ROPE, node: TextNode.Node ←
NIL] = {
root: TextNode.Node;
IF node=NIL THEN
node ← IF TEditSelection.pSel.insertion=before THEN TEditSelection.pSel.start.pos.node ELSE TEditSelection.pSel.end.pos.node;
root ← TextNode.Root[node];
[] ← TEditLocks.Lock[root, "SetStyleName"];
TextEdit.ChangeStyle[node, ForceLower[name], TEditInput.currentEvent, root !
UNWIND => TEditLocks.Unlock[root]];
TEditLocks.Unlock[root];
};
ReloadStyle:
PUBLIC
PROC = {
styleName: ATOM ← NodeStyleOps.StyleNameForNode[TEditSelection.InsertionPoint[].node];
IF NOT NodeStyleOps.ReloadStyle[styleName] THEN CannotReload[styleName]
ELSE ViewerOps.PaintViewer[TEditSelection.pSel.viewer, client, FALSE, TEditTouchup.fullUpdate];
};
ReloadStyleName:
PUBLIC
PROC [name: Rope.
ROPE] = {
styleName: ATOM;
IF name.IsEmpty THEN RETURN;
styleName ← Atom.MakeAtom[name];
IF NOT NodeStyleOps.ReloadStyle[styleName] THEN CannotReload[styleName];
};
CannotReload:
PROC [styleName:
ATOM] = {
MessageWindow.Append["Failed in attempt to load style named ", TRUE];
MessageWindow.Append[Atom.GetPName[styleName]];
MessageWindow.Blink[]
};
SetFormat:
PUBLIC
PROC = {
DoSetFormat:
PROC [root: TextNode.Node, tSel: TEditDocument.Selection] = {
name: Rope.ROPE ← GetWord[];
IF name=NIL THEN { TEditInputOps.EditFailed[]; RETURN };
SetFormatName[name]
};
TEditInputOps.CallWithLocks[DoSetFormat]
};
GetFormat:
PUBLIC
PROC = {
DoGetFormat:
PROC [root: TextNode.Node, tSel: TEditDocument.Selection] = {
name: Rope.ROPE;
format: ATOM ← TEditSelection.InsertionPoint[].node.formatName;
name ← IF format=NIL THEN "default" ELSE Atom.GetPName[format];
TEditInputOps.InsertRope[name]
};
TEditInputOps.CallWithLocks[DoGetFormat]
};
TransposeFormat:
PUBLIC
PROC [target: TEditDocument.SelectionId ← primary] = {
Transpose the formats of the primary and secondary selections
targetSel: TEditDocument.Selection ← IF target=primary THEN TEditSelection.pSel ELSE TEditSelection.sSel;
srcSel: TEditDocument.Selection ← IF target=primary THEN TEditSelection.sSel ELSE TEditSelection.pSel;
DoTransFormat:
PROC [sourceRoot, destRoot: TextNode.Node, tSel, srcSel, targetSel: TEditDocument.Selection] = {
targetFormat, srcFormat: ATOM;
targetNode, srcNode: TextNode.Node;
srcNode ← IF srcSel.insertion=before THEN srcSel.start.pos.node ELSE srcSel.end.pos.node;
srcFormat ← srcNode.formatName;
targetNode ← IF targetSel.insertion=before THEN targetSel.start.pos.node
ELSE targetSel.end.pos.node;
targetFormat ← targetNode.formatName;
TEditSelection.Copy[source: targetSel, dest: TEditSelection.oldSel]; -- save for Repeat's
FOR node: TextNode.Node ← targetSel.start.pos.node, TextNode.StepForward[node]
DO
TextEdit.ChangeFormat[node, srcFormat, TEditInput.currentEvent, destRoot];
IF node = targetSel.end.pos.node THEN EXIT;
ENDLOOP;
FOR node: TextNode.Node ← srcSel.start.pos.node, TextNode.StepForward[node]
DO
TextEdit.ChangeFormat[node, targetFormat, TEditInput.currentEvent, sourceRoot];
IF node = srcSel.end.pos.node THEN EXIT;
ENDLOOP;
TEditSelection.MakeSelection[IF target=primary THEN targetSel ELSE srcSel, primary]
};
TEditInputOps.CallWithBothLocked[DoTransFormat, targetSel, srcSel, write]
};
CopyFormat:
PUBLIC
PROCEDURE [target: TEditDocument.SelectionId ← primary] = {
targetSel: TEditDocument.Selection ← IF target=primary THEN TEditSelection.pSel ELSE TEditSelection.sSel;
srcSel: TEditDocument.Selection ← IF target=primary THEN TEditSelection.sSel ELSE TEditSelection.pSel;
DoCopyFormat:
PROC [sourceRoot, destRoot: TextNode.Node, tSel, srcSel, targetSel: TEditDocument.Selection] = {
srcNode: TextNode.Node ←
IF srcSel.insertion=before THEN srcSel.start.pos.node ELSE srcSel.end.pos.node;
format: ATOM ← srcNode.formatName;
TEditSelection.Copy[source: srcSel, dest: TEditSelection.oldSel]; -- save for Repeat's
FOR node: TextNode.Node ← targetSel.start.pos.node, TextNode.StepForward[node]
DO
TextEdit.ChangeFormat[node, format, TEditInput.currentEvent, destRoot];
IF node = targetSel.end.pos.node THEN EXIT;
ENDLOOP;
TEditSelection.MakeSelection[IF target=primary THEN targetSel ELSE srcSel, primary]
};
TEditInputOps.CallWithBothLocked[DoCopyFormat, targetSel, srcSel, read]
};
SetFormatName:
PUBLIC
PROC [name: Rope.
ROPE, node: TextNode.Node ←
NIL] = {
root: TextNode.Node;
lockSel: BOOL = (node=NIL);
format: ATOM ← IF name.IsEmpty THEN NIL ELSE Atom.MakeAtom[ForceLower[name]];
IF lockSel
THEN {
TEditSelection.LockSel[primary, "SetFormatName"];
IF ~TEditInputOps.CheckReadonly[TEditSelection.pSel]
OR (root ← TEditSelection.SelectionRoot[TEditSelection.pSel])=
NIL
THEN {
TEditSelection.UnlockSel[primary]; RETURN
};
node ← TEditSelection.InsertionPoint[].node
}
ELSE root ← TextNode.Root[node];
{
ENABLE
UNWIND =>
IF lockSel
THEN TEditSelection.UnlockSel[primary];
[] ← TEditLocks.Lock[root, "SetFormatName"];
TextEdit.ChangeFormat[node, format, TEditInput.currentEvent, root];
TEditLocks.Unlock[root];
IF lockSel THEN TEditSelection.UnlockSel[primary]
}
};
SetSelFormatName:
PROC [name: Rope.
ROPE, sel: TEditDocument.Selection] = {
DoSetSelFormatName:
PROC [root: TextNode.Node, tSel: TEditDocument.Selection] = {
format: ATOM ← IF name.IsEmpty THEN NIL ELSE Atom.MakeAtom[ForceLower[name]];
FOR node: TextNode.Node ← tSel.start.pos.node, TextNode.StepForward[node]
DO
TextEdit.ChangeFormat[node, format, TEditInput.currentEvent, root];
IF node = tSel.end.pos.node THEN EXIT;
ENDLOOP
};
TEditInputOps.CallWithLocks[DoSetSelFormatName]
};
SetCommentProp:
PUBLIC
PROC [flag:
BOOLEAN] = {
DoSetCommentProp:
PROC [root: TextNode.Node, tSel: TEditDocument.Selection] = {
FOR node: TextNode.Node ← tSel.start.pos.node, TextNode.StepForward[node]
DO
IF node # NIL THEN
TextEdit.PutProp[node, $Comment,
IF flag THEN NodeProps.true ELSE NodeProps.false,
TEditInput.currentEvent];
IF node = tSel.end.pos.node THEN EXIT;
ENDLOOP
};
TEditInputOps.CallWithLocks[DoSetCommentProp]
};
abbrevFailedProc: PROC RETURNS [BOOL] ← NIL;
RegisterAbbrevFailedProc:
PUBLIC
PROC [proc:
PROC
RETURNS [
BOOL]] = {
abbrevFailedProc ← proc
};
ExpandAbbreviation:
PUBLIC
PROC = {
DoExpand:
PROC [root: TextNode.Node, tSel: TEditDocument.Selection] = {
pos: TextNode.Location;
node: TextNode.Node;
offset: INT ← 0;
done, keyDeterminesDict: BOOLEAN ← FALSE;
clearedMessageWindow: BOOLEAN ← FALSE;
keyStart, keyLen, resultLen: INT ← 0;
rdr: RopeReader.Ref;
commands: LIST OF REF ANY;
styleName: ATOM;
Try:
PROC [name:
ATOM]
RETURNS [stop:
BOOLEAN] = {
dict: Rope.ROPE = Atom.GetPName[name];
[done,keyDeterminesDict,keyStart,keyLen,resultLen,commands] ←
AbbrevExpand.Expand[node,offset,dict,TEditInput.currentEvent];
IF ~done
AND ~keyDeterminesDict
THEN
NodeStyleWorks.ForEachAttachedStyle[name,Try];
RETURN [done]
};
TEditSelection.CaretAfterSelection;
pos ← TEditSelection.InsertionPoint[];
node ← pos.node;
offset ← pos.where;
styleName ← NodeStyleOps.StyleNameForNode[node];
TEditSelection.Deselect[];
IF ~Try[styleName]
THEN {
TEditSelection.MakeSelection[tSel, primary];
IF abbrevFailedProc # NIL AND abbrevFailedProc[] THEN RETURN;
MessageWindow.Append[Rope.Substr[TextEdit.GetRope[node], keyStart, keyLen], ~clearedMessageWindow];
MessageWindow.Append["? Unknown abbreviation."];
RETURN
};
tSel.end.pos.node ← tSel.start.pos.node ← node;
tSel.start.pos.where ← keyStart;
tSel.pendingDelete ← FALSE;
IF resultLen = 0
THEN {
-- make a caret
tSel.end.pos.where ← keyStart;
tSel.insertion ← before;
tSel.granularity ← point
}
ELSE {
tSel.end.pos.where ← keyStart+resultLen-1;
tSel.insertion ← after;
tSel.granularity ← char
};
TEditSelection.MakeSelection[tSel, primary];
rdr ← RopeReader.GetRopeReader[];
RopeReader.SetPosition[rdr, TextEdit.GetRope[node], keyStart];
FOR i:
INT
IN [0..resultLen)
DO
-- check for placeholder
IF RopeReader.Get[rdr] = 1C
THEN {
-- found one
TEditSelection.MakePointSelection[tSel,[node,keyStart+i]];
TEditInputOps.FindPlaceholders[TRUE];
EXIT
};
ENDLOOP;
RopeReader.FreeRopeReader[rdr];
IF commands # NIL THEN TEditInput.Interpret[TEditSelection.pSel.viewer, commands]
};
TEditInputOps.CallWithLocks[DoExpand]
};
LoadAbbreviations:
PUBLIC
PROC [dictName: Rope.
ROPE] = {
count: LONG INTEGER ← 0;
fileName: Rope.ROPE;
IF Rope.Size[dictName]=0 THEN RETURN;
fileName ← Rope.Concat[dictName,".Abbreviations"];
count ← AbbrevExpand.Load[fileName,
dictName ! FS.Error => {CONTINUE}];
IF count = 0
THEN {
-- something went wrong
MessageWindow.Append["The file named <", TRUE];
MessageWindow.Append[fileName];
MessageWindow.Append["> was not found or was not an abbreviation dictionary"]
}
};
END.