<> <> <> <> <> <<>> DIRECTORY AbbrevExpand USING [Expand, Load], Ascii USING [Lower], Basics USING [BITAND], EditSpan USING [ChangeCaps], FS USING [Error], MessageWindow USING [Append, Blink], NameSymbolTable USING [MakeName, Name, RopeFromName], NodeProps USING [false, true], NodeStyle USING [Name, ReloadStyle, StyleNameForNode], NodeStyleExtra USING [ForEachAttachedStyle], Rope USING [Concat, Fetch, Flatten, FromProc, ROPE, Size, Substr], RopeEdit USING [AlphaNumericChar, Substr], RopeReader USING [FreeRopeReader, Get, GetIndex, GetRopeReader, Ref, SetPosition], TextEdit USING [CapChange, ChangeStyle, ChangeType, FetchChar, FetchLooks, GetRope, Offset, PutProp, Ref, RefTextNode, ReplaceByChar], TextNode USING [Location, NarrowToTextNode, NodeItself, nullTypeName, Offset, Ref, RefTextNode, Root, StepForward, TypeName], TEditDocument USING [BeforeAfter, Selection, SelectionId, SelectionPoint], TEditInput USING [currentEvent, Interpret], TEditInputOps, TEditLocks USING [Lock, Unlock], TEditOps, 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 AbbrevExpand, Ascii, FS, EditSpan, Basics, MessageWindow, NameSymbolTable, NodeProps, NodeStyle, NodeStyleExtra, Rope, RopeEdit, RopeReader, TextEdit, TextNode, TEditInput, TEditInputOps, TEditLocks, TEditSelection, TEditTouchup, ViewerOps EXPORTS TEditInputOps = BEGIN OPEN TEditDocument, TEditSelection, TEditOps, TEditInputOps; Capitalise: PUBLIC PROCEDURE [flavor: TextEdit.CapChange] = { DoCapitalise: PROC [root: TextEdit.Ref, tSel: Selection] = { Deselect[]; EditSpan.ChangeCaps[root, [tSel.start.pos, tSel.end.pos], flavor, TEditInput.currentEvent]; tSel.pendingDelete _ FALSE; MakeSelection[tSel,primary] }; CallWithLocks[DoCapitalise] }; ControlChar: PROC [make: BOOLEAN] = { DoControlChar: PROC [root: TextEdit.Ref, tSel: Selection] = { caret: TextNode.Location _ InsertionPoint[tSel]; node: TextNode.RefTextNode; where: TextNode.Offset; char: CHAR; IF caret.where=TextNode.NodeItself OR caret.where=0 THEN GOTO Bad; IF (node _ TextNode.NarrowToTextNode[caret.node]) = NIL THEN GOTO Bad; where _ caret.where-1; char _ TextEdit.FetchChar[node,where]; 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]; Deselect[]; [] _ TextEdit.ReplaceByChar[ root: root, dest:node, char:char, start:where, len:1, inherit:FALSE, looks:TextEdit.FetchLooks[node,where], event:TEditInput.currentEvent]; MakePointSelection[tSel, caret]; EXITS Bad => EditFailed[] }; CallWithLocks[DoControlChar] }; MakeControlCharacter: PUBLIC PROC = { ControlChar[TRUE] }; UnMakeControlCharacter: PUBLIC PROC = { ControlChar[FALSE] }; UnMakeOctalCharacter: PUBLIC PROC = { DoUnMakeOctalCharacter: PROC [root: TextEdit.Ref, tSel: Selection] = { caret: TextNode.Location _ InsertionPoint[tSel]; node: TextNode.RefTextNode; char: CARDINAL; IF caret.where=TextNode.NodeItself OR caret.where=0 THEN GOTO Bad; IF (node _ TextNode.NarrowToTextNode[caret.node]) = NIL THEN GOTO Bad; char _ LOOPHOLE[TextEdit.FetchChar[node,caret.where-1]]; BackSpace[1]; InsertChar[char/64 + '0]; InsertChar[(char/8) MOD 8 + '0]; InsertChar[char MOD 8 + '0]; EXITS Bad => EditFailed[] }; CallWithLocks[DoUnMakeOctalCharacter] }; MakeOctalCharacter: PUBLIC PROC = { DoMakeOctalCharacter: PROC [root: TextEdit.Ref, tSel: Selection] = { caret: TextNode.Location _ InsertionPoint[tSel]; node: TextNode.RefTextNode; where: TextNode.Offset; char: CHAR; d: CARDINAL; IF caret.where=TextNode.NodeItself OR caret.where<3 THEN GOTO Bad; IF (node _ TextNode.NarrowToTextNode[caret.node]) = NIL THEN GOTO Bad; where _ caret.where-3; char _ TextEdit.FetchChar[node,where]; IF char NOT IN ['0..'3] THEN GOTO Bad; d _ char-'0; IF (char _ TextEdit.FetchChar[node,where+1]) NOT IN ['0..'7] THEN GOTO Bad; d _ d*8 + char-'0; IF (char _ TextEdit.FetchChar[node,where+2]) NOT IN ['0..'7] THEN GOTO Bad; d _ d*8 + char-'0; Deselect[]; [] _ TextEdit.ReplaceByChar[ root:root, dest:node, char:LOOPHOLE[d], start:where, len:3, inherit:FALSE, looks:TextEdit.FetchLooks[node,where], event:TEditInput.currentEvent]; caret.where _ where+1; MakePointSelection[tSel, caret]; EXITS Bad => EditFailed[] }; CallWithLocks[DoMakeOctalCharacter] }; NameFromRope: PROC [name: Rope.ROPE] RETURNS [NameSymbolTable.Name] = TRUSTED INLINE { RETURN [NameSymbolTable.MakeName[LOOPHOLE[Rope.Flatten[name]]]]}; GetWord: PROC RETURNS [word: Rope.ROPE] = { tSel: Selection; start: TextEdit.Offset; pos: TextNode.Location; node: TextNode.RefTextNode; nChars: CARDINAL _ 0; CaretAfterSelection; pos _ InsertionPoint[]; IF (node _ TextNode.NarrowToTextNode[pos.node])=NIL THEN RETURN [NIL]; IF pos.where = TextNode.NodeItself THEN RETURN [NIL]; start _ pos.where-1; WHILE start>=0 AND RopeEdit.AlphaNumericChar[TextEdit.FetchChar[node,start]] DO 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 _ Alloc[]; TEditSelection.Copy[source: pSel, dest: tSel]; tSel.start.pos _ [node,start]; tSel.end.pos _ [node,start+nChars-1]; tSel.granularity _ char; MakeSelection[tSel, primary]; Free[tSel]; Delete[]; }; SetStyle: PUBLIC PROC = { DoSetStyle: PROC [root: TextEdit.Ref, tSel: Selection] = { name: Rope.ROPE _ GetWord[]; IF name=NIL THEN { EditFailed[]; RETURN }; SetStyleName[name] }; 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.Ref _ NIL] = BEGIN root: TextNode.Ref; IF node=NIL THEN node _ IF pSel.insertion=before THEN pSel.start.pos.node ELSE 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]; END; ReloadStyle: PUBLIC PROC = BEGIN styleName: NodeStyle.Name _ NodeStyle.StyleNameForNode[InsertionPoint[].node]; IF ~NodeStyle.ReloadStyle[styleName] THEN CannotReload[styleName] ELSE ViewerOps.PaintViewer[pSel.viewer, client, FALSE, TEditTouchup.fullUpdate]; END; ReloadStyleName: PUBLIC PROC [name: Rope.ROPE] = BEGIN styleName: NodeStyle.Name; IF Rope.Size[name]=0 THEN RETURN; styleName _ NameFromRope[name]; IF ~NodeStyle.ReloadStyle[styleName] THEN CannotReload[styleName]; END; CannotReload: PROC [styleName: NodeStyle.Name] = { OPEN MessageWindow; Append["Failed in attempt to load style named ", TRUE]; Append[NameSymbolTable.RopeFromName[styleName]]; Blink[] }; SetType: PUBLIC PROC = { DoSetType: PROC [root: TextEdit.Ref, tSel: Selection] = { name: Rope.ROPE _ GetWord[]; IF name=NIL THEN { EditFailed[]; RETURN }; SetTypeName[name] }; CallWithLocks[DoSetType] }; GetType: PUBLIC PROC = { DoGetType: PROC [root: TextEdit.Ref, tSel: Selection] = { name: Rope.ROPE; type: TextNode.TypeName _ InsertionPoint[].node.typename; name _ IF type=TextNode.nullTypeName THEN "default" ELSE NameSymbolTable.RopeFromName[type]; InsertRope[name] }; CallWithLocks[DoGetType] }; TransposeType: PUBLIC PROC [target: SelectionId _ primary] = { <<-- Transpose the types of the primary and secondary selections>> targetSel: Selection _ IF target=primary THEN pSel ELSE sSel; srcSel: Selection _ IF target=primary THEN sSel ELSE pSel; DoTransType: PROC [sourceRoot, destRoot: TextEdit.Ref, tSel, srcSel, targetSel: Selection] = { targetType, srcType: TextNode.TypeName; targetNode, srcNode: TextNode.Ref; srcNode _ IF srcSel.insertion=before THEN srcSel.start.pos.node ELSE srcSel.end.pos.node; srcType _ srcNode.typename; targetNode _ IF targetSel.insertion=before THEN targetSel.start.pos.node ELSE targetSel.end.pos.node; targetType _ targetNode.typename; TEditSelection.Copy[source: targetSel, dest: oldSel]; -- save for Repeat's FOR node: TextNode.Ref _ targetSel.start.pos.node, TextNode.StepForward[node] DO TextEdit.ChangeType[node, srcType, TEditInput.currentEvent, destRoot]; IF node = targetSel.end.pos.node THEN EXIT; ENDLOOP; FOR node: TextNode.Ref _ srcSel.start.pos.node, TextNode.StepForward[node] DO TextEdit.ChangeType[node, targetType, TEditInput.currentEvent, sourceRoot]; IF node = srcSel.end.pos.node THEN EXIT; ENDLOOP; MakeSelection[IF target=primary THEN targetSel ELSE srcSel, primary] }; CallWithBothLocked[DoTransType, targetSel, srcSel, write] }; CopyType: PUBLIC PROCEDURE [target: SelectionId _ primary] = { targetSel: Selection _ IF target=primary THEN pSel ELSE sSel; srcSel: Selection _ IF target=primary THEN sSel ELSE pSel; DoCopyType: PROC [sourceRoot, destRoot: TextEdit.Ref, tSel, srcSel, targetSel: Selection] = { srcNode: TextNode.Ref _ IF srcSel.insertion=before THEN srcSel.start.pos.node ELSE srcSel.end.pos.node; type: TextNode.TypeName _ srcNode.typename; TEditSelection.Copy[source: srcSel, dest: oldSel]; -- save for Repeat's FOR node: TextNode.Ref _ targetSel.start.pos.node, TextNode.StepForward[node] DO TextEdit.ChangeType[node, type, TEditInput.currentEvent, destRoot]; IF node = targetSel.end.pos.node THEN EXIT; ENDLOOP; MakeSelection[IF target=primary THEN targetSel ELSE srcSel, primary] }; CallWithBothLocked[DoCopyType, targetSel, srcSel, read] }; SetTypeName: PUBLIC PROC [name: Rope.ROPE, node: TextNode.Ref _ NIL] = { root: TextNode.Ref; lockSel: BOOL = (node=NIL); type: TextNode.TypeName _ IF name=NIL THEN TextNode.nullTypeName ELSE NameFromRope[ForceLower[name]]; IF lockSel THEN { LockSel[primary, "SetTypeName"]; IF ~CheckReadonly[pSel] OR (root _ SelectionRoot[pSel])=NIL THEN { UnlockSel[primary]; RETURN }; node _ InsertionPoint[].node } ELSE root _ TextNode.Root[node]; { ENABLE UNWIND => IF lockSel THEN UnlockSel[primary]; [] _ TEditLocks.Lock[root, "SetTypeName"]; TextEdit.ChangeType[node, type, TEditInput.currentEvent, root]; TEditLocks.Unlock[root]; IF lockSel THEN UnlockSel[primary] }}; SetSelTypeName: PROC [name: Rope.ROPE, sel: Selection] = { DoSetSelTypeName: PROC [root: TextEdit.Ref, tSel: Selection] = { type: TextNode.TypeName _ IF name=NIL THEN TextNode.nullTypeName ELSE NameFromRope[ForceLower[name]]; FOR node: TextNode.Ref _ tSel.start.pos.node, TextNode.StepForward[node] DO TextEdit.ChangeType[node, type, TEditInput.currentEvent, root]; IF node = tSel.end.pos.node THEN EXIT; ENDLOOP }; CallWithLocks[DoSetSelTypeName] }; SetCommentProp: PUBLIC PROC [flag: BOOLEAN] = { DoSetCommentProp: PROC [root: TextEdit.Ref, tSel: Selection] = { FOR node: TextNode.Ref _ tSel.start.pos.node, TextNode.StepForward[node] DO n: TextNode.RefTextNode _ TextNode.NarrowToTextNode[node]; IF n # NIL THEN TextEdit.PutProp[n, "Comment", IF flag THEN NodeProps.true ELSE NodeProps.false, TEditInput.currentEvent]; IF node = tSel.end.pos.node THEN EXIT; ENDLOOP }; CallWithLocks[DoSetCommentProp] }; abbrevFailedProc: PROC RETURNS [BOOL] _ NIL; RegisterAbbrevFailedProc: PUBLIC PROC [proc: PROC RETURNS [BOOL]] = { abbrevFailedProc _ proc }; ExpandAbbreviation: PUBLIC PROC = { DoExpand: PROC [root: TextEdit.Ref, tSel: Selection] = { pos: TextNode.Location; node: TextNode.RefTextNode; offset: TextEdit.Offset; done, keyDeterminesDict: BOOLEAN _ FALSE; clearedMessageWindow: BOOLEAN _ FALSE; keyStart, keyLen, resultLen: TextEdit.Offset; rdr: RopeReader.Ref; commands: LIST OF REF ANY; styleName: NameSymbolTable.Name; Try: PROC [name: NameSymbolTable.Name] RETURNS [stop: BOOLEAN] = { dict: Rope.ROPE = NameSymbolTable.RopeFromName[name]; [done,keyDeterminesDict,keyStart,keyLen,resultLen,commands] _ AbbrevExpand.Expand[node,offset,dict,TEditInput.currentEvent]; IF ~done AND ~keyDeterminesDict THEN NodeStyleExtra.ForEachAttachedStyle[name,Try]; RETURN [done] }; CaretAfterSelection; pos _ InsertionPoint[]; node _ TextNode.NarrowToTextNode[pos.node]; offset _ pos.where; styleName _ NodeStyle.StyleNameForNode[node]; Deselect[]; IF ~Try[styleName] THEN { OPEN MessageWindow; MakeSelection[tSel, primary]; IF abbrevFailedProc # NIL AND abbrevFailedProc[] THEN RETURN; Append[Rope.Substr[TextEdit.GetRope[node], keyStart, keyLen], ~clearedMessageWindow]; 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 }; 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 MakePointSelection[tSel,[node,keyStart+i]]; FindPlaceholders[TRUE]; EXIT }; ENDLOOP; RopeReader.FreeRopeReader[rdr]; IF commands # NIL THEN TEditInput.Interpret[pSel.viewer, commands] }; 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 OPEN MessageWindow; Append["The file named <", TRUE]; Append[fileName]; Append["> was not found or was not an abbreviation dictionary"] }}; END.