102 lines
3.2 KiB
Go
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
|
|
}
|