65 lines
2.3 KiB
Go
65 lines
2.3 KiB
Go
// Copyright (c) 2026 Storm Dragon
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
package reader
|
|
|
|
import (
|
|
"slices"
|
|
"strings"
|
|
"time"
|
|
"unicode"
|
|
|
|
"git.stormux.org/storm/fenrir/internal/presentation"
|
|
"git.stormux.org/storm/fenrir/internal/screen"
|
|
)
|
|
|
|
func (r *Reader) Configure_indentation(mode string) { r.indentationMode = mode }
|
|
|
|
func (r *Reader) indentation_feedback(announce bool) *presentation.Message {
|
|
level, valid := r.review.Indentation()
|
|
if !valid {
|
|
return nil // Blank rows preserve the last meaningful level.
|
|
}
|
|
changed := r.indentKnown && level != r.lastIndent
|
|
r.lastIndent, r.indentKnown = level, true
|
|
if !announce || !changed || r.indentationMode == "" || r.indentationMode == "none" {
|
|
return nil
|
|
}
|
|
message := presentation.Indentation_message(level, r.indentationMode)
|
|
return &message
|
|
}
|
|
|
|
func (r *Reader) automatic_indentation(previous, next screen.Snapshot, switched bool) *presentation.Message {
|
|
if switched {
|
|
r.indentKnown = false
|
|
}
|
|
// Passive program output must not create indentation chatter. Match Python's
|
|
// cursor-input window and suppress automatic cursor feedback during review.
|
|
announce := !switched && next.Active && r.automatic && r.cursorEcho && r.trackingMode == "cursor" && !r.review.Active() &&
|
|
r.region_state().allows(next.X, next.Y, next.Cols, true, true) &&
|
|
!r.applicationInputAt.IsZero() && time.Since(r.applicationInputAt) < 300*time.Millisecond
|
|
if announce {
|
|
// A hidden leading-whitespace edit must not produce indentation cues
|
|
// at an otherwise visible cursor farther along the same row.
|
|
for col, char := range next.Line(next.Y) {
|
|
if !r.region_state().allows(col, next.Y, next.Cols, true, true) {
|
|
announce = false
|
|
break
|
|
}
|
|
if !unicode.IsSpace(char) {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if announce && previous.Y == next.Y {
|
|
// Horizontal input only reports a genuine leading-whitespace edit, not
|
|
// movement within a line or ordinary typing/deletion in its content.
|
|
before, after := previous.Text(previous.Y), next.Text(next.Y)
|
|
announce = strings.TrimSpace(before) == strings.TrimSpace(after) && before != after
|
|
} else if announce {
|
|
// A cursor moving with new program output is not line navigation.
|
|
announce = slices.Equal(previous.Line(next.Y), next.Line(next.Y))
|
|
}
|
|
return r.indentation_feedback(announce)
|
|
}
|