<> <> <> <> <> <> <> <<>> 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: BOOL _ TRUE] = { 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] = { <> 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]; <> }; 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: BOOL _ TRUE, quit: BOOL _ FALSE] --TiogaOps.CommandProc-- = { TEditInput.CloseEvent[]; recordAtom _ FALSE; quit _ TRUE; ShowPosition[viewer, TRUE]; }; ShowPositionWithCommentsOp: PROC [viewer: Viewer _ NIL] RETURNS [recordAtom: BOOL _ TRUE, quit: BOOL _ FALSE] --TiogaOps.CommandProc-- = { TEditInput.CloseEvent[]; recordAtom _ FALSE; quit _ TRUE; ShowPosition[viewer, FALSE]; }; MessagePositionOp: PROC [viewer: Viewer _ NIL] RETURNS [recordAtom: BOOL _ TRUE, quit: BOOL _ FALSE] --TiogaOps.CommandProc-- = { quit _ TRUE; MessagePosition[viewer, TRUE]; }; MessagePositionWithCommentsOp: PROC [viewer: Viewer _ NIL] RETURNS [recordAtom: BOOL _ TRUE, quit: BOOL _ FALSE] --TiogaOps.CommandProc-- = { quit _ TRUE; MessagePosition[viewer, FALSE]; }; StuffPositionOp: PROC [viewer: Viewer _ NIL] RETURNS [recordAtom: BOOL _ TRUE, quit: BOOL _ FALSE] --TiogaOps.CommandProc-- = { quit _ TRUE; StuffPosition[viewer, TRUE]; }; StuffPositionWithCommentsOp: PROC [viewer: Viewer _ NIL] RETURNS [recordAtom: BOOL _ TRUE, quit: BOOL _ FALSE] --TiogaOps.CommandProc-- = { quit _ TRUE; StuffPosition[viewer, FALSE]; }; PositionButt: PROC [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift, control: BOOL _ FALSE] --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.