feat(config): add theme customization (#81)
Added theme customization via config.toml #17 ``` [theme] border = "#665C54" accent = "#FABD2F" muted = "#928374" text = "#EBDBB2" text_sel = "#FBF1C7" match = "#FE8019" desc = "#A89984" desc_sel = "#EBDBB2" sel_bg = "#504945" scroll_info = "#83A598" ghost_text = "#7C6F64" hist= "#fe8019" hist_sel = "#d65d0e" sys = "#fb4934" sys_sel = "#cc241d" alias = "#b8bb26" alias_sel = "#98971a" ``` --------- Co-authored-by: verse91 <versedev.store@proton.me> Co-authored-by: VERSE <sunnyone0901@gmail.com>
This commit is contained in:
+106
-93
@@ -276,8 +276,6 @@ func runWrapper() {
|
||||
|
||||
overlay := integration.NewOverlay()
|
||||
|
||||
|
||||
|
||||
// start background update check (async)
|
||||
pendingUpdate = startBackgroundUpdateCheck()
|
||||
updatePrinted := false
|
||||
@@ -289,10 +287,14 @@ func runWrapper() {
|
||||
var isCommandActive atomic.Bool
|
||||
var disableGhostText atomic.Bool
|
||||
disableGhostText.Store(!config.Get().UI.GhostText)
|
||||
var renderOverlayFn atomic.Value // holds func()
|
||||
renderOverlayFn.Store(func() {})
|
||||
config.AutoDetectConfigChange(func(cfg *config.Config) {
|
||||
disableGhostText.Store(!cfg.UI.GhostText)
|
||||
if renderer, ok := renderOverlayFn.Load().(func()); ok {
|
||||
renderer()
|
||||
}
|
||||
})
|
||||
renderOverlay := func() {}
|
||||
isExecuting := func() bool {
|
||||
if isCommandActive.Load() {
|
||||
// for bash: no preexec/precmd hooks, so fall back to TIOCGPGRP to detect when shell returns
|
||||
@@ -312,14 +314,16 @@ func runWrapper() {
|
||||
return pgrp != shellPGID
|
||||
}
|
||||
|
||||
suggestionsEnabled := true
|
||||
|
||||
// Shared handler for configured navigation keys (e.g. ctrl+j / ctrl+k).
|
||||
// Moves the overlay cursor when visible, otherwise opens history/spec
|
||||
// list and selects the next item in the requested direction.
|
||||
handleNavKey := func(dir string) {
|
||||
intercepted = true
|
||||
userNavigated.Store(true)
|
||||
|
||||
if overlay.IsVisible() {
|
||||
intercepted = true
|
||||
userNavigated.Store(true)
|
||||
|
||||
arrowDir := "down"
|
||||
if dir == "up" {
|
||||
arrowDir = "up"
|
||||
@@ -353,7 +357,12 @@ func runWrapper() {
|
||||
}
|
||||
b.WriteString(overlay.Render())
|
||||
writeStdout([]byte(b.String()))
|
||||
} else {
|
||||
} else if suggestionsEnabled {
|
||||
// hidden-overlay history navigation only when suggestions are enabled;
|
||||
// otherwise let the navigation keys pass through to the shell
|
||||
intercepted = true
|
||||
userNavigated.Store(true)
|
||||
|
||||
activeModeMu.Lock()
|
||||
if activeMode == "" {
|
||||
activeMode = loadMode()
|
||||
@@ -443,8 +452,6 @@ func runWrapper() {
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
|
||||
// listen for suggestion requests from shell scripts via the ipc pipe
|
||||
go func() {
|
||||
defer func() {
|
||||
@@ -565,14 +572,15 @@ func runWrapper() {
|
||||
cursorOffset = 0
|
||||
bufferMu.Unlock()
|
||||
|
||||
renderOverlay()
|
||||
if renderer, ok := renderOverlayFn.Load().(func()); ok {
|
||||
renderer()
|
||||
}
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
logger.Errorf("IPC scanner error: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
suggestionsEnabled := true
|
||||
activeModeMu.Lock()
|
||||
activeMode = loadMode()
|
||||
activeModeMu.Unlock()
|
||||
@@ -651,7 +659,9 @@ func runWrapper() {
|
||||
}
|
||||
SetCurrentAISuggestion(sugg)
|
||||
if overlay.InjectAISuggestion(*sugg) {
|
||||
renderOverlay()
|
||||
if renderer, ok := renderOverlayFn.Load().(func()); ok {
|
||||
renderer()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -693,7 +703,7 @@ func runWrapper() {
|
||||
writeStdout([]byte(b.String()))
|
||||
}
|
||||
|
||||
renderOverlay = func() {
|
||||
renderOverlayFn.Store(func() {
|
||||
renderMu.Lock()
|
||||
defer renderMu.Unlock()
|
||||
|
||||
@@ -718,9 +728,11 @@ func runWrapper() {
|
||||
renderMu.Unlock()
|
||||
renderMenuNow()
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
renderOverlay()
|
||||
if renderer, ok := renderOverlayFn.Load().(func()); ok {
|
||||
renderer()
|
||||
}
|
||||
|
||||
// reads from stdin and decides what to forward or intercept
|
||||
// for most cases, I just handle the already have terminal shortcuts
|
||||
@@ -746,30 +758,30 @@ func runWrapper() {
|
||||
b := inputSlice[i]
|
||||
intercepted = false
|
||||
|
||||
if matched, consumed := config.MatchKey(inputSlice[i:], config.Get().Keybindings.ToggleMenu); matched {
|
||||
intercepted = true
|
||||
suggestionsEnabled = !suggestionsEnabled
|
||||
if !suggestionsEnabled {
|
||||
writeStdout([]byte(overlay.ClearAndDisable()))
|
||||
} else {
|
||||
shouldOverlayDraw = true
|
||||
if matched, consumed := config.MatchKey(inputSlice[i:], config.Get().Keybindings.ToggleMenu); matched {
|
||||
intercepted = true
|
||||
suggestionsEnabled = !suggestionsEnabled
|
||||
if !suggestionsEnabled {
|
||||
writeStdout([]byte(overlay.ClearAndDisable()))
|
||||
} else {
|
||||
shouldOverlayDraw = true
|
||||
}
|
||||
i += consumed - 1
|
||||
continue
|
||||
}
|
||||
i += consumed - 1
|
||||
continue
|
||||
}
|
||||
|
||||
if matched, consumed := config.MatchKey(inputSlice[i:], config.Get().Keybindings.ToggleMode); matched { // ctrl+r: toggle between command specs and command history
|
||||
i += consumed - 1
|
||||
intercepted = true
|
||||
activeModeMu.Lock()
|
||||
if activeMode == "spec" {
|
||||
activeMode = "history"
|
||||
} else {
|
||||
activeMode = "spec"
|
||||
}
|
||||
saveMode(activeMode)
|
||||
activeModeMu.Unlock()
|
||||
if userNavigated.Load() {
|
||||
if matched, consumed := config.MatchKey(inputSlice[i:], config.Get().Keybindings.ToggleMode); matched { // ctrl+r: toggle between command specs and command history
|
||||
i += consumed - 1
|
||||
intercepted = true
|
||||
activeModeMu.Lock()
|
||||
if activeMode == "spec" {
|
||||
activeMode = "history"
|
||||
} else {
|
||||
activeMode = "spec"
|
||||
}
|
||||
saveMode(activeMode)
|
||||
activeModeMu.Unlock()
|
||||
if userNavigated.Load() {
|
||||
bufferMu.Lock()
|
||||
naiveBuffer = overlay.GetTypedQuery()
|
||||
cursorOffset = 0
|
||||
@@ -782,61 +794,60 @@ func runWrapper() {
|
||||
continue
|
||||
}
|
||||
|
||||
var isNavUp, isNavDown bool
|
||||
var navConsumed int
|
||||
if isNavUp, navConsumed = config.MatchKey(inputSlice[i:], config.Get().Keybindings.NavigateUp); !isNavUp {
|
||||
isNavDown, navConsumed = config.MatchKey(inputSlice[i:], config.Get().Keybindings.NavigateDown)
|
||||
}
|
||||
|
||||
if isNavUp || isNavDown {
|
||||
arrowDir := "down"
|
||||
if isNavUp {
|
||||
arrowDir = "up"
|
||||
var isNavUp, isNavDown bool
|
||||
var navConsumed int
|
||||
if isNavUp, navConsumed = config.MatchKey(inputSlice[i:], config.Get().Keybindings.NavigateUp); !isNavUp {
|
||||
isNavDown, navConsumed = config.MatchKey(inputSlice[i:], config.Get().Keybindings.NavigateDown)
|
||||
}
|
||||
handleNavKey(arrowDir)
|
||||
i += navConsumed - 1
|
||||
continue
|
||||
}
|
||||
|
||||
if matched, consumed := config.MatchKey(inputSlice[i:], config.Get().Keybindings.SelectSuggestion); matched && config.Get().Keybindings.SelectSuggestion != "" {
|
||||
if overlay.IsVisible() {
|
||||
intercepted = true
|
||||
selected := overlay.GetCurrentCmd()
|
||||
if selected != "" {
|
||||
activeModeMu.RLock()
|
||||
currentMode := activeMode
|
||||
activeModeMu.RUnlock()
|
||||
if currentMode == "spec" {
|
||||
s := strings.TrimSpace(selected)
|
||||
if strings.HasSuffix(s, "/") || strings.HasSuffix(s, "\\") {
|
||||
selected = s
|
||||
} else {
|
||||
selected = s + " "
|
||||
}
|
||||
}
|
||||
bufferMu.Lock()
|
||||
naiveBuffer = selected
|
||||
cursorOffset = 0
|
||||
bufferMu.Unlock()
|
||||
_, _ = ptmx.Write(append([]byte{0x15}, selected...))
|
||||
|
||||
overlay.ClearGhostTextState()
|
||||
userNavigated.Store(false)
|
||||
writeStdout([]byte(overlay.Render()))
|
||||
renderOverlay()
|
||||
if isNavUp || isNavDown {
|
||||
arrowDir := "down"
|
||||
if isNavUp {
|
||||
arrowDir = "up"
|
||||
}
|
||||
handleNavKey(arrowDir)
|
||||
i += navConsumed - 1
|
||||
continue
|
||||
}
|
||||
|
||||
if matched, consumed := config.MatchKey(inputSlice[i:], config.Get().Keybindings.SelectSuggestion); matched && config.Get().Keybindings.SelectSuggestion != "" {
|
||||
if overlay.IsVisible() {
|
||||
intercepted = true
|
||||
selected := overlay.GetCurrentCmd()
|
||||
if selected != "" {
|
||||
activeModeMu.RLock()
|
||||
currentMode := activeMode
|
||||
activeModeMu.RUnlock()
|
||||
if currentMode == "spec" {
|
||||
s := strings.TrimSpace(selected)
|
||||
if strings.HasSuffix(s, "/") || strings.HasSuffix(s, "\\") {
|
||||
selected = s
|
||||
} else {
|
||||
selected = s + " "
|
||||
}
|
||||
}
|
||||
bufferMu.Lock()
|
||||
naiveBuffer = selected
|
||||
cursorOffset = 0
|
||||
bufferMu.Unlock()
|
||||
_, _ = ptmx.Write(append([]byte{0x15}, selected...))
|
||||
|
||||
overlay.ClearGhostTextState()
|
||||
userNavigated.Store(false)
|
||||
writeStdout([]byte(overlay.Render()))
|
||||
}
|
||||
}
|
||||
// always consume the full binding atomically, even when the overlay is hidden
|
||||
i += consumed - 1
|
||||
continue
|
||||
}
|
||||
}
|
||||
if b == 0x0d || b == 0x0a { // enter
|
||||
intercepted = true
|
||||
|
||||
if b == 0x0d || b == 0x0a { // enter
|
||||
intercepted = true
|
||||
|
||||
if b == 0x0d && i+1 < n && inputSlice[i+1] == 0x0a {
|
||||
if b == 0x0d && i+1 < n && inputSlice[i+1] == 0x0a {
|
||||
i++ // consume trailing \n in \r\n to prevent matching ctrl+j
|
||||
}
|
||||
|
||||
|
||||
var selectedCmd string
|
||||
var shouldAutoExecute bool
|
||||
if overlay.IsVisible() && (config.Get().Core.AutoExecute || userNavigated.Load()) {
|
||||
@@ -925,13 +936,13 @@ func runWrapper() {
|
||||
if !isNavUp {
|
||||
isNavDown, navConsumed = config.MatchKey(inputSlice[i:], config.Get().Keybindings.NavigateDown)
|
||||
}
|
||||
if isNavUp || isNavDown {
|
||||
intercepted = true
|
||||
arrowDir := "down"
|
||||
if isNavUp {
|
||||
arrowDir = "up"
|
||||
}
|
||||
handleNavKey(arrowDir)
|
||||
if isNavUp || isNavDown {
|
||||
intercepted = true
|
||||
arrowDir := "down"
|
||||
if isNavUp {
|
||||
arrowDir = "up"
|
||||
}
|
||||
handleNavKey(arrowDir)
|
||||
i += navConsumed - 1
|
||||
continue
|
||||
}
|
||||
@@ -1073,8 +1084,8 @@ func runWrapper() {
|
||||
continue
|
||||
}
|
||||
|
||||
if !intercepted {
|
||||
_, _ = ptmx.Write([]byte{b})
|
||||
if !intercepted {
|
||||
_, _ = ptmx.Write([]byte{b})
|
||||
// we handle line editing keys manually to keep naiveBuffer in sync
|
||||
// since terminal is in raw mode, we must update our state for every change
|
||||
switch b {
|
||||
@@ -1210,7 +1221,9 @@ func runWrapper() {
|
||||
}
|
||||
}
|
||||
if shouldOverlayDraw {
|
||||
renderOverlay()
|
||||
if renderer, ok := renderOverlayFn.Load().(func()); ok {
|
||||
renderer()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user