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: ROPENIL] = {
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