Module: Fatty::ChooseApi

Included in:
CallbackEnvironment
Defined in:
lib/fatty/api.rb,
lib/fatty/api/choose.rb

Instance Method Summary collapse

Instance Method Details

#choose(prompt, choices:, initial_choice_idx: 0, cancel_value: nil) ⇒ Object

The consumer can call #choose to cause an interactive popup session to present the user with a series of choices to select from.

Raises:

  • (ArgumentError)


7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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
68
# File 'lib/fatty/api/choose.rb', line 7

def choose(prompt, choices:, initial_choice_idx: 0, cancel_value: nil)
  items = normalize_choices(choices)
  raise ArgumentError, "choices must not be empty" if items.empty?

  labels = items.map(&:first)
  popup = PopUpSession.new(
    source: labels,
    kind: :terminal_choose,
    title: "Choose",
    message: prompt,
    prompt: "Narrow: ",
    current: :top,
    show_counts: false,
    validate_unique_labels: true,
    history: terminal.history,
    history_kind: :popup_filter,
    history_ctx: { kind: :popup_filter, popup: :choose, prompt: prompt.to_s },
  )
  popup.instance_variable_set(:@current, initial_choice_idx.to_i.clamp(0, labels.length - 1))

  done = false
  result = nil

  acc_proc = ->(payload) do
    item = payload[:item]
    idx = labels.index(item)
    result = idx ? items[idx][1] : cancel_value
    done = true
  end
  cancel_proc = -> do
    result = cancel_value
    done = true
  end
  owner = Terminal::PopupOwner.new(on_result: acc_proc, on_cancel: cancel_proc)

  begin
    terminal.apply_command(Fatty::Command.terminal(:push_modal, session: popup, owner: owner))
    terminal.render_frame

    while !done && terminal.running?
      dirty = false
      command = terminal.event_source.next_event

      if command
        terminal.apply_command(command)
        dirty = true
      end

      begin
        dirty ||= !!terminal.tick_active_session
      rescue StandardError => e
        Fatty.error("PromptApi#choose tick failed: #{e.class}: #{e.message}", tag: :terminal)
        dirty = true
      end

      terminal.render_frame if dirty
    end
  ensure
    terminal.render_frame
  end
  result
end

#choose_multi(prompt, choices:, cancel_value: nil) ⇒ Object

The consumer can call #choose_multi to cause an interactive popup session to present the user with a series of choices to select from.

Raises:

  • (ArgumentError)


81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/fatty/api/choose.rb', line 81

def choose_multi(prompt, choices:, cancel_value: nil)
  items = normalize_choices(choices)
  raise ArgumentError, "choices must not be empty" if items.empty?

  labels = items.map(&:first)
  popup = PopUpSession.new(
    source: labels,
    kind: :terminal_choose_multi,
    title: "Choose Many",
    message: prompt,
    prompt: "> ",
    current: :top,
    show_counts: true,
    selection_mode: :multiple,
    validate_unique_labels: true,
    history: terminal.history,
    history_kind: :popup_filter,
    history_ctx: { kind: :popup_filter, popup: :choose_multi, prompt: prompt.to_s },
  )
  done = false
  result = nil

  label_to_value = items.to_h
  acc_proc = ->(payload) do
    selected = payload[:items] || {}
    result =
      selected.each_with_object({}) do |(label, _), h|
      h[label] = label_to_value.fetch(label, cancel_value)
    end
    done = true
  end
  cancel_proc = -> do
    result = cancel_value
    done = true
  end
  owner = Terminal::PopupOwner.new(on_result: acc_proc, on_cancel: cancel_proc)

  begin
    terminal.apply_command(Fatty::Command.terminal(:push_modal, session: popup, owner: owner))
    terminal.render_frame

    while !done && terminal.running?
      dirty = false
      command = terminal.event_source.next_event
      if command
        terminal.apply_command(command)
        dirty = true
      end

      begin
        dirty ||= !!terminal.tick_active_session
      rescue StandardError => e
        Fatty.error("Terminal#choose_multi tick failed: #{e.class}: #{e.message}", tag: :terminal)
        dirty = true
      end

      terminal.render_frame if dirty
    end
  ensure
    terminal.render_frame
  end
  result
end

#confirm(prompt, yes_label: "Yes", no_label: "No", cancel_value: false) ⇒ Object

A simple Yes/No chooser.



71
72
73
74
75
76
77
# File 'lib/fatty/api/choose.rb', line 71

def confirm(prompt, yes_label: "Yes", no_label: "No", cancel_value: false)
  choose(
    prompt,
    choices: { yes_label => true, no_label => false },
    cancel_value: cancel_value,
  )
end