// Copyright 2025 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
///|
/// Ported from `cosmic-text/src/line_ending.rs` (cosmic-text is dual-licensed MIT OR Apache-2.0).
pub(all) enum LineEnding {
Lf
CrLf
Cr
LfCr
None
}
///|
pub fn LineEnding::as_str(self : LineEnding) -> String {
match self {
Lf => "\n"
CrLf => "\r\n"
Cr => "\r"
LfCr => "\n\r"
None => ""
}
}
///|
/// Default line ending (matches upstream: LF).
pub fn LineEnding::default() -> LineEnding {
Lf
}
///|
pub struct LineIter {
string : String
start : Int
end : Int
}
///|
pub fn LineIter::new(string : String) -> LineIter {
LineIter::{ string, start: 0, end: string.length() }
}
///|
fn is_cr(code : Int) -> Bool {
code == 13
}
///|
fn is_lf(code : Int) -> Bool {
code == 10
}
///|
/// Returns (start, end, ending) where [start,end) is the line content range.
pub fn LineIter::next(self : LineIter) -> (LineIter, (Int, Int, LineEnding)?) {
let start = self.start
let len = self.end
let mut i = start
while i < len {
let code = self.string.code_unit_at(i).to_int()
if is_cr(code) || is_lf(code) {
let end = i
let after0 = code
let after1 = if i + 1 < len {
self.string.code_unit_at(i + 1).to_int()
} else {
-1
}
let ending = if is_cr(after0) && is_lf(after1) {
CrLf
} else if is_lf(after0) && is_cr(after1) {
LfCr
} else if is_lf(after0) {
Lf
} else if is_cr(after0) {
Cr
} else {
None
}
let next_start = i + ending.as_str().length()
let iter = LineIter::{ ..self, start: next_start }
return (iter, Some((start, end, ending)))
}
i = i + 1
}
if start < len {
let iter = LineIter::{ ..self, start: len }
(iter, Some((start, len, None)))
} else {
(self, None)
}
}