// Copyright (c) 2026 Storm Dragon // Authors: Storm Dragon, Angus Kola // SPDX-License-Identifier: GPL-3.0-or-later package presentation // Speech retains presentation boundaries independently of the display text. // Source punctuation is always part of its original chunk. type Speech struct { Text string Chunks []string } func SpeechWithOptions(parts []string, options Options) Speech { var nonempty []string for _, part := range parts { if part != "" { nonempty = append(nonempty, part) } } parts = nonempty result := Speech{Text: join_speech_parts(parts, options)} if reading_options(options).EnablePauseBreaks { result.Chunks = parts } return result } // WithText replaces the presentation only when its text has changed. func (speech Speech) WithText(text string) Speech { if text == speech.Text { return speech } return Speech{Text: text} } // Prepend and Append carry explicitly added presentation boundaries without // inspecting source text for punctuation or matching it inside another string. func (speech Speech) Prepend(text, separator string) Speech { if text == "" { return speech } if speech.Text == "" { return Speech{Text: text} } result := Speech{Text: text + separator + speech.Text} if len(speech.Chunks) != 0 { result.Chunks = append([]string{text}, speech.Chunks...) } return result } func (speech Speech) Append(text, separator string) Speech { if text == "" { return speech } if speech.Text == "" { return Speech{Text: text} } result := Speech{Text: speech.Text + separator + text} if len(speech.Chunks) != 0 { result.Chunks = append(append([]string(nil), speech.Chunks...), text) } return result }