<<-- WordEditImpl.mesa>> <<-- written by Bill Paxton, March 1981>> <<-- last edit by Bill Paxton, May 5, 1982 8:27 am>> DIRECTORY TextEdit, RopeEdit, TextNode; WordEditImpl: CEDAR PROGRAM IMPORTS TextEdit, RopeEdit, TextNode EXPORTS TextEdit = BEGIN OPEN TextEdit; <<-- ***** Word Editing Operations ****>> ReplaceWords: PUBLIC PROC [ destRoot, sourceRoot: Ref, dest: RefTextNode, destStart: Offset _ 0, destLen: Offset _ MaxLen, source: RefTextNode, sourceStart: Offset _ 0, sourceLen: Offset _ MaxLen, event: Event] RETURNS [resultStart, resultLen: Offset] = { <<-- replace the dest words by a copy of the source words>> wantLeading, hasLeading, wantTrailing, hasTrailing: BOOLEAN; destSize, sourceSize: Offset; IF source # NIL THEN { sourceSize _ Size[source]; sourceStart _ MIN[MAX[0,sourceStart],sourceSize]; sourceLen _ MIN[MAX[0,sourceLen],sourceSize-sourceStart] } ELSE sourceSize _ sourceStart _ sourceLen _ 0; destSize _ IF dest=source THEN sourceSize ELSE Size[dest]; destStart _ MIN[MAX[0,destStart],destSize]; destLen _ MIN[MAX[0,destLen],destSize-destStart]; IF destLen=0 AND sourceLen=0 THEN RETURN [destStart,0]; [wantLeading,hasLeading,wantTrailing,hasTrailing] _ CheckSpaces[dest,destStart,destLen,destSize,source,sourceStart,sourceLen]; IF hasTrailing AND ~wantTrailing THEN { -- get rid of trailing space sourceLen _ sourceLen-1; hasTrailing _ FALSE }; IF hasLeading AND ~wantLeading THEN { -- get rid of leading space sourceStart _ sourceStart+1; sourceLen _ sourceLen-1; hasLeading _ FALSE }; [] _ ReplaceText[destRoot,sourceRoot, dest,destStart,destLen,source,sourceStart,sourceLen,event]; resultStart _ destStart; resultLen _ sourceLen + AdjustSpaces[wantLeading,hasLeading,wantTrailing,hasTrailing, dest,destStart,sourceLen,event]; [resultStart,resultLen] _ AdjustResults[dest,resultStart,resultLen] }; DeleteWords: PUBLIC OneSpanProc = <<-- delete the specified words>> { [] _ ReplaceWords[root,NIL,text,start,len,NIL,0,MaxLen,event] }; CopyWords: PUBLIC DestSpanProc = <<-- copy the specified words>> { [resultStart,resultLen] _ ReplaceWords[destRoot,sourceRoot, dest,destLoc,0,source,start,len,event] }; MoveWordsOnto: PUBLIC PROC [ destRoot, sourceRoot: Ref, dest: RefTextNode, destStart: Offset _ 0, destLen: Offset _ MaxLen, source: RefTextNode, sourceStart: Offset _ 0, sourceLen: Offset _ MaxLen, event: Event _ NIL] RETURNS [resultStart, resultLen: Offset] = { sourceSize, destSize, start, len, end, destEnd: Offset; start _ sourceStart; len _ sourceLen; sourceSize _ Size[source]; start _ MIN[MAX[0,start],sourceSize]; len _ MIN[MAX[0,len],sourceSize-start]; end _ start+len; destSize _ IF dest=source THEN sourceSize ELSE Size[dest]; destStart _ MIN[MAX[0,destStart],destSize]; destLen _ MIN[MAX[0,destLen],destSize-destStart]; destEnd _ destStart+destLen; resultStart _ destStart; resultLen _ len; IF source=dest THEN { -- check for overlapping or adjacent IF start IN [destStart..destEnd) THEN { IF end < destEnd THEN [] _ DeleteText[sourceRoot,source,end,destEnd-end,event]; IF start > destStart THEN [] _ DeleteText[sourceRoot,source,destStart,start-destStart,event]; RETURN }; IF end IN (destStart..destEnd) THEN { [] _ DeleteText[sourceRoot,source,end,destEnd-end,event]; RETURN [start,len] }; IF start <= destStart AND end >= destEnd THEN RETURN [start,len]; IF end=destStart THEN { [] _ DeleteText[sourceRoot,source,destStart,destLen,event]; RETURN [start,len] }; IF start=destEnd THEN { [] _ DeleteText[sourceRoot,source,destStart,destLen,event]; RETURN }}; [] _ DeleteText[destRoot,dest,destStart,destLen,event]; IF source=dest AND start > destStart THEN start _ start-destLen; [resultStart,resultLen] _ MoveWords[destRoot,sourceRoot,dest,destStart,source,start,len,event] }; MoveWords: PUBLIC PROC [ destRoot, sourceRoot: Ref, dest: RefTextNode, destLoc: Offset _ 0, source: RefTextNode, start: Offset _ 0, len: Offset _ MaxLen, event: Event] RETURNS [resultStart, resultLen: Offset] = { <<-- move the specified words>> wantLeading, hasLeading, wantTrailing, hasTrailing: BOOLEAN; destSize, sourceSize: Offset; sourceSize _ Size[source]; start _ MIN[MAX[0,start],sourceSize]; len _ MIN[MAX[0,len],sourceSize-start]; IF len=0 THEN RETURN [destLoc,0]; destSize _ IF source=dest THEN sourceSize ELSE Size[dest]; IF source=dest AND destLoc IN [start..start+len] THEN RETURN [start,len]; [wantLeading,hasLeading,wantTrailing,hasTrailing] _ CheckSpaces[dest,destLoc,0,destSize,source,start,len]; IF wantTrailing AND ~hasTrailing AND hasLeading AND ~wantLeading AND start+len < sourceSize AND Fetch[source,start]=Fetch[source,start+len] THEN { start _ start+1; hasLeading _ FALSE; hasTrailing _ TRUE }; IF wantLeading AND ~hasLeading AND hasTrailing AND ~wantTrailing AND start > 0 AND Fetch[source,start-1]=Fetch[source,start+len-1] THEN { start _ start-1; hasLeading _ TRUE; hasTrailing _ FALSE }; [] _ MoveText[destRoot,sourceRoot,dest,destLoc,source,start,len,event]; IF source=dest AND destLoc > start THEN destLoc _ destLoc-len; resultStart _ destLoc; resultLen _ len + AdjustSpaces[wantLeading,hasLeading,wantTrailing,hasTrailing, dest,destLoc,len,event]; [resultStart,resultLen] _ AdjustResults[dest,resultStart,resultLen] }; TransposeWords: PUBLIC PROC [ alphaRoot, betaRoot: Ref, alpha: RefTextNode, alphaStart: Offset _ 0, alphaLen: Offset _ MaxLen, beta: RefTextNode, betaStart: Offset _ 0, betaLen: Offset _ MaxLen, event: Event] RETURNS [alphaResultStart, alphaResultLen, betaResultStart, betaResultLen: Offset] = { <<-- transpose the alpha words and the beta words>> SwitchResults: PROC = { start, len: Offset; start _ betaResultStart; len _ betaResultLen; betaResultStart _ alphaResultStart; betaResultLen _ alphaResultLen; alphaResultStart _ start; alphaResultLen _ len }; wantLeadingAlpha, hasLeadingAlpha, wantTrailingAlpha, hasTrailingAlpha: BOOLEAN; wantLeadingBeta, hasLeadingBeta, wantTrailingBeta, hasTrailingBeta: BOOLEAN; alphaSize, betaSize: Offset; alphaCnt, betaCnt: INTEGER; switched: BOOLEAN _ FALSE; alphaSize _ Size[alpha]; alphaStart _ MIN[MAX[0,alphaStart],alphaSize]; alphaLen _ MIN[MAX[0,alphaLen],alphaSize-alphaStart]; betaSize _ IF beta=alpha THEN alphaSize ELSE Size[beta]; betaStart _ MIN[MAX[0,betaStart],betaSize]; betaLen _ MIN[MAX[0,betaLen],betaSize-betaStart]; IF alpha=beta THEN { alphaEnd: Offset; IF alphaStart > betaStart THEN { -- switch them start: Offset _ alphaStart; len: Offset _ alphaLen; root: Ref _ alphaRoot; alphaStart _ betaStart; betaStart _ start; alphaResultLen _ alphaLen _ betaLen; betaResultLen _ betaLen _ len; alphaRoot _ betaRoot; betaRoot _ root; switched _ TRUE }; alphaEnd _ alphaStart+alphaLen; IF alphaEnd = betaStart THEN { -- turn into a Move instead [betaResultStart,betaResultLen] _ MoveWords[alphaRoot,betaRoot,alpha,alphaStart,alpha,betaStart,betaLen,event]; alphaResultStart _ betaStart+betaResultLen-betaLen; alphaResultLen _ alphaLen; [alphaResultStart,alphaResultLen] _ AdjustResults[alpha,alphaResultStart,alphaResultLen]; IF switched THEN SwitchResults; RETURN }; IF alphaEnd > betaStart THEN { -- overlapping overlap, alphaHeadLen, betaTailLen: Offset; alphaHeadLen _ betaStart-alphaStart; betaTailLen _ betaStart+betaLen-alphaEnd; IF alphaHeadLen < 0 OR betaTailLen < 0 THEN RETURN [alphaStart,alphaLen,betaStart,betaLen]; overlap _ alphaEnd-betaStart; [alphaResultStart,alphaResultLen,betaResultStart,betaResultLen] _ TransposeWords[alphaRoot,betaRoot,alpha,alphaStart,alphaHeadLen, alpha,alphaEnd,betaTailLen,event]; betaResultLen _ betaResultLen+overlap; alphaResultStart _ alphaResultStart-overlap; alphaResultLen _ alphaResultLen+overlap; IF switched THEN SwitchResults; RETURN }}; [wantLeadingAlpha,hasLeadingAlpha,wantTrailingAlpha,hasTrailingAlpha] _ CheckSpaces[alpha,alphaStart,alphaLen,alphaSize,beta,betaStart,betaLen]; [wantLeadingBeta,hasLeadingBeta,wantTrailingBeta,hasTrailingBeta] _ CheckSpaces[beta, betaStart,betaLen,betaSize,alpha,alphaStart,alphaLen]; [] _ TransposeText[alphaRoot,betaRoot,alpha,alphaStart,alphaLen,beta,betaStart,betaLen,event]; betaCnt _ AdjustSpaces[ wantLeadingAlpha,hasLeadingAlpha,wantTrailingAlpha,hasTrailingAlpha, alpha,alphaStart,betaLen,event]; IF alpha=beta THEN betaStart _ betaStart+betaLen-alphaLen+betaCnt; alphaCnt _ AdjustSpaces[wantLeadingBeta,hasLeadingBeta,wantTrailingBeta,hasTrailingBeta, beta,betaStart,alphaLen,event]; alphaResultStart _ betaStart; alphaResultLen _ alphaLen+alphaCnt; [alphaResultStart,alphaResultLen] _ AdjustResults[beta,alphaResultStart,alphaResultLen]; betaResultStart _ alphaStart; betaResultLen _ betaLen+betaCnt; [betaResultStart,betaResultLen] _ AdjustResults[alpha,betaResultStart,betaResultLen]; IF switched THEN SwitchResults }; CheckSpaces: PROC [dest: RefTextNode, destStart, destLen, destSize: Offset, source: RefTextNode, sourceStart, sourceLen: Offset] RETURNS [wantLeading, hasLeading, wantTrailing, hasTrailing: BOOLEAN] = { wantLeading _ WantLeadingSpace[dest,destStart]; wantTrailing _ WantTrailingSpace[dest,destStart+destLen,destSize]; hasLeading _ HasLeadingSpace[source,sourceStart,sourceLen]; hasTrailing _ HasTrailingSpace[source,sourceStart,sourceLen] }; AdjustSpaces: PROC [wantLeading, hasLeading, wantTrailing, hasTrailing: BOOLEAN, dest: RefTextNode, start, len: Offset, event: Event] RETURNS [cnt: INTEGER] = { root: Ref = TextNode.Root[dest]; cnt _ 0; IF hasTrailing AND ~wantTrailing THEN { [] _ DeleteText[root,dest,start+len-1,1,event]; cnt_cnt-1 }; IF ~hasTrailing AND wantTrailing THEN { [] _ InsertChar[root,dest,' ,start+len,TRUE,noLooks,event]; cnt_cnt+1 }; IF hasLeading AND ~wantLeading THEN { [] _ DeleteText[root,dest,start,1,event]; cnt_cnt-1 }; IF ~hasLeading AND wantLeading THEN { [] _ InsertChar[root,dest,' ,start,TRUE,noLooks,event]; cnt_cnt+1 }}; WantLeadingSpace: PROC [dest: RefTextNode, destStart: Offset] RETURNS [BOOLEAN] = INLINE { <<-- returns true if char before destStart is a letter/digit>> RETURN [destStart > 0 AND RopeEdit.AlphaNumericChar[FetchChar[dest,destStart-1]]] }; WantTrailingSpace: PROC [dest: RefTextNode, destEnd, destSize: Offset] RETURNS [BOOLEAN] = INLINE { <<-- returns true if char after destEnd is a letter/digit>> RETURN [destEnd < destSize AND RopeEdit.AlphaNumericChar[FetchChar[dest,destEnd]]] }; HasLeadingSpace: PROC [source: RefTextNode, start, len: Offset] RETURNS [BOOLEAN] = INLINE { RETURN [len > 0 AND RopeEdit.BlankChar[FetchChar[source,start]]] }; HasTrailingSpace: PROC [source: RefTextNode, start, len: Offset] RETURNS [BOOLEAN] = INLINE { RETURN [len > 0 AND RopeEdit.BlankChar[FetchChar[source,start+len-1]]] }; HasFollowingSpace: PROC [source: RefTextNode, end, size: Offset] RETURNS [BOOLEAN] = INLINE { RETURN [end < size AND RopeEdit.BlankChar[FetchChar[source,end]]] }; HasPreceedingSpace: PROC [source: RefTextNode, start: Offset] RETURNS [BOOLEAN] = INLINE { RETURN [start > 0 AND RopeEdit.BlankChar[FetchChar[source,start-1]]] }; AdjustResults: PROC [dest: RefTextNode, start, len: Offset] RETURNS [resultStart, resultLen: Offset] = { size: Offset _ Size[dest]; following: BOOLEAN _ HasFollowingSpace[dest,start+len,size]; preceeding: BOOLEAN _ HasPreceedingSpace[dest,start]; leading: BOOLEAN _ HasLeadingSpace[dest,start,size]; trailing: BOOLEAN _ HasTrailingSpace[dest,start,len]; resultStart _ start; resultLen _ len; IF leading THEN IF trailing THEN { resultLen _ resultLen-1; resultStart _ resultStart+1 } ELSE IF following THEN resultStart _ resultStart+1 ELSE NULL ELSE IF ~trailing THEN IF following THEN resultLen _ resultLen+1 ELSE IF preceeding THEN { resultStart _ resultStart-1; resultLen _ resultLen+1 } ELSE NULL ELSE NULL }; END.