mirror of
https://github.com/jixishi/SerialTerminalForWindowsTerminal.git
synced 2026-06-15 16:42:46 +00:00
885f6a68cf
- Call enableVTInput after tea.NewProgram to restore VT input mode on Windows (bubbletea v1 conInputReader disables it, breaking Ctrl+Alt+Key combos) - Move normalizeHotkey to internal/config.NormalizeHotkey, eliminate duplicate implementations in tui and console packages - Remove unused Sess() getter from App Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
149 lines
3.3 KiB
Go
149 lines
3.3 KiB
Go
package tui
|
|
|
|
import (
|
|
"strings"
|
|
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
"github.com/jixishi/SerialTerminalForWindowsTerminal/internal/config"
|
|
"github.com/jixishi/SerialTerminalForWindowsTerminal/internal/event"
|
|
)
|
|
|
|
func handleLocalHotkey(m *Model, key string) bool {
|
|
if m.isLocalHotkey(key, "h") {
|
|
modifier := strings.ToUpper(normalizeHotkeyPrefix(m.App.Cfg().HotkeyMod))
|
|
m.App.ShowModal("Shortcuts", modifier+"+C => local exit\nCtrl+C => remote interrupt\n"+modifier+"+F => forward panel\n"+modifier+"+P => plugin panel\n"+modifier+"+M => mode panel\nF1 => shortcut help")
|
|
return true
|
|
}
|
|
if m.isLocalHotkey(key, "f") {
|
|
m.App.OpenPanel(event.UIPanelForward)
|
|
return true
|
|
}
|
|
if m.isLocalHotkey(key, "p") {
|
|
m.App.OpenPanel(event.UIPanelPlugin)
|
|
return true
|
|
}
|
|
if m.isLocalHotkey(key, "m") {
|
|
m.App.OpenPanel(event.UIPanelMode)
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (m *Model) isLocalHotkey(key, action string) bool {
|
|
parts := strings.Split(strings.ToLower(key), "+")
|
|
if len(parts) < 2 || parts[len(parts)-1] != action {
|
|
return false
|
|
}
|
|
|
|
hasCtrl := false
|
|
hasAlt := false
|
|
hasShift := false
|
|
for _, p := range parts[:len(parts)-1] {
|
|
switch p {
|
|
case "ctrl":
|
|
hasCtrl = true
|
|
case "alt":
|
|
hasAlt = true
|
|
case "shift":
|
|
hasShift = true
|
|
}
|
|
}
|
|
|
|
mod := normalizeHotkeyPrefix(m.App.Cfg().HotkeyMod)
|
|
if mod == "ctrl+shift" {
|
|
return hasCtrl && hasShift
|
|
}
|
|
return hasCtrl && hasAlt
|
|
}
|
|
|
|
func normalizeHotkeyPrefix(mod string) string { return config.NormalizeHotkey(mod) }
|
|
|
|
func hotkeyWith(mod, action string) string {
|
|
return normalizeHotkeyPrefix(mod) + "+" + action
|
|
}
|
|
|
|
func parseCtrlKey(key string) (byte, bool) {
|
|
if !strings.HasPrefix(key, "ctrl+") || strings.HasPrefix(key, "ctrl+shift+") {
|
|
return 0, false
|
|
}
|
|
|
|
parts := strings.Split(key, "+")
|
|
if len(parts) != 2 || len(parts[1]) != 1 {
|
|
return 0, false
|
|
}
|
|
ch := parts[1][0]
|
|
if ch < 'a' || ch > 'z' {
|
|
return 0, false
|
|
}
|
|
return ch, true
|
|
}
|
|
|
|
func (m *Model) handleViewportKey(msg tea.KeyMsg) bool {
|
|
if !m.ready || m.showModal {
|
|
return false
|
|
}
|
|
|
|
key := strings.ToLower(msg.String())
|
|
switch key {
|
|
case "pgup", "ctrl+u", "alt+up", "up":
|
|
var cmd tea.Cmd
|
|
m.viewport, cmd = m.viewport.Update(msg)
|
|
_ = cmd
|
|
m.followTail = false
|
|
return true
|
|
case "pgdown", "ctrl+d", "alt+down", "down":
|
|
var cmd tea.Cmd
|
|
m.viewport, cmd = m.viewport.Update(msg)
|
|
_ = cmd
|
|
return true
|
|
case "home":
|
|
m.viewport.GotoTop()
|
|
m.followTail = false
|
|
return true
|
|
case "end":
|
|
m.viewport.GotoBottom()
|
|
m.followTail = true
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
func (m *Model) resetCompletion() {
|
|
m.completionActive = false
|
|
m.completionBase = ""
|
|
m.completionCandidates = nil
|
|
m.completionIndex = 0
|
|
}
|
|
|
|
func (m *Model) stepCompletion(direction int) {
|
|
if len(m.completionCandidates) == 0 {
|
|
m.resetCompletion()
|
|
return
|
|
}
|
|
if direction >= 0 {
|
|
m.completionIndex = (m.completionIndex + 1) % len(m.completionCandidates)
|
|
} else {
|
|
m.completionIndex = (m.completionIndex - 1 + len(m.completionCandidates)) % len(m.completionCandidates)
|
|
}
|
|
m.applyCompletion()
|
|
}
|
|
|
|
func (m *Model) applyCompletion() {
|
|
if len(m.completionCandidates) == 0 {
|
|
return
|
|
}
|
|
m.input.SetValue(m.completionBase + m.completionCandidates[m.completionIndex] + " ")
|
|
}
|
|
|
|
func completionBase(line string) string {
|
|
if strings.HasSuffix(line, " ") {
|
|
return line
|
|
}
|
|
i := strings.LastIndex(line, " ")
|
|
if i < 0 {
|
|
return ""
|
|
}
|
|
return line[:i+1]
|
|
}
|