package fuzzyfinder import ( "context" "sync" ) type opt struct { mode mode previewFunc func(i, width, height int) string multi bool hotReload bool hotReloadLock sync.Locker promptString string header string beginAtTop bool context context.Context query string selectOne bool preselected func(i int) bool } type mode int const ( // ModeSmart enables a smart matching. It is the default matching mode. // At the beginning, matching mode is ModeCaseInsensitive, but it switches // over to ModeCaseSensitive if an upper case character is inputted. ModeSmart mode = iota // ModeCaseSensitive enables a case-sensitive matching. ModeCaseSensitive // ModeCaseInsensitive enables a case-insensitive matching. ModeCaseInsensitive ) var defaultOption = opt{ promptString: "> ", hotReloadLock: &sync.Mutex{}, // this won't resolve the race condition but avoid nil panic preselected: func(i int) bool { return false }, } // Option represents available fuzzy-finding options. type Option func(*opt) // WithMode specifies a matching mode. The default mode is ModeSmart. func WithMode(m mode) Option { return func(o *opt) { o.mode = m } } // WithPreviewWindow enables to display a preview for the selected item. // The argument f receives i, width and height. i is the same as Find's one. // width and height are the size of the terminal so that you can use these to adjust // a preview content. Note that width and height are calculated as a rune-based length. // // If there is no selected item, previewFunc passes -1 to previewFunc. // // If f is nil, the preview feature is disabled. func WithPreviewWindow(f func(i, width, height int) string) Option { return func(o *opt) { o.previewFunc = f } } // WithHotReload reloads the passed slice automatically when some entries are appended. // The caller must pass a pointer of the slice instead of the slice itself. // // Deprecated: use WithHotReloadLock instead. func WithHotReload() Option { return func(o *opt) { o.hotReload = true } } // WithHotReloadLock reloads the passed slice automatically when some entries are appended. // The caller must pass a pointer of the slice instead of the slice itself. // The caller must pass a RLock which is used to synchronize access to the slice. // The caller MUST NOT lock in the itemFunc passed to Find / FindMulti because it will be locked by the fuzzyfinder. // If used together with WithPreviewWindow, the caller MUST use the RLock only in the previewFunc passed to WithPreviewWindow. func WithHotReloadLock(lock sync.Locker) Option { return func(o *opt) { o.hotReload = true o.hotReloadLock = lock } } type cursorPosition int const ( CursorPositionBottom cursorPosition = iota CursorPositionTop ) // WithCursorPosition sets the initial position of the cursor // // If Find is called with WithCursorPosition and WithPreselected, the cursor will be positioned at the first preselected item. func WithCursorPosition(position cursorPosition) Option { return func(o *opt) { switch position { case CursorPositionTop: o.beginAtTop = true case CursorPositionBottom: o.beginAtTop = false } } } // WithPromptString changes the prompt string. The default value is "> ". func WithPromptString(s string) Option { return func(o *opt) { o.promptString = s } } // withMulti enables to select multiple items by tab key. func withMulti() Option { return func(o *opt) { o.multi = true } } // WithHeader enables to set the header. func WithHeader(s string) Option { return func(o *opt) { o.header = s } } // WithContext enables closing the fuzzy finder from parent. func WithContext(ctx context.Context) Option { return func(o *opt) { o.context = ctx } } // WithQuery enables to set the initial query. func WithQuery(s string) Option { return func(o *opt) { o.query = s } } // WithQuery enables to set the initial query. func WithSelectOne() Option { return func(o *opt) { o.selectOne = true } } // WithPreselected enables to specify which items should be preselected. // The argument f is a function that returns true for items that should be preselected. // i is the same index value passed to itemFunc in Find or FindMulti. // This option is effective in both Find and FindMulti, but in Find mode only // the first preselected item will be considered. // // If Find is called with WithCursorPosition and WithPreselected, the cursor will be positioned at the first preselected item. func WithPreselected(f func(i int) bool) Option { return func(o *opt) { o.preselected = f } }