diff --git a/src/index.ts b/src/index.ts index 25dc4a9..21fc37e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -61,10 +61,6 @@ export class SourceText { return this.chars.length; } - get lineCount(): number { - return this.lineStarts.length; - } - sliceByCp(start: number, end: number): string { const startRef = this.chars[start]; // Handle out of bounds gracefully @@ -78,31 +74,6 @@ export class SourceText { return this.source.slice(startOff, endOff); } - // Returns a Span for the given line (1-based index). - // If stripNewlines is true, the span will exclude trailing \r\n. - getLineSpan(line: number, stripNewlines = true): Span { - const range = this.getLineRange(line); - let endIdx = range.end; - - if (stripNewlines && endIdx > range.start) { - // Look at the character just before endIdx - const lastChar = this.chars[endIdx - 1].char; - if (lastChar === NEW_LINE) { - endIdx--; - if (endIdx > range.start && this.chars[endIdx - 1].char === CARRIAGE_RETURN) { - endIdx--; - } - } else if (lastChar === CARRIAGE_RETURN) { - endIdx--; - } - } - - return { - start: this.getLocation(range.start), - end: this.getLocation(endIdx) - }; - } - // Converts a linear Code Point Index into a SourceLocation (line, column, index). getLocation(index: CodePointIndex): SourceLocation { // Does binary search. @@ -126,22 +97,6 @@ export class SourceText { return { index, line, column }; } - // Creates a SourceRegion from a Span. - makeRegion(span: Span): SourceRegion { - // Basic validation - if (span.start.index < 0 || span.end.index > this.length) { - throw new Error(`Span out of bounds: ${span.start.index}-${span.end.index} (length: ${this.length})`); - } - return new SourceRegion(this, span); - } - - // Creates a SourceRegion covering the entire SourceText. - fullRegion(): SourceRegion { - const start = this.getLocation(0); - const end = this.getLocation(this.length); - return this.makeRegion({ start, end }); - } - // Returns the full text of a specific line (1-based index) getLineText(line: number): string { const lineIndex = line - 1; @@ -176,65 +131,19 @@ export function sourceText(s: string): SourceText { return new SourceText(s); } -// Creates a Span from two SourceLocations. -export function span(start: SourceLocation, end: SourceLocation): Span { - return { start, end }; -} - export class SourceRegion { - constructor( - public readonly source: SourceText, - public readonly span: Span - ) {} + // TODO + readonly sourceText: SourceText; + readonly span: Span; - get length(): number { - return this.span.end.index - this.span.start.index; - } - - get lineCount(): number { - return this.span.end.line - this.span.start.line + 1; - } - - toString(): string { - return this.source.sliceByCp(this.span.start.index, this.span.end.index); - } - - // Returns a Span for the given line (1-based index). - getLineSpan(line: number, stripNewlines = true): Span { - if (line < this.span.start.line || line > this.span.end.line) { - throw new Error(`Line ${line} is outside of region lines ${this.span.start.line}-${this.span.end.line}`); - } - return this.source.getLineSpan(line, stripNewlines); - } - - // Iterates over all lines that intersect this region. - // Yields a Span for each line. - *lines(stripNewlines = true): IterableIterator { - const startLine = this.span.start.line; - const endLine = this.span.end.line; - - for (let currentLine = startLine; currentLine <= endLine; currentLine++) { - yield this.getLineSpan(currentLine, stripNewlines); - } - } - - forEachLine(callback: (span: Span, lineNo: number) => void, stripNewlines = true): void { - let lineNo = this.span.start.line; - for (const lineSpan of this.lines(stripNewlines)) { - callback(lineSpan, lineNo++); - } - } - - // Creates a sub-region within this region. - // Validates that the new span is contained within the current region. - subRegion(span: Span): SourceRegion { - if (span.start.index < this.span.start.index || span.end.index > this.span.end.index) { - throw new Error(`Sub-region span ${span.start.index}-${span.end.index} is not within parent region ${this.span.start.index}-${this.span.end.index}`); - } - return this.source.makeRegion(span); + constructor(sourceText: SourceText, span: Span) { + this.sourceText = sourceText; + // TODO: What about span validation? + this.span = span; } } + export type Span = { start: SourceLocation; end: SourceLocation; @@ -281,12 +190,7 @@ export type LineView = { underline: string; // The literal "^^^" string for CLI usage }; -export function renderRegion(region: SourceRegion, contextLines = 1): LineView[] { - return renderSpan(region, region.span, contextLines); -} - -export function renderSpan(region: SourceRegion, span: Span, contextLines = 1): LineView[] { - const text = region.source; +export function renderSpan(text: SourceText, span: Span, contextLines = 1): LineView[] { const views: LineView[] = []; // Determine range of lines to show (including context)