summaryrefslogtreecommitdiff
path: root/menu
diff options
context:
space:
mode:
authorewy <ewy0@protonmail.com>2026-05-02 16:23:36 +0200
committerewy <ewy0@protonmail.com>2026-05-02 16:23:36 +0200
commitc01a06e38d0b0331f459cd439ce7706ef1556e50 (patch)
tree8bee63be92b6301d169be6113dfc3bbf16d37c9e /menu
parent1e932e7015ac9d21a1f92ad57cd0c109f58bb29f (diff)
* fix infinite loop on not found
* add bash tab completion script (will have install option in the future) * add search to tui (bound to / and ?)
Diffstat (limited to 'menu')
-rw-r--r--menu/input.go47
-rw-r--r--menu/model.go33
-rw-r--r--menu/search.go11
-rw-r--r--menu/target.go9
4 files changed, 98 insertions, 2 deletions
diff --git a/menu/input.go b/menu/input.go
index cd07543..e2e35b3 100644
--- a/menu/input.go
+++ b/menu/input.go
@@ -3,8 +3,32 @@ package menu
import tea "github.com/charmbracelet/bubbletea"
func (m *Model) HandleInput(msg tea.KeyMsg) (tea.Cmd, error) {
+
+ if m.Search.Focused() {
+ var cmd tea.Cmd
+ switch msg.String() {
+ case "ctrl+c":
+ m.Search.SetValue("")
+ m.Search.Blur()
+ case "ctrl+d":
+ m.Search.Blur()
+ case "enter":
+ m.Search.Blur()
+ default:
+ result, c := m.Search.Update(msg)
+ cmd = c
+ m.Search = result
+ }
+ return cmd, nil
+ }
+
var cmd tea.Cmd
switch msg.String() {
+ case "/":
+ m.Search.SetValue("")
+ fallthrough
+ case "?":
+ return m.Search.Focus(), nil
case "i", "I":
if m.Alt {
m.Alt = false
@@ -23,6 +47,10 @@ func (m *Model) HandleInput(msg tea.KeyMsg) (tea.Cmd, error) {
m.Index--
case "down", "j":
m.Index++
+ case "n":
+ m.LeapFilter(1)
+ case "N":
+ m.LeapFilter(-1)
case "q", "esc", "ctrl+c":
m.Cancel = true
return tea.Quit, nil
@@ -31,11 +59,28 @@ func (m *Model) HandleInput(msg tea.KeyMsg) (tea.Cmd, error) {
return tea.Quit, nil
}
- m.Validate()
+ _ = m.Validate()
return cmd, nil
}
+func (m *Model) LeapFilter(direction int) {
+ startIndex := m.Index
+ for {
+ m.Index += direction
+ clamped := m.Validate()
+ if clamped {
+ m.Index = startIndex
+ return
+ }
+
+ source, target := m.Result()
+ if m.Highlights(source, target) {
+ return
+ }
+ }
+}
+
func (m *Model) Leap(direction int) {
for {
source, target := m.Result()
diff --git a/menu/model.go b/menu/model.go
index aa7b00e..4480c96 100644
--- a/menu/model.go
+++ b/menu/model.go
@@ -1,6 +1,7 @@
package menu
import (
+ "github.com/charmbracelet/bubbles/textinput"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/x/term"
"github.com/ewy1/pik/model"
@@ -9,6 +10,7 @@ import (
"github.com/ewy1/pik/viewport"
"github.com/spf13/pflag"
"os"
+ "strings"
)
type Model struct {
@@ -21,9 +23,31 @@ type Model struct {
Height int
Alt bool
AutoAlt bool
+ Search textinput.Model
Motd string
}
+func (m *Model) Highlights(src *model.HydratedSource, t model.HydratedTarget) bool {
+ val := m.Search.Value()
+ if val == "" {
+ return false
+ }
+
+ if strings.Contains(t.Target().Label(), val) {
+ return true
+ }
+
+ if strings.Contains(t.Description(src), val) {
+ return true
+ }
+
+ if strings.Contains(strings.Join(append(t.Target().Sub(), t.Target().Label()), " "), val) {
+ return true
+ }
+
+ return false
+}
+
func (m *Model) Init() tea.Cmd {
_, h, err := term.GetSize(0)
if err != nil {
@@ -79,6 +103,9 @@ func (m *Model) View() string {
}
result := m.State()
result = viewport.Process(result, m.Height)
+ if m.Search.Focused() {
+ result = m.AddSearch(result)
+ }
return result
}
@@ -89,13 +116,16 @@ func (m *Model) Result() (*model.HydratedSource, model.HydratedTarget) {
return m.SourceIndices[m.Index], m.Indices[m.Index]
}
-func (m *Model) Validate() {
+func (m *Model) Validate() (clamped bool) {
if m.Index < 0 {
m.Index = 0
+ return true
}
if m.Index > len(m.Indices)-1 {
m.Index = len(m.Indices) - 1
+ return true
}
+ return false
}
var ForcedInlineTerminals = map[string]string{
@@ -117,6 +147,7 @@ func NewModel(st *model.State, hydrators []model.Modder) *Model {
SourceIndices: make(map[int]*model.HydratedSource),
AutoAlt: !pflag.Lookup("inline").Changed && !isBanned,
Motd: motd.One(),
+ Search: textinput.New(),
}
idx := 0
for _, src := range st.Sources {
diff --git a/menu/search.go b/menu/search.go
new file mode 100644
index 0000000..79cc03b
--- /dev/null
+++ b/menu/search.go
@@ -0,0 +1,11 @@
+package menu
+
+import "strings"
+
+func (m *Model) AddSearch(croppedInput string) string {
+ lines := strings.Split(croppedInput, "\n")
+ lastIndex := len(lines) - 1
+ view := m.Search.View()
+ lines[lastIndex] = view
+ return strings.Join(lines, "\n")
+}
diff --git a/menu/target.go b/menu/target.go
index f0b35fd..ee31889 100644
--- a/menu/target.go
+++ b/menu/target.go
@@ -14,6 +14,10 @@ var (
st := lipgloss.NewStyle().Border(lipgloss.OuterHalfBlockBorder(), false, false, false, true)
return st
})
+ TargetHighlightedColor = lipgloss.Color("1")
+ TargetHighlightedStyle = style.New(func() lipgloss.Style {
+ return TargetStyle.Get().Foreground(TargetHighlightedColor)
+ })
SelectedTargetStyle = style.New(func() lipgloss.Style {
return TargetStyle.Get().BorderBackground(SelectedTargetBackgroundColor).Background(SelectedTargetBackgroundColor)
})
@@ -59,6 +63,11 @@ func (m *Model) Target(src *model.HydratedSource, t model.HydratedTarget, header
}
selectionStyle := TargetStyle
selectionDescriptionStyle := TargetDescriptionStyle
+
+ if m.Highlights(src, t) {
+ selectionStyle = TargetHighlightedStyle
+ }
+
if selected {
selectionStyle = SelectedTargetStyle
selectionDescriptionStyle = SelectedTargetDescriptionStyle