RopeEditImpl.mesa
Copyright © 1985, 1986 by Xerox Corporation. All rights reserved.
written by Bill Paxton, February 1981
Paxton, October 29, 1982 8:45 am
Maxwell, January 5, 1983 11:57 am
Russ Atkinson, March 13, 1985 9:21:40 pm PST
Paul Rovner, August 10, 1983 4:20 pm
Michael Plass, April 7, 1986 9:23:33 am PST
Doug Wyatt, September 3, 1986 3:53:29 pm PDT
DIRECTORY
Ascii USING [CR, SP, TAB],
FS USING [defaultStreamOptions, Open, OpenFile, StreamFromOpenFile, StreamOpen, StreamOptions],
IO USING [Close, PutRope, SetIndex, SetLength, STREAM],
Rope USING [Concat, Fetch, FromChar, FromProc, InlineSize, MaxLen, Replace, ROPE, Size, Substr],
RopeEdit USING [CharPropertyTable],
RopeFile USING [FromStream],
RopeIO USING [],
RopePrivate USING [InlineDepth];
RopeEditImpl:
CEDAR
PROGRAM
IMPORTS FS, IO, Rope, RopePrivate, RopeFile
EXPORTS RopeEdit, RopeIO
SHARES Rope
= BEGIN OPEN RopeEdit;
ROPE: TYPE = Rope.ROPE;
MaxLen: INT = Rope.MaxLen;
Depth:
PUBLIC
PROC [rope:
ROPE]
RETURNS [depth:
INTEGER] = {
RETURN [RopePrivate.InlineDepth[rope]]
};
Editing operations
Substr:
PUBLIC
PROC [base:
ROPE, start:
INT ← 0, len:
INT ← MaxLen]
RETURNS [
ROPE] = {
RETURN [Rope.Substr[base: base, start: start, len: len]];
Concat:
PUBLIC
PROC [base, rest:
ROPE, baseLen, restLen:
INT ← MaxLen]
RETURNS [new:
ROPE] = {
IF Rope.Size[rest] > restLen THEN rest ← Rope.Substr[base: rest, start: 0, len: restLen];
IF Rope.Size[base] > baseLen THEN base ← Rope.Substr[base: base, start: 0, len: baseLen];
RETURN [Rope.Concat[base, rest]];
Copy:
PUBLIC
PROC [dest:
ROPE, destLoc:
INT, source:
ROPE, start:
INT, len:
INT, destSize:
INT]
RETURNS [
ROPE] = {
IF destLoc > destSize THEN destLoc ← destSize;
RETURN [
Replace[base: dest, start: destLoc, len: 0, replace: Substr[source, start, len], baseSize: destSize, repSize: len]
]
};
Delete:
PUBLIC
PROC [base:
ROPE, start, len, baseSize:
INT]
RETURNS [
ROPE] = {
RETURN [Replace[base, start, len, NIL, baseSize, 0]];
};
Insert:
PUBLIC
PROC [dest:
ROPE, destLoc:
INT ← 0, source:
ROPE, destSize, sourceSize:
INT ← MaxLen]
RETURNS [
ROPE] = {
RETURN [Replace[dest, destLoc, 0, source, destSize, sourceSize]];
};
AppendChar:
PUBLIC
PROC [base:
ROPE, char:
CHAR, baseSize:
INT ← MaxLen]
RETURNS [
ROPE]
= {
RETURN [ReplaceByChar[base, char, MaxLen, 0, baseSize]];
};
InsertChar:
PUBLIC
PROC [base:
ROPE, char:
CHAR, loc:
INT ← 0, baseSize:
INT ← MaxLen]
RETURNS [
ROPE] = {
RETURN [ReplaceByChar[base, char, loc, 0, baseSize]];
};
**** IO Operations ****
PutRope:
PUBLIC
PROC [stream:
IO.STREAM, rope:
ROPE] = {
IO.PutRope[stream, rope];
};
GetRope:
PUBLIC
PROC [stream:
IO.STREAM, len:
INT ← MaxLen]
RETURNS [
ROPE] = {
RETURN [RopeFile.FromStream[stream, 0, len]];
};
**** Filing Operations ****
ToFile:
PUBLIC
PROC [fileName, rope:
ROPE, start:
INT ← 0] = {
WriteFile[FS.StreamOpen[fileName, $create], rope, start];
};
ToFileC:
PUBLIC
PROC [openFile:
FS.OpenFile, rope:
ROPE, start:
INT ← 0] = {
WriteFile[FS.StreamFromOpenFile[openFile, $write], rope, start];
};
WriteFile:
PROC [stream:
IO.STREAM, rope:
ROPE, start:
INT] = {
IO.SetLength[stream, start];
IO.SetIndex[stream, start];
PutRope[stream, rope];
IO.Close[stream];
};
FromFile:
PUBLIC
PROC [fileName:
ROPE, start:
INT ← 0, len:
INT ← MaxLen]
RETURNS [
ROPE] = {
openFile: FS.OpenFile ~ FS.Open[fileName, $read];
RETURN[FromFileC[openFile, start, len]];
};
BufferStrategyProc:
TYPE ~
PROC [len:
INT]
RETURNS [
pagesPerStreamBuffer: INT,
streamBuffers: INT,
ropeBufSize: INT,
ropeBuffers: INT
];
BufferStrategy: BufferStrategyProc ← DefaultBufferStrategy;
Supply a new one of these to experiment with different buffering strategies;
DefaultBufferStrategy: BufferStrategyProc ~ {
pagesPerStreamBuffer ← defaultPagesPerStreamBuffer;
streamBuffers ← defaultStreamBuffers;
ropeBufSize ← defaultRopeBufSize;
ropeBuffers ← defaultRopeBuffers;
};
These parameters are here to encorage experimentation. However, don't set them to unreasonable values or you will be sorry!
defaultPagesPerStreamBuffer: NAT ← 4;
defaultStreamBuffers: NAT ← 2;
defaultRopeBufSize: NAT ← 512;
defaultRopeBuffers: NAT ← 4;
FromFileC:
PUBLIC
PROC [openFile:
FS.OpenFile, start:
INT ← 0, len:
INT ← MaxLen]
RETURNS [
ROPE] = {
stream: IO.STREAM;
pagesPerStreamBuffer: INT;
streamBuffers: INT;
ropeBufSize: INT;
ropeBuffers: INT;
options: FS.StreamOptions ← FS.defaultStreamOptions;
options[tiogaRead] ← FALSE; -- include the formatting information
options[closeFSOpenFileOnClose] ← FALSE; -- don't close the openFile
[pagesPerStreamBuffer, streamBuffers, ropeBufSize, ropeBuffers] ← BufferStrategy[len];
stream ←
FS.StreamFromOpenFile[
openFile: openFile, accessRights: $read, streamOptions: options,
streamBufferParms: [vmPagesPerBuffer: pagesPerStreamBuffer, nBuffers: streamBuffers]
];
RETURN [RopeFile.FromStream[stream: stream, start: start, len: len, bufSize: ropeBufSize, buffers: ropeBuffers]];
};
***** Replace Operations
ReplaceByChar:
PUBLIC
PROC [base:
ROPE, char:
CHAR, start:
INT, len:
INT, baseSize:
INT]
RETURNS [new:
ROPE] = {
new ← Replace[base: base, start: start, len: len, replace: Rope.FromChar[char], baseSize: baseSize, repSize: MaxLen];
ReplaceByTEXT:
PUBLIC
PROC [base:
ROPE, text:
REF
READONLY
TEXT, textStart:
NAT, textSize:
NAT, start:
INT, len:
INT, baseSize:
INT]
RETURNS [new:
ROPE ←
NIL] = {
Chars: PROC RETURNS [CHAR] ~ {c: CHAR ← text[i]; i ← i + 1; RETURN [c]};
i: NAT ← textStart ← MIN[text.length, textStart];
textSize ← MIN[text.length-textStart, textSize];
IF baseSize < Rope.InlineSize[base] THEN base ← Rope.Substr[base, 0, baseSize];
new ← Rope.Replace[base, start, len, Rope.FromProc[textSize, Chars]];
Replace:
PUBLIC
PROC [base:
ROPE, start:
INT, len:
INT, replace:
ROPE, baseSize:
INT, repSize:
INT]
RETURNS [new:
ROPE] = {
IF baseSize < Rope.Size[base] THEN base ← Rope.Substr[base: base, start: 0, len: baseSize];
IF repSize < Rope.Size[replace] THEN replace ← Rope.Substr[replace, 0, repSize];
new ← Rope.Replace[base: base, start: start, len: len, with: replace];
***** Initialization
punctuationString: ROPE ← "!@#$%~&*()-—`=+[{]};:'"",.<>/?\\|←^";
charPropertyTable: PUBLIC REF READONLY CharPropertyTable ← InitCharPropertyTable[];
LegalCharacters: TYPE = CHAR[0C..177C];
InitCharPropertyTable:
PROC
RETURNS [
REF CharPropertyTable] = {
cpt: REF CharPropertyTable ← NEW[CharPropertyTable];
FOR ch: CHAR IN CHAR DO cpt[ch] ← illegal; ENDLOOP;
FOR ch: CHAR IN LegalCharacters DO cpt[ch] ← alphaNumeric; ENDLOOP;
cpt[Ascii.TAB] ← white;
cpt[Ascii.SP] ← white;
cpt[Ascii.CR] ← white;
cpt[140C] ← punctuation;
TRUSTED {
FOR i:
INT
IN [0 .. Rope.Size[punctuationString])
DO
cpt[Rope.Fetch[punctuationString, i]] ← punctuation;
ENDLOOP
};
RETURN[cpt];
};
END.
Plass, February 14, 1985 5:16:16 pm PST
Simplified RopeEditReplaceImpl ruthlessly, pending evidence that the old mess was needed.
changes to: ReplaceByChar, ReplaceByString, Replace
Plass, February 14, 1985 3:31:52 pm PST
Replaced procedure bodies with simple ones, pending evidence that the complicated stuff is really needed
changes to: Depth, Substr, Concat, Copy, SemiFlatten, RopeStats, PutRope, punctuationString(added "—"), END
Plass, February 15, 1985 4:08:45 pm PST
Merged in RopeEditReplaceImpl
Plass, March 1, 1985 1:16:06 pm PST
Cedar 6.0 cleanup. Removed RopeFrom usage, many INLINES, renamed ReplaceByString to ReplaceByTEXT