Skip to content

Commit

Permalink
Merge pull request #15 from koki-develop/quit-manually
Browse files Browse the repository at this point in the history
  • Loading branch information
koki-develop committed Mar 26, 2023
2 parents c500068 + 00787ca commit 19a92ae
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 44 deletions.
31 changes: 22 additions & 9 deletions fzf.go
Expand Up @@ -13,7 +13,9 @@ var defaultFindOption = findOption{

// Fuzzy Finder.
type FZF struct {
option *option
option *option
model *model
program *tea.Program
}

// New returns a new Fuzzy Finder.
Expand All @@ -23,8 +25,12 @@ func New(opts ...Option) *FZF {
opt(&o)
}

m := newModel(&o)

return &FZF{
option: &o,
option: &o,
model: m,
program: tea.NewProgram(m),
}
}

Expand All @@ -47,22 +53,29 @@ func (fzf *FZF) Find(items interface{}, itemFunc func(i int) string, opts ...Fin
if err != nil {
return nil, err
}
m := newModel(fzf, is, &findOption)
fzf.model.setItems(is)
fzf.model.setFindOption(&findOption)

p := tea.NewProgram(m)
if _, err := p.Run(); err != nil {
if _, err := fzf.program.Run(); err != nil {
return nil, err
}

if m.abort {
if fzf.model.abort {
return nil, ErrAbort
}

return m.choices, nil
return fzf.model.choices, nil
}

// Quit quits the Fuzzy Finder.
func (fzf *FZF) Quit() {
fzf.program.Quit()
}

func (fzf *FZF) multiple() bool {
return fzf.option.noLimit || fzf.option.limit > 1
// Abort aborts the Fuzzy Finder.
func (fzf *FZF) Abort() {
fzf.model.abort = true
fzf.Quit()
}

// Option represents a option for the Find.
Expand Down
76 changes: 41 additions & 35 deletions model.go
Expand Up @@ -14,8 +14,8 @@ var (
)

type model struct {
fzf *FZF
items *items
option *option
findOption *findOption

// state
Expand Down Expand Up @@ -46,45 +46,34 @@ type model struct {
input textinput.Model
}

func newModel(fzf *FZF, items *items, opt *findOption) *model {
func newModel(opt *option) *model {
input := textinput.New()
input.Prompt = fzf.option.prompt
input.Placeholder = fzf.option.inputPlaceholder
input.Prompt = opt.prompt
input.Placeholder = opt.inputPlaceholder
input.Focus()

if !fzf.multiple() {
fzf.option.keymap.Toggle.SetEnabled(false)
}

var matches matches
for i := 0; i < items.Len(); i++ {
matches = append(matches, match{
Str: items.String(i),
Index: i,
})
if !opt.multiple() {
opt.keymap.Toggle.SetEnabled(false)
}

return &model{
fzf: fzf,
items: items,
findOption: opt,
option: opt,
// state
abort: false,

cursor: fzf.option.styles.option.cursor.Render(fzf.option.cursor),
nocursor: strings.Repeat(" ", lipgloss.Width(fzf.option.cursor)),
cursor: opt.styles.option.cursor.Render(opt.cursor),
nocursor: strings.Repeat(" ", lipgloss.Width(opt.cursor)),
cursorPosition: 0,

promptWidth: lipgloss.Width(fzf.option.prompt),
promptWidth: lipgloss.Width(opt.prompt),

selectedPrefix: fzf.option.styles.option.selectedPrefix.Render(fzf.option.selectedPrefix),
unselectedPrefix: fzf.option.styles.option.unselectedPrefix.Render(fzf.option.unselectedPrefix),
selectedPrefix: opt.styles.option.selectedPrefix.Render(opt.selectedPrefix),
unselectedPrefix: opt.styles.option.unselectedPrefix.Render(opt.unselectedPrefix),

matchesStyle: fzf.option.styles.option.matches,
cursorLineStyle: fzf.option.styles.option.cursorLine,
cursorLineMatchesStyle: lipgloss.NewStyle().Inherit(fzf.option.styles.option.matches).Inherit(fzf.option.styles.option.cursorLine),
matchesStyle: opt.styles.option.matches,
cursorLineStyle: opt.styles.option.cursorLine,
cursorLineMatchesStyle: lipgloss.NewStyle().Inherit(opt.styles.option.matches).Inherit(opt.styles.option.cursorLine),

matches: matches,
choices: []int{},
// window
windowWidth: 0,
Expand All @@ -95,6 +84,23 @@ func newModel(fzf *FZF, items *items, opt *findOption) *model {
}
}

func (m *model) setItems(items *items) {
var matches matches
for i := 0; i < items.Len(); i++ {
matches = append(matches, match{
Str: items.String(i),
Index: i,
})
}

m.items = items
m.matches = matches
}

func (m *model) setFindOption(findOption *findOption) {
m.findOption = findOption
}

func (m *model) Init() tea.Cmd {
return tea.Batch(
textinput.Blink,
Expand Down Expand Up @@ -122,9 +128,9 @@ func (m *model) headerView() string {
// input
_, _ = v.WriteString(m.input.View())
// count
if m.fzf.option.countViewEnabled {
if m.option.countViewEnabled {
_, _ = v.WriteRune('\n')
_, _ = v.WriteString(m.fzf.option.countViewFunc(m.items.Len(), len(m.matches), m.windowWidth))
_, _ = v.WriteString(m.option.countViewFunc(m.items.Len(), len(m.matches), m.windowWidth))
}

return v.String()
Expand All @@ -150,7 +156,7 @@ func (m *model) itemsView() string {
}

// write toggle
if m.fzf.multiple() {
if m.option.multiple() {
if intContains(m.choices, match.Index) {
_, _ = v.WriteString(m.selectedPrefix)
} else {
Expand Down Expand Up @@ -197,23 +203,23 @@ func (m *model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case tea.KeyMsg:
// key
switch {
case key.Matches(msg, m.fzf.option.keymap.Abort):
case key.Matches(msg, m.option.keymap.Abort):
// abort
m.abort = true
return m, tea.Quit
case key.Matches(msg, m.fzf.option.keymap.Choose):
case key.Matches(msg, m.option.keymap.Choose):
// choose
m.choice()
return m, tea.Quit
case key.Matches(msg, m.fzf.option.keymap.Toggle):
case key.Matches(msg, m.option.keymap.Toggle):
// toggle
m.toggle()
case key.Matches(msg, m.fzf.option.keymap.Up):
case key.Matches(msg, m.option.keymap.Up):
// up
m.cursorUp()
m.fixYPosition()
m.fixCursor()
case key.Matches(msg, m.fzf.option.keymap.Down):
case key.Matches(msg, m.option.keymap.Down):
// down
m.cursorDown()
m.fixYPosition()
Expand Down Expand Up @@ -265,7 +271,7 @@ func (m *model) toggle() {
if intContains(m.choices, match.Index) {
m.choices = intFilter(m.choices, func(i int) bool { return i != match.Index })
} else {
if m.fzf.option.noLimit || len(m.choices) < m.fzf.option.limit {
if m.option.noLimit || len(m.choices) < m.option.limit {
m.choices = append(m.choices, match.Index)
}
}
Expand Down
4 changes: 4 additions & 0 deletions option.go
Expand Up @@ -55,6 +55,10 @@ type option struct {
countViewFunc func(itemsCount, matchesCount, windowWidth int) string
}

func (o *option) multiple() bool {
return o.noLimit || o.limit > 1
}

// Option represents a option for the Fuzzy Finder.
type Option func(o *option)

Expand Down

0 comments on commit 19a92ae

Please sign in to comment.