Files

56 lines
2.2 KiB
Go

// Fenrir console screen reader.
// Copyright (c) 2026 Storm Dragon
// SPDX-License-Identifier: GPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program. If not, see <https://www.gnu.org/licenses/gpl-3.0.html>.
package screen
import (
"slices"
"unicode"
)
// A TUI can scroll only its message area, leaving headers, status and input
// rows fixed. Suppress the longest contiguous shifted overlap, while leaving
// every other changed row available for normal feedback. Partial overlaps
// require two nonblank rows: a lone repeated label or a blank area is ambiguous.
func Scrolled_overlap(previous, next Snapshot) (bestStart, bestEnd int) {
// Match a whole-screen scroll first, including sparse screens. Ignore
// whitespace-only overlaps, which cannot establish that anything scrolled.
firstText := slices.IndexFunc(next.Cells, func(cell rune) bool { return !unicode.IsSpace(cell) })
for shift := 1; shift < next.Rows && firstText >= 0 && firstText < (next.Rows-shift)*next.Cols; shift++ {
if slices.Equal(previous.Cells[shift*next.Cols:], next.Cells[:(next.Rows-shift)*next.Cols]) {
return 0, next.Rows - shift
}
}
bestText := 0
for shift := 1; shift < next.Rows; shift++ {
start, textRows := 0, 0
for row := 0; row <= next.Rows-shift; row++ {
if row < next.Rows-shift && slices.Equal(previous.Line(row+shift), next.Line(row)) {
if !slices.Equal(previous.Line(row), next.Line(row)) && slices.ContainsFunc(next.Line(row), func(cell rune) bool { return !unicode.IsSpace(cell) }) {
textRows++
}
continue
}
if textRows >= 2 && textRows > bestText {
bestStart, bestEnd, bestText = start, row, textRows
}
start, textRows = row+1, 0
}
}
return bestStart, bestEnd
}