Skip to content

cupertino-files / TextStorage

Class: TextStorage ​

Defined in: src/tswp/textstorage.ts:212

Constructors ​

Constructor ​

new TextStorage(store, object): TextStorage

Defined in: src/tswp/textstorage.ts:216

Parameters ​

store ​

ObjectStore

object ​

IwaObject

Returns ​

TextStorage

Properties ​

object ​

readonly object: IwaObject

Defined in: src/tswp/textstorage.ts:214


store ​

readonly store: ObjectStore

Defined in: src/tswp/textstorage.ts:213

Accessors ​

endsWithEmptyParagraph ​

Get Signature ​

get endsWithEmptyParagraph(): boolean

Defined in: src/tswp/textstorage.ts:813

True when the text ends with a paragraph terminator, so the app draws one more, empty paragraph after the last one paragraphs lists.

Both tail states are the apps' own. Of the corpus's 26 body storages, 15 end bare — the shape typing leaves, and what a current Pages saves for a document whose last paragraph was typed, not returned past — 8 end with a terminator and carry the paragraph-style entry at text.length for the phantom paragraph, and 3 are empty. A built document that should not show a stray final line wants the bare shape; normalizeTail produces it, keeping every attribute table lawful on the way.

Returns ​

boolean


id ​

Get Signature ​

get id(): bigint

Defined in: src/tswp/textstorage.ts:221

Returns ​

bigint


kind ​

Get Signature ​

get kind(): number

Defined in: src/tswp/textstorage.ts:259

Returns ​

number


revision ​

Get Signature ​

get revision(): number

Defined in: src/tswp/textstorage.ts:247

Edit count; pair with offsetsStableSince for staleness checks.

Returns ​

number


stylesheetId ​

Get Signature ​

get stylesheetId(): bigint | undefined

Defined in: src/tswp/textstorage.ts:264

Identifier of the TSS.StylesheetArchive governing this storage.

Returns ​

bigint | undefined


text ​

Get Signature ​

get text(): string

Defined in: src/tswp/textstorage.ts:292

Returns ​

string

Methods ​

addBookmark() ​

addBookmark(start, end, name?): bigint

Defined in: src/tswp/textstorage.ts:1714

Mark [start, end) as a bookmark — a named destination a link can target.

A bookmark with no name is what the apps create for a link pointing at a stretch of text rather than a named place; both shapes occur in the corpus and both are written here.

Parameters ​

start ​

number

end ​

number

name? ​

string

Returns ​

bigint


addComment() ​

addComment(start, end, text, options?): bigint

Defined in: src/tswp/textstorage.ts:1818

Attach a comment to [start, end).

Creates the three objects a comment needs — highlight, comment storage, author — and spans the highlight over the range, which is what makes the words show highlighted. The author is reused by default: a document where every comment has its own copy of the same person is not what the apps produce.

Returns the comment storage's identifier, which removeComment takes.

Parameters ​

start ​

number

end ​

number

text ​

string

options? ​

AddCommentOptions = {}

Returns ​

bigint


addFootnote() ​

addFootnote(pos, text, options?): TextStorage

Defined in: src/tswp/textstorage.ts:1364

Add a footnote anchored at pos, with text as its content.

A footnote is two storages, not one: this one gains a U+000E reference character, and a new storage of kind FOOTNOTE holds the note itself. That note's text starts with its own U+FFFC placeholder — the spot where the app draws the footnote's number — so the note reads "<mark> your text", exactly as Apple writes it.

Numbering is not set here. Which number a footnote gets depends on how many precede it and on the document's numbering settings, both of which the app resolves when it lays the document out.

Returns the new footnote storage, so its text can be styled or edited like any other.

Parameters ​

pos ​

number

text ​

string

options? ​
markStyle? ​

bigint | false

Returns ​

TextStorage


appendParagraph() ​

appendParagraph(text, listStyle?): number

Defined in: src/tswp/textstorage.ts:770

Append a paragraph, preserving the file's trailing-newline convention. Returns the new paragraph's index.

The new paragraph states its own list membership rather than inheriting the previous one's: attribute tables are read as runs, so one bulleted paragraph would otherwise turn every later append into a list item — invisibly, because membership lives in the list table and not in the paragraph style. Apple writes the same statement, with a list style named "None" (222 of 222 corpus list-table entries name a style; 82 name that one). Pass a list style to opt in, or call setListStyle afterwards.

Character styling ends at the same seam: a character-style run open at the end of the text is closed before the new paragraph is inserted, so a styled last line never bleeds into what is appended after it. Raw insertText/replaceRange keep the typing model — text inserted inside or at the edge of a run takes the run's style.

Writing direction is stated the same way: when the storage has a bidi table, the new paragraph gets its own pair, copying the baseline at position 0 — 2594 of the corpus's 2896 bidi-bearing storages cover every paragraph start, and an open-ended RTL entry appears only where no paragraph follows it. Without the statement one flipped paragraph turns every later append RTL.

Parameters ​

text ​

string

listStyle? ​

bigint

Returns ​

number


applyEdits() ​

applyEdits(edits): void

Defined in: src/tswp/textstorage.ts:703

Apply several non-overlapping edits from one snapshot of the text.

Every edit's offsets refer to the text as it is now: the batch is sorted descending internally, so no edit shifts another's offsets and callers need no re-reading discipline between spans. Overlapping edits are refused before anything is written. An omitted replacement deletes the range.

Parameters ​

edits ​

readonly object[]

Returns ​

void


attachments() ​

attachments(): object[]

Defined in: src/tswp/textstorage.ts:1261

Inline attachment runs: page numbers, page counts, footnote marks and anchored drawables, each at its U+FFFC character.

Returns ​

object[]


bookmarks() ​

bookmarks(): object[]

Defined in: src/tswp/textstorage.ts:1735

Bookmarks anchored in this storage (named destinations).

Returns ​

object[]


characterFormattingAt() ​

characterFormattingAt(pos): CharacterFormatting

Defined in: src/tswp/textstorage.ts:404

The formatting in effect at pos, with inheritance folded in: the paragraph style's character bag as the base, the character-style chain's values on top — id in, effective CharacterFormatting out, no schema knowledge needed.

Parameters ​

pos ​

number

Returns ​

CharacterFormatting


characterStyleIdAt() ​

characterStyleIdAt(pos): bigint | undefined

Defined in: src/tswp/textstorage.ts:394

The character style ruling pos, or undefined when no direct character styling applies there and the paragraph style alone rules — the normal state of most text. Resolve a name with styleNameOf.

Parameters ​

pos ​

number

Returns ​

bigint | undefined


characterStyleRuns() ​

characterStyleRuns(): StyleRun[]

Defined in: src/tswp/textstorage.ts:891

Character-style runs (undefined objectId = paragraph style applies).

Returns ​

StyleRun[]


comments() ​

comments(): CommentInfo[]

Defined in: src/tswp/textstorage.ts:1776

Comments anchored in this storage (from both anchor tables).

Returns ​

CommentInfo[]


copyShapeFrom() ​

copyShapeFrom(sibling): void

Defined in: src/tswp/textstorage.ts:904

Adopt a sibling storage's attribute shape: its paragraph style, and its character-table and language entries when it has them. This is how text written into one of a page master's always-empty header/footer storages becomes drawable — the bare default shape those storages carry is one the app never draws from, while every rendered corpus header/footer storage states its own paragraph style with the char-style table or the language table beside it.

Parameters ​

sibling ​

TextStorage

Returns ​

void


dateFields() ​

dateFields(): object[]

Defined in: src/tswp/textstorage.ts:1547

The date fields in this storage, with their settings.

Returns ​

object[]


defineAsPlaceholder() ​

defineAsPlaceholder(start, end): bigint

Defined in: src/tswp/textstorage.ts:1695

Mark [start, end) as placeholder text, the way Format → Advanced → Define as Placeholder Text does: a click in the app selects the whole span and typing replaces it. Any smart field already on the span is replaced, like inserting any other field. Returns the field's id.

Parameters ​

start ​

number

end ​

number

Returns ​

bigint


deleteRange() ​

deleteRange(start, end): void

Defined in: src/tswp/textstorage.ts:690

Parameters ​

start ​

number

end ​

number

Returns ​

void


effectiveObjectAt() ​

effectiveObjectAt(tableField, pos): bigint | undefined

Defined in: src/tswp/textstorage.ts:424

Effective object id at a position — the last value set at or before pos in the given attribute table.

tableField is a Storage.* field number (e.g. Storage.TABLE_CHAR_STYLE), not a name. undefined means no run entry rules the position: for the character table that is "no direct character styling here — the paragraph style alone applies", which is the normal state of most text, not an error.

Parameters ​

tableField ​

number

pos ​

number

Returns ​

bigint | undefined


ensureTrailingParagraphEntry() ​

ensureTrailingParagraphEntry(): void

Defined in: src/tswp/textstorage.ts:674

Restore the phantom-paragraph invariant: a text ending with a terminator carries a paragraph-style entry at text.length for the empty paragraph the app draws there (31 of 31 corpus body storages; the entry names no style). Pages refuses a file with the terminator and no entry. Idempotent; a no-op when the text ends mid-paragraph.

Returns ​

void


fillPlaceholder() ​

fillPlaceholder(placeholder, text): object

Defined in: src/tswp/textstorage.ts:1662

Fill a placeholder: put real text in its span and shed the placeholder marking, which is what typing into one does in Pages. The replacement keeps the placeholder's styling — a template styles its ghost text the way the final content should look. Returns the filled span.

Address the placeholder by its fieldId — the id placeholders reports, passed bare or on the listing's own entry — and the span is resolved live at this call: filling several from one listing lands each in its own field no matter how earlier fills moved the text. A filled or removed field throws rather than editing whatever text now occupies its old offsets. An entry carrying only start/end keeps positional meaning, offsets against the text as it is now.

Parameters ​

placeholder ​

bigint | { end: number; fieldId?: bigint; start: number; }

text ​

string

Returns ​

object

end ​

end: number

start ​

start: number


find() ​

find(pattern): TextRange[]

Defined in: src/tswp/textstorage.ts:1032

Find matches as fluent ranges (string = literal; RegExp honored with /g).

Parameters ​

pattern ​

string | RegExp

Returns ​

TextRange[]


footnotes() ​

footnotes(): object[]

Defined in: src/tswp/textstorage.ts:1754

Footnotes/endnotes anchored in this storage (their text is editable).

Returns ​

object[]


insertAttachment() ​

insertAttachment(pos, objectId): void

Defined in: src/tswp/textstorage.ts:1313

Put an existing attachment archive at pos.

Inserts the U+FFFC placeholder through replaceRange, so every other attribute table shifts with it, then anchors the attachment at the new character. Doing it the other way round leaves the entry pointing one character short.

Parameters ​

pos ​

number

objectId ​

bigint

Returns ​

void


insertDateField() ​

insertDateField(pos, text, options?): bigint

Defined in: src/tswp/textstorage.ts:1530

Insert a live date field showing text.

Unlike a page number, a date field spans real characters: the text is in the storage and the app rewrites it when the field updates. So the text to show is supplied rather than rendered here — formatting a date the way a given locale and pattern would is Foundation's job, and approximating it would put subtly wrong text in the document. The field is marked as needing an update, so the app replaces it with its own rendering at the first opportunity.

Parameters ​

pos ​

number

text ​

string

options? ​

DateFieldOptions = {}

Returns ​

bigint


insertLink(start, end, url, options?): bigint

Defined in: src/tswp/textstorage.ts:1118

Make [start, end) a hyperlink. Creates a TSWP.HyperlinkFieldArchive in this storage's component and spans it in the smart-field table.

The link also gets the document's Link character style — identifier character-style-hyperlink, name "Link", property bag {underline: 1} in every native Pages fixture that carries links, and shipped by every template in the corpus. The hyperlink works without it (the first in-app check clicked through fine) and does not look like one: the field makes it live, the style makes it underlined.

characterStyle overrides the convention: a style id or identifier applies that style instead; false leaves the run unstyled — the text keeps whatever formatting it had.

Parameters ​

start ​

number

end ​

number

url ​

string

options? ​
characterStyle? ​

string | bigint | false

Returns ​

bigint


insertPageCount() ​

insertPageCount(pos, options?): bigint

Defined in: src/tswp/textstorage.ts:1301

Insert a live page count — "of 12" — at pos.

Parameters ​

pos ​

number

options? ​

NumberAttachmentOptions = {}

Returns ​

bigint


insertPageNumber() ​

insertPageNumber(pos, options?): bigint

Defined in: src/tswp/textstorage.ts:1292

Insert a live page number (or page count) at pos.

A page number is not text: no digits exist in the storage, because the value depends on pagination the app performs. What is inserted is a U+FFFC placeholder plus an attachment archive that renders it — which is why this cannot simply be insertText("1").

Returns the attachment's object identifier. Nothing here computes the number; the app fills it in when it lays the document out.

Parameters ​

pos ​

number

options? ​

NumberAttachmentOptions = {}

Returns ​

bigint


insertText() ​

insertText(pos, text): void

Defined in: src/tswp/textstorage.ts:686

Parameters ​

pos ​

number

text ​

string

Returns ​

void


links(): object[]

Defined in: src/tswp/textstorage.ts:1091

Hyperlink runs in this storage.

Returns ​

object[]


listStyleIdAt() ​

listStyleIdAt(paragraphIndex): bigint | undefined

Defined in: src/tswp/textstorage.ts:1058

Effective list-style object id of a paragraph.

Parameters ​

paragraphIndex ​

number

Returns ​

bigint | undefined


normalizeTail() ​

normalizeTail(): boolean

Defined in: src/tswp/textstorage.ts:831

Delete a final trailing \n terminator so the text ends the way typed text does — bare, with no empty paragraph drawn after the last line. The phantom paragraph's table entries go with it and any character-style run or smart field ending at the old terminator stays closed exactly where its text ends.

Idempotent. A no-op on empty text, a bare tail, or a tail ending with a section, layout or page break — those characters carry structure this call must not remove, and no corpus storage ends with one (all 32 terminator-ending tails are U+000A). Returns whether a terminator was removed.

Returns ​

boolean


objectRuns() ​

objectRuns(tableField, textLength?): StyleRun[]

Defined in: src/tswp/textstorage.ts:340

Decode an object table into runs. objectId undefined covers both "no attribute" and "continues previous" — for paragraph-aligned tables the effective value carries forward (see paragraphValues).

Parameters ​

tableField ​

number

textLength? ​

number = ...

Returns ​

StyleRun[]


offsetsStableSince() ​

offsetsStableSince(revision, end): boolean

Defined in: src/tswp/textstorage.ts:252

True when every edit made after revision began at or after end.

Parameters ​

revision ​

number

end ​

number

Returns ​

boolean


ownStyleNameOf() ​

ownStyleNameOf(styleId): string | undefined

Defined in: src/tswp/textstorage.ts:1017

The name written on this style object itself — undefined for the anonymous style direct formatting creates. Use it to tell "styled as Heading" from "styled as Heading, then modified here".

Parameters ​

styleId ​

bigint

Returns ​

string | undefined


pageNumberFields() ​

pageNumberFields(): NumberAttachmentInfo & object[]

Defined in: src/tswp/textstorage.ts:1509

Page-number and page-count fields in this storage, with their formats.

Returns ​

NumberAttachmentInfo & object[]


paragraph() ​

paragraph(index): ParagraphHandle

Defined in: src/tswp/textstorage.ts:1027

Fluent handle for one paragraph.

Parameters ​

index ​

number

Returns ​

ParagraphHandle


paragraphDirection() ​

paragraphDirection(paragraphIndex): "ltr" | "rtl" | "natural"

Defined in: src/tswp/textstorage.ts:1572

A paragraph's base writing direction, from the storage's bidi table (table_para_bidi): the run-anchored entry pair whose first slot is the direction — 0 LTR, 1 RTL, 65535 natural — with the second slot 0, or 65535 when the first is natural. The paragraph style plays no part; the app writes only this pair when a paragraph is flipped.

Parameters ​

paragraphIndex ​

number

Returns ​

"ltr" | "rtl" | "natural"


paragraphs() ​

paragraphs(): ParagraphInfo[]

Defined in: src/tswp/textstorage.ts:312

Returns ​

ParagraphInfo[]


paragraphStarts() ​

paragraphStarts(text?): number[]

Defined in: src/tswp/textstorage.ts:303

UTF-16 offsets where paragraphs begin. Always includes 0 for non-empty text.

Parameters ​

text? ​

string = ...

Returns ​

number[]


placeholders() ​

placeholders(): object[]

Defined in: src/tswp/textstorage.ts:1631

Placeholder text runs — a template's "tap or click to add …" spans, which the app selects whole on a click and replaces on the first keystroke (TSWP.PlaceholderSmartFieldArchive).

Returns ​

object[]


range() ​

range(start, end): TextRange

Defined in: src/tswp/textstorage.ts:1022

A live fluent handle over [start, end).

Parameters ​

start ​

number

end ​

number

Returns ​

TextRange


removeAttachment() ​

removeAttachment(objectId): boolean

Defined in: src/tswp/textstorage.ts:1500

Remove an attachment and the placeholder character it occupies.

What goes here is the character and the table entry, which is what makes the field disappear from the text. The archives it left behind — for an image, the drawable and its attachment — are reclaimed by IWorkDocument.compact(), which collects whatever the document no longer reaches. The image bytes stay: a Data/ file's link to its object is not something this library can safely trace, so nothing collects one (see docs/BLOCKERS.md).

Parameters ​

objectId ​

bigint

Returns ​

boolean


removeBookmark() ​

removeBookmark(fieldId): boolean

Defined in: src/tswp/textstorage.ts:1727

Remove a bookmark. The text it marked stays.

Parameters ​

fieldId ​

bigint

Returns ​

boolean


removeComment() ​

removeComment(commentStorageId): boolean

Defined in: src/tswp/textstorage.ts:1841

Detach a comment. The commented text stays; the highlight goes.

The archives are left in the package, as everywhere else here — what makes the comment disappear is the text no longer pointing at it.

Parameters ​

commentStorageId ​

bigint

Returns ​

boolean


removeFootnote() ​

removeFootnote(noteStorageId): boolean

Defined in: src/tswp/textstorage.ts:1473

Remove a footnote: its reference character goes, and with it the note.

Takes the note storage's identifier, which is what footnotes reports. The archives stay in the package; what removes the footnote is the body no longer referencing it.

Parameters ​

noteStorageId ​

bigint

Returns ​

boolean


removeLinks(start, end): number

Defined in: src/tswp/textstorage.ts:1176

Remove any hyperlink overlapping [start, end); the text is untouched.

Parameters ​

start ​

number

end ​

number

Returns ​

number


replaceAll() ​

replaceAll(find, replace): number

Defined in: src/tswp/textstorage.ts:729

Literal find/replace across the storage. Returns replacement count.

Parameters ​

find ​

string

replace ​

string

Returns ​

number


replaceRange() ​

replaceRange(start, end, replacement): void

Defined in: src/tswp/textstorage.ts:453

Replace [start, end) with replacement, fixing up every attribute table. Offsets are UTF-16 code units (plain JS string indexes).

Parameters ​

start ​

number

end ​

number

replacement ​

string

Returns ​

void


resolveStyle() ​

resolveStyle(style, type): bigint

Defined in: src/tswp/textstorage.ts:977

Resolve a style given by name (searched in the sheet chain) or id.

Parameters ​

style ​

string | bigint

type ​

number

Returns ​

bigint


setCharacterStyleRange() ​

setCharacterStyleRange(start, end, styleId): void

Defined in: src/tswp/textstorage.ts:860

Apply (or clear, with undefined) a character-style object over a range. The previous effective style resumes at end.

A range ending at text.length writes no resume entry — no corpus storage (0 of 2896) carries a character-table entry at text.length, so the run is left open there. appendParagraph closes it when it next extends the text, keeping the styled range at exactly [start, end).

Parameters ​

start ​

number

end ​

number

styleId ​

bigint | undefined

Returns ​

void


setListStyle() ​

setListStyle(paragraphIndex, styleId): void

Defined in: src/tswp/textstorage.ts:1067

Set the list style of a paragraph (see also PagesDocument.setListStyle).

Parameters ​

paragraphIndex ​

number

styleId ​

bigint | undefined

Returns ​

void


setParagraphDirection() ​

setParagraphDirection(paragraphIndex, direction): void

Defined in: src/tswp/textstorage.ts:1588

Set a paragraph's base writing direction, writing the same pair the app writes when the direction control flips a paragraph: (1, 0) for RTL, (0, 0) for LTR, (65535, 65535) for natural. Every paragraph gets its own entry so no run bleeds into a neighbour, with existing values carried.

Parameters ​

paragraphIndex ​

number

direction ​

"ltr" | "rtl" | "natural"

Returns ​

void


setParagraphStyle() ​

setParagraphStyle(paragraphIndex, styleId): void

Defined in: src/tswp/textstorage.ts:838

Set (or clear) the paragraph style of one paragraph.

Parameters ​

paragraphIndex ​

number

styleId ​

bigint | undefined

Returns ​

void


setParagraphTableValue() ​

setParagraphTableValue(tableField, paragraphIndex, styleId): void

Defined in: src/tswp/textstorage.ts:1072

Set one paragraph's value in any paragraph-aligned object table.

Parameters ​

tableField ​

number

paragraphIndex ​

number

styleId ​

bigint | undefined

Returns ​

void


setText() ​

setText(text): void

Defined in: src/tswp/textstorage.ts:724

Replace the storage's whole text, keeping run structure where possible.

Parameters ​

text ​

string

Returns ​

void


sheet() ​

sheet(): StylesheetModel | undefined

Defined in: src/tswp/textstorage.ts:970

The stylesheet governing this storage, if resolvable.

Returns ​

StylesheetModel | undefined


smartFields() ​

smartFields(): object[]

Defined in: src/tswp/textstorage.ts:1219

All smart-field runs (hyperlinks, page numbers, dates, bookmarks, merge fields, TOC fields, …). kind is the registry name of the field archive so callers can switch on it without importing type IDs.

Returns ​

object[]


spanObject() ​

spanObject(tableField, start, end, objectId): void

Defined in: src/tswp/textstorage.ts:1188

Span an object over [start, end) in a character-run object table.

Parameters ​

tableField ​

number

start ​

number

end ​

number

objectId ​

bigint | undefined

Returns ​

void


styleNameOf() ​

styleNameOf(styleId): string | undefined

Defined in: src/tswp/textstorage.ts:999

UI name of a style object — the name the app's style panel shows.

Direct formatting parents a paragraph on an anonymous child of the named style, so the applied object usually carries no name of its own: 644 of 2093 corpus paragraphs sit on such a style, and every one of the 644 has a named ancestor (one fixture's every paragraph does). The name therefore resolves up the parent chain, which is what makes a directly formatted heading still read as "Heading" — and still be collected by a table of contents, which matches on the named style.

ownStyleNameOf answers the literal question instead.

Parameters ​

styleId ​

bigint

Returns ​

string | undefined


tablePositionViolation() ​

tablePositionViolation(): { position: number; table: string; } | undefined

Defined in: src/tswp/textstorage.ts:1872

The first attribute-table entry outside its lawful positions, if any.

The law, measured across the corpus's 2921 storages: no entry sits past text.length in any table, and an entry at exactly text.length occurs only in the paragraph-family tables — and only when a final empty paragraph exists to describe: empty text, or text ending with a terminator. The character-content tables (character styles, smart fields, anchors, language runs) leave a run reaching the end of the text open instead.

Returns ​

{ position: number; table: string; } | undefined

MIT licensed. Independently made — not by Apple in California. Not affiliated with or endorsed by Apple Inc.