///|
pub(all) struct SourceSummary {
file_name : String
lines : Int
characters : Int
blank_lines : Int
comment_lines : Int
code_lines : Int
max_line_length : Int
} derive(Eq, Debug)
///|
fn is_comment_line(line : String) -> Bool {
let value = line.trim()
value.has_prefix("//") ||
value.has_prefix("/*") ||
value.has_prefix("*") ||
value.has_prefix("*/")
}
///|
pub fn SourceFile::summary(self : SourceFile) -> SourceSummary {
let lines = self.lines()
let mut blank = 0
let mut comments = 0
let mut max_length = 0
for line in lines {
let length = line.to_array().length()
if length > max_length {
max_length = length
}
if line.trim().is_empty() {
blank += 1
} else if is_comment_line(line) {
comments += 1
}
}
{
file_name: self.name(),
lines: lines.length(),
characters: self.character_count(),
blank_lines: blank,
comment_lines: comments,
code_lines: lines.length() - blank - comments,
max_line_length: max_length,
}
}
///|
pub fn SourceFile::normalized(self : SourceFile) -> SourceFile {
let builder = StringBuilder()
let chars = self.text.to_array()
let mut index = 0
while index < chars.length() {
if chars[index] == '\r' {
if index + 1 < chars.length() && chars[index + 1] == '\n' {
index += 1
}
builder.write_char('\n')
} else {
builder.write_char(chars[index])
}
index += 1
}
SourceFile::new(self.name(), builder.to_string())
}
///|
pub(all) struct SourceBundle {
files : Array[SourceFile]
}
///|
pub fn SourceBundle::new() -> SourceBundle {
{ files: [] }
}
///|
pub fn SourceBundle::from_files(files : Array[SourceFile]) -> SourceBundle {
let bundle = SourceBundle::new()
for file in files {
bundle.add(file)
}
bundle
}
///|
pub fn SourceBundle::add(self : SourceBundle, file : SourceFile) -> Unit {
for existing in self.files {
if existing.name() == file.name() {
return
}
}
self.files.push(file)
}
///|
pub fn SourceBundle::len(self : SourceBundle) -> Int {
self.files.length()
}
///|
pub fn SourceBundle::is_empty(self : SourceBundle) -> Bool {
self.files.length() == 0
}
///|
pub fn SourceBundle::get(self : SourceBundle, name : String) -> SourceFile? {
for file in self.files {
if file.name() == name {
return Some(file)
}
}
None
}
///|
pub fn SourceBundle::names(self : SourceBundle) -> Array[String] {
let result : Array[String] = []
for file in self.files {
result.push(file.name())
}
result.sort()
result
}
///|
pub fn SourceBundle::summaries(self : SourceBundle) -> Array[SourceSummary] {
let result : Array[SourceSummary] = []
for name in self.names() {
match self.get(name) {
Some(file) => result.push(file.summary())
None => ()
}
}
result
}
///|
pub fn SourceBundle::total_lines(self : SourceBundle) -> Int {
let mut total = 0
for file in self.files {
total += file.line_count()
}
total
}
///|
pub fn SourceBundle::total_characters(self : SourceBundle) -> Int {
let mut total = 0
for file in self.files {
total += file.character_count()
}
total
}
///|
pub fn SourceBundle::code_lines(self : SourceBundle) -> Int {
let mut total = 0
for summary in self.summaries() {
total += summary.code_lines
}
total
}
///|
pub fn SourceBundle::largest_file(self : SourceBundle) -> SourceSummary? {
let summaries = self.summaries()
if summaries.length() == 0 {
return None
}
let mut largest = summaries[0]
for summary in summaries {
if summary.characters > largest.characters {
largest = summary
}
}
Some(largest)
}
///|
pub fn SourceBundle::summary(self : SourceBundle) -> String {
"files=" +
self.len().to_string() +
", lines=" +
self.total_lines().to_string() +
", code_lines=" +
self.code_lines().to_string() +
", characters=" +
self.total_characters().to_string()
}