新增: 会话分叉功能,优化增量扫描缓存
- 会话分叉: 按 c 键从历史会话分叉,支持带方向提示 - 启动自动加载历史记录 - 增量扫描: 缓存内存化、目录 modTime 跳过、已删除条目裁剪 - 刷新按钮复用 onTabSwitch 单一入口
This commit is contained in:
134
internal/util.go
Normal file
134
internal/util.go
Normal file
@@ -0,0 +1,134 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"math/big"
|
||||
"runtime"
|
||||
"strings"
|
||||
"unicode/utf16"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// 平台信息(启动时确定)
|
||||
var (
|
||||
isWindows = runtime.GOOS == "windows"
|
||||
platformKey = runtime.GOOS + "-" + runtime.GOARCH
|
||||
)
|
||||
|
||||
// toWinPath 将路径中的 / 替换为 \
|
||||
func toWinPath(s string) string {
|
||||
return strings.ReplaceAll(s, "/", "\\")
|
||||
}
|
||||
|
||||
// --- 字符串宽度 ---
|
||||
|
||||
func stringWidth(s string) int {
|
||||
w := 0
|
||||
for _, r := range s {
|
||||
w += runeWidth(r)
|
||||
}
|
||||
return w
|
||||
}
|
||||
|
||||
func runeWidth(r rune) int {
|
||||
if r >= 0x1100 &&
|
||||
(r <= 0x115F || r == 0x2329 || r == 0x232A ||
|
||||
(r >= 0x2E80 && r <= 0xA4CF && r != 0x303F) ||
|
||||
(r >= 0xAC00 && r <= 0xD7A3) ||
|
||||
(r >= 0xF900 && r <= 0xFAFF) ||
|
||||
(r >= 0xFE10 && r <= 0xFE19) ||
|
||||
(r >= 0xFE30 && r <= 0xFE6F) ||
|
||||
(r >= 0xFF01 && r <= 0xFF60) ||
|
||||
(r >= 0xFFE0 && r <= 0xFFE6) ||
|
||||
(r >= 0x20000 && r <= 0x2FFFD) ||
|
||||
(r >= 0x30000 && r <= 0x3FFFD)) {
|
||||
return 2
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
func padRightByWidth(s string, targetW int) string {
|
||||
w := stringWidth(s)
|
||||
if w >= targetW {
|
||||
return s
|
||||
}
|
||||
return s + strings.Repeat(" ", targetW-w)
|
||||
}
|
||||
|
||||
func truncateByWidth(s string, maxW int) string {
|
||||
w := 0
|
||||
for i := 0; i < len(s); {
|
||||
r, size := utf8.DecodeRuneInString(s[i:])
|
||||
rw := runeWidth(r)
|
||||
if w+rw > maxW {
|
||||
return s[:i]
|
||||
}
|
||||
w += rw
|
||||
i += size
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func wrapByWidth(s string, maxW int) []string {
|
||||
if maxW <= 0 || s == "" {
|
||||
return []string{s}
|
||||
}
|
||||
var lines []string
|
||||
for s != "" {
|
||||
cut := truncateByWidth(s, maxW)
|
||||
lines = append(lines, cut)
|
||||
s = s[len(cut):]
|
||||
}
|
||||
return lines
|
||||
}
|
||||
|
||||
func fitWidth(s string, w int) string {
|
||||
return padRightByWidth(truncateByWidth(s, w), w)
|
||||
}
|
||||
|
||||
// --- 视口 ---
|
||||
|
||||
func viewport(cursor, total, height int) (int, int) {
|
||||
if total <= height {
|
||||
return 0, total
|
||||
}
|
||||
half := height / 2
|
||||
start := cursor - half
|
||||
if start < 0 {
|
||||
start = 0
|
||||
}
|
||||
end := start + height
|
||||
if end > total {
|
||||
end = total
|
||||
start = end - height
|
||||
if start < 0 {
|
||||
start = 0
|
||||
}
|
||||
}
|
||||
return start, end
|
||||
}
|
||||
|
||||
func padLinesTo(lines []string, w, target int) string {
|
||||
for len(lines) < target {
|
||||
lines = append(lines, strings.Repeat(" ", w))
|
||||
}
|
||||
return strings.Join(lines, "\n")
|
||||
}
|
||||
|
||||
// --- Windows Terminal ---
|
||||
|
||||
func encodePSCommand(script string) string {
|
||||
u16 := utf16.Encode([]rune(script))
|
||||
b := make([]byte, len(u16)*2)
|
||||
for i, r := range u16 {
|
||||
b[i*2] = byte(r)
|
||||
b[i*2+1] = byte(r >> 8)
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString(b)
|
||||
}
|
||||
|
||||
func randRange(min, max int) int {
|
||||
n, _ := rand.Int(rand.Reader, big.NewInt(int64(max-min)))
|
||||
return min + int(n.Int64())
|
||||
}
|
||||
Reference in New Issue
Block a user