Class: Fatty::PopUpSession

Inherits:
ModalSession show all
Defined in:
lib/fatty/session/popup_session.rb

Constant Summary collapse

MAX_WIDTH =
120
DEFAULT_HEIGHT =
12
MIN_LIST_H =
1
MAX_LIST_H =
20
MARGIN =
2
SELECTED_GUTTER =
'[X] '
UNSELECTED_GUTTER =
'[ ] '

Instance Attribute Summary collapse

Attributes inherited from ModalSession

#win

Attributes inherited from Session

#counter, #id, #keymap, #terminal

Instance Method Summary collapse

Methods inherited from ModalSession

#close, #handle_resize

Methods inherited from Session

#close, #handle_resize, #persist!, #renderer, #screen, #tick

Methods included from Actionable

included

Constructor Details

#initialize(source:, title: nil, message: nil, prompt: "Narrow: ", keymap: Keymaps.emacs, matcher: nil, order: :as_given, kind: nil, current: :preserve, initial_query: nil, show_counts: true, show_filter: true, selection_mode: :single, history: nil, history_kind: :popup_filter, history_ctx: nil, save_history: true, validate_unique_labels: false) ⇒ PopUpSession

API:

  • source: Proc that returns the candidate list. May accept (query) or be arity 0.
  • matcher: Proc (item, query) -> truthy. Defaults to substring match.
  • order: :as_given (default) or :reverse (presentation order).
  • current: :preserve (default), :top, :bottom (how the current behaves after refresh).


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
69
70
71
72
73
74
75
76
# File 'lib/fatty/session/popup_session.rb', line 23

def initialize(
      source:,
      title: nil,
      message: nil,
      prompt: "Narrow: ",
      keymap: Keymaps.emacs,
      matcher: nil,
      order: :as_given,
      kind: nil,
      current: :preserve,
      initial_query: nil,
      show_counts: true,
      show_filter: true,
      selection_mode: :single,
      history: nil,
      history_kind: :popup_filter,
      history_ctx: nil,
      save_history: true,
      validate_unique_labels: false
    )
  super(keymap: keymap)
  @source = source
  @title = title&.to_s
  @message = message&.to_s
  @prompt = Prompt.ensure(prompt)
  @matcher = matcher || method(:default_matcher)
  @order = order.to_sym
  @kind = kind&.to_sym
  @current_policy = current.to_sym
  @current = nil
  @selection_mode = selection_mode.to_sym
  @show_counts = !!show_counts
  @history = history
  @save_history = !!save_history
  @field = InputField.new(
    prompt: @prompt,
    history: @history,
    history_kind: history_kind,
    history_ctx: history_ctx,
  )
  @show_filter = !!show_filter
  @validate_unique_labels = !!validate_unique_labels
  text = initial_query.to_s
  @field.buffer.replace(text) unless text.empty?

  @items = []
  @filtered = []
  @displayed = []
  @selected_labels = {}

  @last_query = nil
  @scroll_start = 0
  refresh_items
end

Instance Attribute Details

#displayedObject (readonly)

Returns the value of attribute displayed.



7
8
9
# File 'lib/fatty/session/popup_session.rb', line 7

def displayed
  @displayed
end

#fieldObject (readonly)

Returns the value of attribute field.



7
8
9
# File 'lib/fatty/session/popup_session.rb', line 7

def field
  @field
end

#filteredObject (readonly)

Returns the value of attribute filtered.



7
8
9
# File 'lib/fatty/session/popup_session.rb', line 7

def filtered
  @filtered
end

#itemsObject (readonly)

Returns the value of attribute items.



7
8
9
# File 'lib/fatty/session/popup_session.rb', line 7

def items
  @items
end

#messageObject (readonly)

Returns the value of attribute message.



7
8
9
# File 'lib/fatty/session/popup_session.rb', line 7

def message
  @message
end

#promptObject (readonly)

Returns the value of attribute prompt.



7
8
9
# File 'lib/fatty/session/popup_session.rb', line 7

def prompt
  @prompt
end

#titleObject (readonly)

Returns the value of attribute title.



7
8
9
# File 'lib/fatty/session/popup_session.rb', line 7

def title
  @title
end

Instance Method Details

#countsObject



145
146
147
148
149
150
151
152
# File 'lib/fatty/session/popup_session.rb', line 145

def counts
  {
    total: total_count,
    selected: selected_count,
    matching: matching_count,
    showing: showing_count
  }
end

#counts_present?Boolean

Returns:

  • (Boolean)


154
155
156
# File 'lib/fatty/session/popup_session.rb', line 154

def counts_present?
  @show_counts
end

#currentObject



141
142
143
# File 'lib/fatty/session/popup_session.rb', line 141

def current
  current_index
end

#filter_present?Boolean

Returns:

  • (Boolean)


158
159
160
# File 'lib/fatty/session/popup_session.rb', line 158

def filter_present?
  @show_filter
end

#gutter_for(item:, selected:) ⇒ Object



172
173
174
175
176
177
178
# File 'lib/fatty/session/popup_session.rb', line 172

def gutter_for(item:, selected:)
  if multi_select?
    selected_item_label?(item) ? SELECTED_GUTTER : UNSELECTED_GUTTER
  else
    ' '
  end
end

#init(terminal:) ⇒ Object

Session Protocol



82
83
84
85
86
87
# File 'lib/fatty/session/popup_session.rb', line 82

def init(terminal:)
  commands = super
  refresh_items
  rebuild_windows!
  commands.concat(notify_owner(:popup_changed))
end

#replace_query(text) ⇒ Object

During path completion update the popup's candidates.



181
182
183
184
185
186
# File 'lib/fatty/session/popup_session.rb', line 181

def replace_query(text)
  @field.buffer.replace(text.to_s)
  refresh_items
  ensure_scroll_visible
  notify_owner(:popup_changed)
end

#replace_source(source:, title: nil, message: nil, query: "", current: :top) ⇒ Object



188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/fatty/session/popup_session.rb', line 188

def replace_source(source:, title: nil, message: nil, query: "", current: :top)
  @source = source
  @title = title.to_s if title
  @message = message.to_s if message
  @current_policy = current.to_sym
  @field.buffer.replace(query.to_s)
  @last_query = nil
  @scroll_start = 0

  refresh_items
  ensure_scroll_visible
  notify_owner(:popup_changed)
end

#scroll_start(list_h:) ⇒ Object

Renderer calls this to determine which slice of items to display.



163
164
165
166
167
168
169
170
# File 'lib/fatty/session/popup_session.rb', line 163

def scroll_start(list_h:)
  max_start = @displayed.length - list_h
  max_start = 0 if max_start < 0

  @scroll_start = 0 if @scroll_start < 0
  @scroll_start = max_start if @scroll_start > max_start
  @scroll_start
end

#stateObject

Other public API methods



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/fatty/session/popup_session.rb', line 125

def state
  [
    title.to_s.dup.freeze,
    message.to_s.dup.freeze,
    displayed.map { |item| item.to_s.dup.freeze }.freeze,
    current,
    field.buffer.text.to_s.dup.freeze,
    field.buffer.cursor,
    field.buffer.virtual_suffix.to_s.dup.freeze,
    selected_labels.map { |label| label.to_s.dup.freeze }.sort.freeze,
    counts&.dup&.freeze,
    renderer.screen.rows,
    renderer.screen.cols,
  ]
end

#update(command) ⇒ Object



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/fatty/session/popup_session.rb', line 89

def update(command)
  commands =
    case command.action
    when :key
      ev = command.payload.fetch(:event)
      action, args = resolve_action(ev)

      if action
        normalize_action_result(apply_action(action, args, event: ev))
      else
        []
      end
    when :terminal_paste
      text = command.payload.fetch(:text, "").to_s
      env = action_env(event: nil)
      @field.act_on(:paste, text, env: env)
      refresh_items
      ensure_scroll_visible
      []
    else
      []
    end
  Array(commands)
end

#viewObject



114
115
116
117
118
119
# File 'lib/fatty/session/popup_session.rb', line 114

def view
  Fatty.debug("PopupSession#view: object_id=#{object_id} win_nil=#{@win.nil?}", tag: :session)
  return unless @win

  renderer.render_popup(session: self)
end