Introduce SourceRegion
This commit is contained in:
parent
9939f6c97f
commit
a439f15c5f
1 changed files with 41 additions and 9 deletions
50
src/index.ts
50
src/index.ts
|
|
@ -97,6 +97,22 @@ export class SourceText {
|
||||||
return { index, line, column };
|
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)
|
// Returns the full text of a specific line (1-based index)
|
||||||
getLineText(line: number): string {
|
getLineText(line: number): string {
|
||||||
const lineIndex = line - 1;
|
const lineIndex = line - 1;
|
||||||
|
|
@ -132,18 +148,29 @@ export function sourceText(s: string): SourceText {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SourceRegion {
|
export class SourceRegion {
|
||||||
// TODO
|
constructor(
|
||||||
readonly sourceText: SourceText;
|
public readonly source: SourceText,
|
||||||
readonly span: Span;
|
public readonly span: Span
|
||||||
|
) {}
|
||||||
|
|
||||||
constructor(sourceText: SourceText, span: Span) {
|
get length(): number {
|
||||||
this.sourceText = sourceText;
|
return this.span.end.index - this.span.start.index;
|
||||||
// TODO: What about span validation?
|
}
|
||||||
this.span = span;
|
|
||||||
|
toString(): string {
|
||||||
|
return this.source.sliceByCp(this.span.start.index, this.span.end.index);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export type Span = {
|
export type Span = {
|
||||||
start: SourceLocation;
|
start: SourceLocation;
|
||||||
end: SourceLocation;
|
end: SourceLocation;
|
||||||
|
|
@ -190,7 +217,12 @@ export type LineView = {
|
||||||
underline: string; // The literal "^^^" string for CLI usage
|
underline: string; // The literal "^^^" string for CLI usage
|
||||||
};
|
};
|
||||||
|
|
||||||
export function renderSpan(text: SourceText, span: Span, contextLines = 1): LineView[] {
|
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;
|
||||||
const views: LineView[] = [];
|
const views: LineView[] = [];
|
||||||
|
|
||||||
// Determine range of lines to show (including context)
|
// Determine range of lines to show (including context)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue