Files

90 lines
2.7 KiB
Go

// Copyright (c) 2026 Storm Dragon
// Authors: Storm Dragon, Angus Kola
// SPDX-License-Identifier: GPL-3.0-or-later
package app
import (
"strings"
"git.stormux.org/storm/cthulhu/internal/ocr"
"git.stormux.org/storm/cthulhu/internal/review"
)
// Retain an unchanged prefix or suffix exactly. A changed middle keeps the
// nearest legal offset; identical repeated text is deliberately not guessed.
func remapOCROffset(oldText, newText string, offset int) int {
oldRunes, newRunes := []rune(oldText), []rune(newText)
offset = max(0, min(offset, len(oldRunes)))
prefix := 0
for prefix < len(oldRunes) && prefix < len(newRunes) && oldRunes[prefix] == newRunes[prefix] {
prefix++
}
if offset < prefix {
return offset
}
suffix := 0
for suffix < len(oldRunes)-prefix && suffix < len(newRunes)-prefix &&
oldRunes[len(oldRunes)-1-suffix] == newRunes[len(newRunes)-1-suffix] {
suffix++
}
if offset >= len(oldRunes)-suffix {
return len(newRunes) - (len(oldRunes) - offset)
}
return min(offset, len(newRunes))
}
func (session *ocrSession) finish_refresh_locked(job ocrJob, interest review.Interest, capture ocr.Capture, result ocr.Result, err error) {
session.refreshing = false
if err != nil {
session.refreshFailed = true
session.status_locked("OCR refresh failed; activate after a successful refresh")
return
}
previous := session.cursor.Text()
offset := remapOCROffset(previous, result.Text, session.cursor.Offset())
anchor := -1
if session.selectionAnchor >= 0 {
anchor = remapOCROffset(previous, result.Text, session.selectionAnchor)
}
session.source, session.pixels = interest, capture
session.cursor = ocr.NewCursor(result)
position, _ := session.cursor.Set(offset)
session.selectionAnchor = anchor
session.refreshFailed = result.Text == ""
if result.Text == "" {
session.status_locked("No text recognized")
} else if result.Text != previous {
session.status_locked(ocrChangedAnnouncement(previous, result.Text))
} else if !job.automatic {
session.status_locked("OCR text unchanged")
}
if session.display != nil {
session.display.EnqueueFrame(session.frame_locked(position))
}
session.schedule_refresh_locked()
}
func ocrChangedAnnouncement(previous, current string) string {
oldRunes, newRunes := []rune(previous), []rune(current)
index := 0
for index < len(oldRunes) && index < len(newRunes) && oldRunes[index] == newRunes[index] {
index++
}
if index == len(newRunes) && index < len(oldRunes) {
return "OCR text removed"
}
start, end := index, index
for start > 0 && newRunes[start-1] != '\n' {
start--
}
for end < len(newRunes) && newRunes[end] != '\n' && end-start < 100 {
end++
}
line := strings.TrimSpace(string(newRunes[start:end]))
if line == "" {
return "OCR text changed"
}
return line
}