Files

102 lines
3.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 review
import (
"strings"
"git.stormux.org/storm/fenrir/internal/i18n"
"git.stormux.org/storm/fenrir/internal/presentation"
"git.stormux.org/storm/fenrir/internal/screen"
)
func (r *Review) Set_mark() presentation.Message {
if !r.ready || !r.reviewing {
return presentation.Message{Text: i18n.T("no review cursor")}
}
if r.tableMode {
return r.set_table_headers()
}
point := r.y*r.screen.Cols + r.x
cue := presentation.PlaceStartMark
if r.markCount == 0 {
r.startMark, r.markCount = point, 1
} else {
r.endMark, r.markCount = point, 2
cue = presentation.PlaceEndMark
}
return presentation.Message{Text: i18n.T("set mark"), Cue: cue}
}
func (r *Review) Clear_marks() {
r.markCount = 0
if r.tableMode {
r.tableHeaders = nil
r.tableLayout = tableLayout{}
r.tableManual = false
r.tableAutoDisabled = true
}
}
// Marked_region is rectangular, unlike clipboard selection. A single mark
// optionally selects the rest of its physical row. Table header marks never
// enter markCount and cannot accidentally become reading regions.
func (r *Review) Marked_region(singleLine bool) (screen.Region, bool) {
if !r.ready || r.markCount == 0 || r.markCount < 2 && !singleLine {
return screen.Region{}, false
}
x1, y1 := r.startMark%r.screen.Cols, r.startMark/r.screen.Cols
if r.markCount == 1 {
return screen.Region{Left: x1, Top: y1, Bottom: y1, ToLineEnd: true}, true
}
x2, y2 := r.endMark%r.screen.Cols, r.endMark/r.screen.Cols
return screen.Region{Left: min(x1, x2), Top: min(y1, y2), Right: max(x1, x2), Bottom: max(y1, y2)}, true
}
// Marked_text uses inclusive Unicode cell positions in either direction. Copy
// with one mark takes the current review cursor as its second endpoint.
func (r *Review) Marked_text(copying bool) (string, bool) {
if !r.ready || r.markCount == 0 || !copying && r.markCount < 2 {
return "", false
}
end := r.endMark
if r.markCount == 1 {
end = r.y*r.screen.Cols + r.x
}
start := r.startMark
if start > end {
start, end = end, start
}
var lines []string
for row := start / r.screen.Cols; row <= end/r.screen.Cols; row++ {
left, right := 0, r.screen.Cols
if row == start/r.screen.Cols {
left = start % r.screen.Cols
}
if row == end/r.screen.Cols {
right = end%r.screen.Cols + 1
}
text := string(r.screen.Line(row)[left:right])
if start/r.screen.Cols != end/r.screen.Cols {
text = strings.TrimRight(text, " \x00\t\r")
}
lines = append(lines, text)
}
return strings.Join(lines, "\n"), true
}