Module: OllamaChat::Utils::Chooser

Extended by:
SearchUI, Term::ANSIColor
Defined in:
lib/ollama_chat/utils/chooser.rb

Overview

A module that provides interactive selection functionality using fuzzy matching and search capabilities.

The Chooser module enables users to interactively select items from a list using a search interface with fuzzy matching. It leverages the Amatch library for similarity matching and SearchUI for the interactive display and selection experience.

Examples:

Using the chooser in an interactive menu

entries = ['apple', 'banana', 'cherry']
selected = OllamaChat::Utils::Chooser.choose(entries, prompt: 'Choose a fruit:')

Returning immediately if only one entry exists

entries = ['single_option']
result = OllamaChat::Utils::Chooser.choose(entries, return_immediately: true)
# Returns 'single_option' directly without user interaction

Class Method Summary collapse

Class Method Details

.choose(entries, prompt: 'Search? %s', return_immediately: false) ⇒ Object

The choose method presents a list of entries and prompts the user for input, allowing them to select one entry based on their input.

Examples:

choose(['entry1', 'entry2'], prompt: 'Choose an option:')

Parameters:

  • entries (Array)

    the list of entries to present to the user

  • prompt (String) (defaults to: 'Search? %s')

    the prompt message to display when asking for input (default: ‘Search? %s’)

  • return_immediately (Boolean) (defaults to: false)

    whether to immediately return the first entry if there is only one or nil when there is none (default: false)

Returns:

  • (Object)

    the selected entry, or nil if no entry was chosen



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/ollama_chat/utils/chooser.rb', line 38

def choose(entries, prompt: 'Search? %s', return_immediately: false)
  if return_immediately && entries.size <= 1
    return entries.first
  end
  entry = Search.new(
    prompt:,
    match: -> answer {
      matcher = Amatch::PairDistance.new(answer.downcase)
      matches = entries.map { |n| [ n, -matcher.similar(n.to_s.downcase) ] }.
        select { |_, s| s < 0 }.sort_by(&:last).map(&:first)
      matches.empty? and matches = entries
      matches.first(Tins::Terminal.lines - 1)
    },
    query: -> _answer, matches, selector {
      matches.each_with_index.map { |m, i|
        i == selector ? "#{blue{?⮕}} #{on_blue{m}}" : "  #{m.to_s}"
      } * ?\n
    },
    found: -> _answer, matches, selector {
      matches[selector]
    },
    output: STDOUT
  ).start
  if entry
    entry
  else
    print clear_screen, move_home
    nil
  end
end