EditorComfortablePositioning.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Plass, March 21, 1985 12:54:53 pm PST
Doug Wyatt, June 20, 1985 3:11:02 pm PDT
Russ Atkinson (RRA) June 25, 1985 1:24:54 am PDT
Spreitzer, February 28, 1986 3:33:32 pm PST
Mike Spreitzer August 25, 1986 5:03:35 pm PDT
DIRECTORY
Convert USING [Error, IntFromRope, RopeFromInt],
Menus USING [ClickProc, MenuEntry, MouseButton],
MessageWindow USING [Append, Blink],
NodeProps USING [GetProp],
Rope USING [Cat, Equal, Index, Length, ROPE, Substr],
TEditDocument USING [Selection, SelectionId, TEditDocumentData],
TEditDocumentPrivate USING [findMenu],
TEditInput USING [CloseEvent, currentEvent, InterpretAtom, Register],
TEditInputOps USING [CallWithLocks, EditFailed],
TEditOps USING [GetSelContents, GetSelData, RememberCurrentPosition],
TEditProfile USING [selectionCaret],
TEditRefresh USING [ScrollToEndOfSel],
TEditSelection USING [CallWithSelAndDocAndTddLocks, Deselect, MakeSelection, SetSelLooks],
TEditSelectionOps USING [],
TEditSelectionOpsEtc,
TextEdit USING [InsertRope, RefTextNode, Size],
TextNode USING [Location, LocNumber, LocWithin, NarrowToTextNode, NodeItself, Ref, RefTextNode],
ViewerClasses USING [Viewer];
EditorComfortablePositioning: CEDAR PROGRAM
IMPORTS Convert, MessageWindow, NodeProps, Rope, TEditDocumentPrivate, TEditInput, TEditInputOps, TEditOps, TEditProfile, TEditRefresh, TEditSelection, TextEdit, TextNode
EXPORTS TEditSelectionOpsEtc
SHARES Menus --in order to change existing Position button, which is too inflexible
= BEGIN
ROPE: TYPE ~ Rope.ROPE;
Viewer: TYPE ~ ViewerClasses.Viewer;
SelectionId: TYPE ~ TEditDocument.SelectionId;
Selection: TYPE ~ TEditDocument.Selection;
ShowPosition: PROC[viewer: Viewer, skipCommentNodes: BOOLTRUE] = {
countI, countF: INT ← -1;
sel: ROPE = TEditOps.GetSelContents[];
selLen: INT = sel.Length[];
sepStart: INT = sel.Index[s2: ".."];
countI ← Convert.IntFromRope[sel.Substr[len: sepStart] ! Convert.Error => GOTO Bitch];
IF countI < 0 THEN GOTO Bitch;
IF sepStart < selLen
THEN countF ← Convert.IntFromRope[sel.Substr[sepStart+2] ! Convert.Error => GOTO Bitch]
ELSE countF ← countI + 3;
IF countF < 0 THEN GOTO Bitch;
ShowGivenPositionRange[viewer, feedback, countI, countF, skipCommentNodes, FALSE];
EXITS
Bitch => {OPEN MessageWindow;
Append["Select character count or count..count for position.", TRUE];
Blink[];
};
};
Position: PROC[viewer: Viewer] ~ {
ShowPosition[viewer: viewer, skipCommentNodes: TRUE];
};
ShowGivenPositionRange: PUBLIC PROC [viewer: Viewer, selectionId: SelectionId, posI, posF: INT, skipCommentNodes, pendingDelete: BOOL] = {
Should join or replace ShowGivenPosition, which is currently in TEditSelectionOps
DoPosition: PROC [tdd: TEditDocument.TEditDocumentData, tSel: Selection] = {
tiogaFile: BOOL = (NodeProps.GetProp[tdd.text, $FromTiogaFile] = $Yes);
IF posF < posI THEN {p: INT ← posI; posI ← posF; posF ← p};
IF Adjust[tiogaFile] THEN {posI ← posI + 1; posF ← posF+1};
tSel.start.pos ← TextNode.LocWithin[tdd.text, posI, 1, skipCommentNodes];
tSel.end.pos ← TextNode.LocWithin[tdd.text, posF, 1, skipCommentNodes];
tSel.granularity ← char;
tSel.viewer ← viewer;
tSel.data ← tdd;
tSel.pendingDelete ← pendingDelete;
tSel.insertion ← IF TEditProfile.selectionCaret=before THEN before ELSE after;
TEditOps.RememberCurrentPosition[viewer];
TEditSelection.SetSelLooks[tSel];
TEditSelection.MakeSelection[new: tSel, selection: selectionId];
TEditRefresh.ScrollToEndOfSel[viewer, FALSE, selectionId];
sets bit to cause scroll after refresh
};
TEditSelection.CallWithSelAndDocAndTddLocks[viewer, selectionId, DoPosition];
};
Adjust: PROC [tiogaFile: BOOL] RETURNS [adj: BOOL] = INLINE {adj ← NOT tiogaFile};
Range: TYPE = RECORD [start, end: INT];
FmtRange: PROC [r: Range] RETURNS [rope: ROPE] = {
IF r.start = r.end
THEN rope ← Convert.RopeFromInt[r.start]
ELSE rope ← Rope.Cat[
Convert.RopeFromInt[r.start],
"..",
Convert.RopeFromInt[r.end]];
};
messagedPosition: Range ← [0, 0];
MessagePosition: PROC [viewer: Viewer, skipCommentNodes: BOOL] = {
tSel: Selection = TEditOps.GetSelData[];
tiogaFile: BOOL = (NodeProps.GetProp[tSel.data.text, $FromTiogaFile] = $Yes);
messagedPosition ← [
start: TextNode.LocNumber[at: tSel.start.pos, skipCommentNodes: skipCommentNodes],
end: TextNode.LocNumber[at: tSel.end.pos, skipCommentNodes: skipCommentNodes]];
IF Adjust[tiogaFile] THEN messagedPosition ← [
start: messagedPosition.start - 1,
end: messagedPosition.end - 1];
MessageWindow.Append[
Rope.Cat[
"Current position is ",
FmtRange[messagedPosition],
IF skipCommentNodes THEN " (excluding comment nodes)" ELSE " (including comment nodes)"],
TRUE];
};
StuffPosition: PROC [viewer: Viewer ← NIL, skipCommentNodes: BOOL] = {
Doit: PROC [root: TextNode.Ref, tSel: Selection] = {
loc: TextNode.Location = SELECT tSel.insertion FROM before => tSel.start.pos, after => tSel.end.pos, ENDCASE => ERROR;
node: TextNode.RefTextNode = TextNode.NarrowToTextNode[loc.node];
nodeSize: INT;
where: INT ← loc.where;
insertion: ROPE = FmtRange[messagedPosition];
resultStart, resultLen: INT;
IF node = NIL THEN GOTO Bad;
nodeSize ← TextEdit.Size[node];
where ← MIN[where, nodeSize];
IF where = TextNode.NodeItself
THEN where ← SELECT tSel.insertion FROM before => 0, after => nodeSize, ENDCASE => ERROR
ELSE IF tSel.insertion = after AND tSel.granularity # point THEN where ← where + 1;
TEditSelection.Deselect[primary];
[resultStart, resultLen] ← TextEdit.InsertRope[
root: root,
dest: node,
rope: insertion,
destLoc: where,
inherit: FALSE,
looks: tSel.looks,
event: TEditInput.currentEvent];
tSel.start.pos.node ← tSel.end.pos.node ← node;
tSel.start.pos.where ← resultStart;
tSel.end.pos.where ← resultStart + resultLen - 1;
tSel.granularity ← char;
tSel.pendingDelete ← FALSE;
TEditSelection.MakeSelection[selection: primary, new: tSel];
EXITS Bad => TEditInputOps.EditFailed[]
};
TEditInputOps.CallWithLocks[Doit, write];
};
ShowPositionOp: PROC [viewer: Viewer ← NIL] RETURNS [recordAtom: BOOLTRUE, quit: BOOLFALSE] --TiogaOps.CommandProc-- = {
TEditInput.CloseEvent[];
recordAtom ← FALSE;
quit ← TRUE;
ShowPosition[viewer, TRUE];
};
ShowPositionWithCommentsOp: PROC [viewer: Viewer ← NIL] RETURNS [recordAtom: BOOLTRUE, quit: BOOLFALSE] --TiogaOps.CommandProc-- = {
TEditInput.CloseEvent[];
recordAtom ← FALSE;
quit ← TRUE;
ShowPosition[viewer, FALSE];
};
MessagePositionOp: PROC [viewer: Viewer ← NIL] RETURNS [recordAtom: BOOLTRUE, quit: BOOLFALSE] --TiogaOps.CommandProc-- = {
quit ← TRUE;
MessagePosition[viewer, TRUE];
};
MessagePositionWithCommentsOp: PROC [viewer: Viewer ← NIL] RETURNS [recordAtom: BOOLTRUE, quit: BOOLFALSE] --TiogaOps.CommandProc-- = {
quit ← TRUE;
MessagePosition[viewer, FALSE];
};
StuffPositionOp: PROC [viewer: Viewer ← NIL] RETURNS [recordAtom: BOOLTRUE, quit: BOOLFALSE] --TiogaOps.CommandProc-- = {
quit ← TRUE;
StuffPosition[viewer, TRUE];
};
StuffPositionWithCommentsOp: PROC [viewer: Viewer ← NIL] RETURNS [recordAtom: BOOLTRUE, quit: BOOLFALSE] --TiogaOps.CommandProc-- = {
quit ← TRUE;
StuffPosition[viewer, FALSE];
};
PositionButt: PROC [parent: REF ANY, clientData: REF ANYNIL,
mouseButton: Menus.MouseButton ← red, shift, control: BOOLFALSE] --Menus.ClickProc-- = {
TEditInput.InterpretAtom[
NARROW[parent],
SELECT mouseButton FROM
red => IF shift THEN $PositionIncludingComments ELSE $Position,
yellow => IF shift THEN $MsgPositionIncludingComments ELSE $MsgPosition,
blue => IF shift THEN $StuffPositionIncludingComments ELSE $StuffPosition,
ENDCASE => ERROR
];
};
AmbushMenuEntry: PROC [first: Menus.MenuEntry, name: ROPE, proc: Menus.ClickProc] = {
me: Menus.MenuEntry;
FOR me ← first, me.link WHILE NOT me.name.Equal[name] DO NULL ENDLOOP;
me.proc ← proc;
};
Start: PROC = {
TEditInput.Register[$Position, ShowPositionOp];
TEditInput.Register[$PositionIncludingComments, ShowPositionWithCommentsOp];
TEditInput.Register[$MsgPosition, MessagePositionOp];
TEditInput.Register[$MsgPositionIncludingComments, MessagePositionWithCommentsOp];
TEditInput.Register[$StuffPosition, StuffPositionOp];
TEditInput.Register[$StuffPositionIncludingComments, StuffPositionWithCommentsOp];
AmbushMenuEntry[TEditDocumentPrivate.findMenu, "Position", PositionButt];
};
Start[];
END.