Skip to content

Commit

Permalink
Add iterLines to Text interface
Browse files Browse the repository at this point in the history
  • Loading branch information
marijnh committed Aug 23, 2021
1 parent 684da54 commit 1dccbaf
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 0 deletions.
46 changes: 46 additions & 0 deletions src/text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,23 @@ export abstract class Text implements Iterable<string> {
/// iterator will run in reverse.
iterRange(from: number, to: number = this.length): TextIterator { return new PartialTextCursor(this, from, to) }

/// Return a cursor that iterates over the given range of lines,
/// _without_ returning the line breaks between, and yielding empty
/// strings for empty lines.
///
/// When `from` and `to` are given, they should be 1-based line numbers.
iterLines(from?: number, to?: number) {
let inner
if (from == null) {
inner = this.iter()
} else {
if (to == null) to = this.lines + 1
let start = this.line(from).from
inner = this.iterRange(start, Math.max(start, to == this.lines + 1 ? this.length : to <= 1 ? 0 : this.line(to - 1).to))
}
return new LineCursor(inner)
}

/// @internal
abstract decompose(from: number, to: number, target: Text[], open: Open): void

Expand Down Expand Up @@ -466,6 +483,35 @@ class PartialTextCursor implements TextIterator {
get lineBreak() { return this.cursor.lineBreak && this.value != "" }
}

class LineCursor implements TextIterator {
afterBreak = true
value = ""
done = false

constructor(readonly inner: TextIterator) {}

next(skip = 0) {
let {done, lineBreak, value} = this.inner.next(skip)
if (done) {
this.done = true
this.value = ""
} else if (lineBreak) {
if (this.afterBreak) {
this.value = ""
} else {
this.afterBreak = true
this.next()
}
} else {
this.value = value
this.afterBreak = false
}
return this
}

get lineBreak() { return false }
}

/// This type describes a line in the document. It is created
/// on-demand when lines are [queried](#text.Text.lineAt).
export class Line {
Expand Down
15 changes: 15 additions & 0 deletions test/test-text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,21 @@ describe("Text", () => {
ist(doc0.iterRange(doc0.length - 2, doc0.length - 1).next().value, "9")
})

it("can iterate over lines", () => {
let doc = Text.of(["ab", "cde", "", "", "f", "", "g"])
function get(from?: number, to?: number) {
let result = []
for (let i = doc.iterLines(from, to); !i.next().done;) result.push(i.value)
return result.join("\n")
}
ist(get(), "ab\ncde\n\n\nf\n\ng")
ist(get(1, doc.lines + 1), "ab\ncde\n\n\nf\n\ng")
ist(get(2, 3), "cde")
ist(get(1, 1), "")
ist(get(2, 1), "")
ist(get(3), "\n\nf\n\ng")
})

it("can convert to JSON", () => {
for (let i = 0; i < 200; i++) lines.push("line " + i)
let text = Text.of(lines)
Expand Down

0 comments on commit 1dccbaf

Please sign in to comment.