///|
/// Return the number of logical lines in a source file.
pub fn SourceFile::line_count(self : SourceFile) -> Int {
let mut count = 1
for character in self.text {
if character == '\n' {
count += 1
}
}
count
}
///|
/// Return the number of characters in the source text.
pub fn SourceFile::character_count(self : SourceFile) -> Int {
self.text.to_array().length()
}
///|
/// Return whether an offset can identify a position in the source text.
pub fn SourceFile::contains_offset(self : SourceFile, offset : Int) -> Bool {
offset >= 0 && offset <= self.character_count()
}
///|
/// Return the complete line containing an offset, without its newline.
pub fn SourceFile::line_text(self : SourceFile, offset : Int) -> String {
let chars = self.text.to_array()
let safe_offset = if offset < 0 {
0
} else if offset > chars.length() {
chars.length()
} else {
offset
}
let mut line_start = safe_offset
while line_start > 0 && chars[line_start - 1] != '\n' {
line_start -= 1
}
let mut line_end = safe_offset
while line_end < chars.length() && chars[line_end] != '\n' {
line_end += 1
}
String::from_array(chars[line_start:line_end])
}
///|
/// Return all source lines in order, retaining empty lines.
pub fn SourceFile::lines(self : SourceFile) -> Array[String] {
let result : Array[String] = []
let current = StringBuilder()
for character in self.text {
if character == '\n' {
result.push(current.to_string())
current.reset()
} else {
current.write_char(character)
}
}
result.push(current.to_string())
result
}