Forms-Zustand und Darstellung korrigieren und Change archivieren

This commit is contained in:
2026-09-05 20:48:13 +02:00
parent 644a86212f
commit 58b1f620ea
22 changed files with 1362 additions and 101 deletions

View File

@@ -399,16 +399,31 @@ impl TextScreen {
match ch {
'\n' => self.newline(),
'\r' => self.cur_col = 0,
_ => self.zeichen_setzen(ch),
_ => self.zeichen_setzen(ch, true),
}
}
}
/// Eine UI-Zeile ohne Umbruch oder Scrollen bis zum Bildschirmrand zeichnen.
/// Steuerzeichen werden als Leerzeichen dargestellt; breite Zeichen passen
/// nur vollständig. Der Cursor bleibt spätestens in der letzten Spalte.
pub fn print_line(&mut self, text: &str) {
self.veraendert = true;
for ch in text.chars() {
let ch = if ch.is_control() { ' ' } else { ch };
if self.cur_col + ch.width().unwrap_or(1).max(1) > self.cols {
break;
}
self.zeichen_setzen(ch, false);
}
self.cur_col = self.cur_col.min(self.cols - 1);
}
/// Ein Zeichen an der Cursorposition setzen und den Cursor um seine
/// Darstellungsbreite vorrücken. Ein breites Zeichen, das nicht mehr
/// vollständig in die Zeile passt, wandert als Ganzes in die nächste;
/// die letzte Spalte bleibt dann leer.
fn zeichen_setzen(&mut self, ch: char) {
fn zeichen_setzen(&mut self, ch: char, wrap: bool) {
// ponytail: Breite 0 (kombinierende Zeichen) wird wie 1 behandelt —
// sie bekommen eine eigene Zelle statt sich an die vorige zu hängen.
// Ceiling: echte Kombination erst, wenn ein Korpusprogramm sie braucht.
@@ -437,7 +452,7 @@ impl TextScreen {
let b = &mut self.belegt[self.cur_row];
*b = Some(b.map_or(letzte, |c| c.max(letzte)));
self.cur_col += breite;
if self.cur_col >= self.cols {
if wrap && self.cur_col >= self.cols {
self.newline();
}
}
@@ -541,6 +556,37 @@ mod tests {
assert_eq!((s.csrlin(), s.pos()), (1, 3));
}
#[test]
fn ui_zeile_bleibt_am_rand_ohne_umbruch_oder_scrollen() {
let mut s = TextScreen::new();
s.print("oben");
s.view_print(3, 10).unwrap();
s.set_color(2, 4);
for row in [10, 25] {
s.locate(row, 78).unwrap();
s.print_line("中xREST");
assert_eq!(s.cell(row, 78).ch, '中');
assert!(s.cell(row, 79).fortsetzung);
assert_eq!(s.cell(row, 80).ch, 'x');
assert_eq!((s.csrlin(), s.pos()), (row, 80));
assert_eq!((s.cell(row, 80).fg, s.cell(row, 80).bg), (2, 4));
}
assert_eq!(s.cell(1, 1).ch, 'o');
assert_eq!(s.cell(9, 78).ch, ' ');
assert_eq!(s.cell(24, 78).ch, ' ');
s.locate(2, 1).unwrap();
s.print_line("a\nb\rc");
assert_eq!(
(1..=5).map(|col| s.cell(2, col).ch).collect::<String>(),
"a b c"
);
s.locate(2, 80).unwrap();
s.print_line("");
assert_eq!(s.cell(2, 80).ch, ' ');
assert_eq!(s.cell(3, 1).ch, ' ');
assert_eq!((s.csrlin(), s.pos()), (2, 80));
}
#[test]
fn unicode_zeichen_belegen_eine_zelle() {
let mut s = TextScreen::new();