Immutable text document data structure with efficient operations for large documents and line-based access.
The abstract Text class provides an immutable representation of document content with efficient operations for large documents.
/**
* The data structure for documents. All instances are immutable.
*/
abstract class Text {
/** Create a Text instance from an array of lines */
static of(text: string[]): Text;
/** Create an empty text document */
static empty: Text;
/** The length of the string */
readonly length: number;
/** The number of lines in the string (always >= 1) */
readonly lines: number;
/** Get the line description around the given position */
lineAt(pos: number): Line;
/** Get the description for the given (1-based) line number */
line(n: number): Line;
/** Replace a range of the text with the given content */
replace(from: number, to: number, text: Text): Text;
/** Append another document to this one */
append(other: Text): Text;
/** Retrieve the text between the given points */
slice(from: number, to?: number): Text;
/** Retrieve a part of the document as a string */
sliceString(from: number, to?: number, lineSep?: string): string;
/** Test whether this text is equal to another instance */
eq(other: Text): boolean;
/** Iterate over the document content */
[Symbol.iterator](): Iterator<string>;
}
interface Line {
/** The start position of the line */
readonly from: number;
/** The end position of the line (excluding line break) */
readonly to: number;
/** The 1-based line number */
readonly number: number;
/** The text content of the line (excluding line break) */
readonly text: string;
}Usage Examples:
import { Text } from "@codemirror/state";
// Create text from lines
const doc = Text.of([
"First line",
"Second line",
"Third line"
]);
console.log(doc.length); // Total character count
console.log(doc.lines); // 3
// Access lines
const firstLine = doc.line(1);
console.log(firstLine.text); // "First line"
console.log(firstLine.from); // 0
console.log(firstLine.to); // 10
// Get line at position
const lineAtPos = doc.lineAt(15);
console.log(lineAtPos.number); // 2
console.log(lineAtPos.text); // "Second line"
// Extract text content
const substring = doc.sliceString(0, 10);
console.log(substring); // "First line"
// Replace content
const newDoc = doc.replace(0, 5, Text.of(["Hello"]));
console.log(newDoc.sliceString(0, 20)); // "Hello line\nSecond line"Methods for manipulating and querying text content.
/**
* Replace a range of the text with the given content
* @param from Start position
* @param to End position
* @param text Replacement text
*/
replace(from: number, to: number, text: Text): Text;
/**
* Append another document to this one
* @param other Text to append
*/
append(other: Text): Text;
/**
* Retrieve the text between the given points
* @param from Start position (default: 0)
* @param to End position (default: document length)
*/
slice(from: number, to?: number): Text;
/**
* Retrieve a part of the document as a string
* @param from Start position (default: 0)
* @param to End position (default: document length)
* @param lineSep Line separator to use in output
*/
sliceString(from: number, to?: number, lineSep?: string): string;
/**
* Test whether this text is equal to another instance
* @param other Text to compare with
*/
eq(other: Text): boolean;Usage Examples:
const doc = Text.of(["Hello", "world"]);
// Replace text
const replaced = doc.replace(0, 5, Text.of(["Hi"]));
console.log(replaced.toString()); // "Hi\nworld"
// Append text
const appended = doc.append(Text.of(["!", "More text"]));
console.log(appended.toString()); // "Hello\nworld\n!\nMore text"
// Slice text
const slice = doc.slice(2, 8);
console.log(slice.toString()); // "llo\nwo"
// Get string representation
const str = doc.sliceString(0, 5, " | ");
console.log(str); // "Hello"
// Compare texts
const doc2 = Text.of(["Hello", "world"]);
console.log(doc.eq(doc2)); // trueMethods for accessing line information within the document.
/**
* Get the line description around the given position
* @param pos Character position within the document
*/
lineAt(pos: number): Line;
/**
* Get the description for the given (1-based) line number
* @param n Line number (1-based)
*/
line(n: number): Line;Usage Examples:
const doc = Text.of([
"First line",
"Second line with more content",
"Third line"
]);
// Access by line number
const line2 = doc.line(2);
console.log(line2.text); // "Second line with more content"
console.log(line2.number); // 2
console.log(line2.from); // 11 (position after "First line\n")
console.log(line2.to); // 39 (end of second line)
// Access by position
const lineAtPos = doc.lineAt(15); // Position within second line
console.log(lineAtPos.number); // 2
console.log(lineAtPos.text); // "Second line with more content"
// First line
const firstLine = doc.lineAt(0);
console.log(firstLine.number); // 1
console.log(firstLine.from); // 0
console.log(firstLine.to); // 10The Text class implements the Iterable interface for iterating over document content.
/**
* Text iterator iterates over a sequence of strings. When iterating over a Text document,
* result values will either be lines or line breaks.
*/
interface TextIterator extends Iterator<string> {
/** Retrieve the next string */
next(skip?: number): this;
/** The current string */
value: string;
/** Whether the end of the iteration has been reached */
done: boolean;
/** Whether the current string represents a line break */
lineBreak: boolean;
}Usage Examples:
const doc = Text.of(["Line 1", "Line 2", "Line 3"]);
// Iterate using for...of
for (const chunk of doc) {
console.log(chunk); // "Line 1", "\n", "Line 2", "\n", "Line 3"
}
// Manual iteration
const iter = doc[Symbol.iterator]() as TextIterator;
let result = iter.next();
while (!result.done) {
console.log(`Content: "${result.value}", LineBreak: ${result.lineBreak}`);
result = iter.next();
}/**
* Information about a line in a document
*/
interface Line {
/** The start position of the line in the document */
readonly from: number;
/** The end position of the line (not including the line break) */
readonly to: number;
/** The 1-based line number */
readonly number: number;
/** The text content of the line (not including the line break) */
readonly text: string;
}
/**
* A text iterator for iterating over document content
*/
interface TextIterator extends Iterator<string>, Iterable<string> {
next(skip?: number): this;
value: string;
done: boolean;
lineBreak: boolean;
}