<> <> <> DIRECTORY Basics, Rope, RuntimeError, TextNode, TiogaRopes; TiogaRopesImpl: CEDAR PROGRAM IMPORTS Rope, RuntimeError, TextNode EXPORTS TiogaRopes = BEGIN OPEN TiogaRopes; Location: TYPE = TextNode.Location; TiogaRope: TYPE = REF TiogaRopePrivate; TiogaRopePrivate: TYPE = RECORD [ node: Node, start, length: INT, skipCommentNode: BOOL, curNode: Node _ NIL, curNodeStart, curNodeLength: INT _ 0, curRope: ROPE ]; RopeFromTioga: PUBLIC PROC [node: Node, start: INT _ 0, length: INT _ LAST[INT], skipCommentNode: BOOL _ FALSE] RETURNS [asRope: ROPE] = { end: Location = DocEnd[node, skipCommentNode]; nodeLoc: Location = [node, 0]; remSize: INT = TextNode.LocOffset[nodeLoc, end, 1, skipCommentNode]; IF start >= remSize THEN RETURN [NIL]; {curRope: ROPE = node.NodeRope[]; tr: TiogaRope = NEW [TiogaRopePrivate _ [ node: node, start: start, length: MIN[length, remSize - start], skipCommentNode: skipCommentNode, curNode: node, curNodeStart: 0, curNodeLength: curRope.Length[], curRope: curRope ]]; asRope _ Rope.MakeRope[tr, tr.length, FetchFromTiogaRope, NIL, MoveFromTiogaRope]; }}; JumpTo: PROC [tr: TiogaRope, index: INT] = { newOffset: INT = tr.start+index; here: Location = IF newOffset >= tr.curNodeStart/2 THEN LocRelative[[tr.curNode, 0], newOffset-tr.curNodeStart, 1, tr.skipCommentNode] ELSE LocRelative[[tr.node, 0], newOffset, 1, tr.skipCommentNode]; tr.curNode _ here.node; tr.curNodeStart _ newOffset - here.where; tr.curRope _ TextNode.NodeRope[tr.curNode]; tr.curNodeLength _ tr.curRope.Length[]; }; LocRelative: PROC [location: Location, count: INT, break: NAT _ 1, skipCommentNodes: BOOL _ FALSE] RETURNS [rel: Location] = { SELECT count FROM =0 => rel _ location --avoid the bogosity in TextNodeImpl.LocRelative--; >0 => rel _ TextNode.LocRelative[location, count, break, skipCommentNodes]; <0 => {--TextNodeImpl.LocRelative won't backup over node boundaries backParent: Node _ NIL; rel _ location; WHILE count + rel.where < 0 DO count _ count + rel.where; [rel.node, backParent, ] _ TextNode.Backward[rel.node, backParent]; rel.where _ IF (NOT skipCommentNodes) OR (NOT rel.node.comment) THEN rel.node.rope.Length[] + break ELSE 0; ENDLOOP; rel.where _ count + rel.where; }; ENDCASE => ERROR; rel _ rel; }; FetchFromTiogaRope: PROC [data: REF, index: INT] RETURNS [CHAR] --Rope.FetchType-- = { tr: TiogaRope = NARROW[data]; IF NOT index IN [0 .. tr.length) THEN ERROR RuntimeError.BoundsFault; {rel: INT _ index+tr.start - tr.curNodeStart; {IF rel<0 THEN GOTO Fixit; SELECT tr.curNodeLength FROM >rel => GOTO TakeIt; =rel => RETURN ['\n]; ENDCASE => GOTO Fixit; EXITS Fixit => { JumpTo[tr, index]; rel _ index+tr.start - tr.curNodeStart; IF rel=tr.curNodeLength THEN RETURN ['\n]}; TakeIt => NULL}; RETURN [tr.curRope.InlineFetch[rel]]}}; MoveFromTiogaRope: UNSAFE PROC [block: Basics.UnsafeBlock, data: REF ANY, start: INT] RETURNS [charsMoved: INT _ 0] ~ CHECKED { tr: TiogaRope = NARROW[data]; IF NOT start IN [0 .. tr.length) THEN ERROR RuntimeError.BoundsFault; WHILE block.count>0 DO rel: INT _ start + tr.start - tr.curNodeStart; IF rel NOT IN [0 .. tr.curNodeLength] THEN {JumpTo[tr, start]; rel _ start + tr.start - tr.curNodeStart}; IF rel < tr.curNodeLength THEN { n: INT; TRUSTED {n _ Rope.UnsafeMoveChars[block: block, rope: tr.curRope, start: rel]}; start _ start + n; charsMoved _ charsMoved + n; block.startIndex _ block.startIndex + n; block.count _ block.count - n; }; IF block.count # 0 THEN { TRUSTED {LOOPHOLE[block.base, LONG POINTER TO Basics.RawChars][block.startIndex] _ '\n}; start _ start + 1; charsMoved _ charsMoved + 1; block.startIndex _ block.startIndex + 1; block.count _ block.count - 1; }; ENDLOOP; RETURN}; DocEnd: PROC [node: Node, skipCommentNode: BOOL] RETURNS [endLoc: Location] = { endNode: Node _ TextNode.Root[node]; IF endNode = NIL THEN ERROR; DO next: Node _ TextNode.LastChild[endNode]; IF next = NIL THEN EXIT; endNode _ next; ENDLOOP; IF skipCommentNode THEN WHILE endNode.comment DO endNode _ TextNode.StepBackward[endNode] ENDLOOP; endLoc _ [endNode, TextNode.NodeRope[endNode].Length[]+1]; }; END.