class Chamomile::List
Batteries-included item browser composing Paginator, TextInput, Spinner, Help.
Constants
- DEFAULT_KEY_MAP
- FILTER_APPLIED
- FILTER_FILTERING
- FILTER_UNFILTERED
Attributes
Public Class Methods
Source
# File lib/chamomile/components/list.rb, line 35 def initialize(items:, width: 80, height: 24, delegate: nil, key_map: DEFAULT_KEY_MAP) @id = self.class.next_id @all_items = items.dup @filtered_items = @all_items.dup @width = width @height = height @delegate = delegate @key_map = key_map @title = "" @cursor = 0 @show_title = true @show_filter = true @show_status_bar = true @show_pagination = true @show_help = true @filtering_enabled = true @filter_state = FILTER_UNFILTERED @infinite_scroll = false @spinner_visible = false @status_message = nil @paginator = Paginator.new(per_page: items_per_page) @filter_input = TextInput.new(prompt: "/ ") @spinner = Spinner.new @help = Help.new(width: width) @help_bindings = [ { key: "/", desc: "filter" }, { key: "esc", desc: "clear" }, { key: "q", desc: "quit" }, { key: "?", desc: "more" }, ] recalculate end
Source
# File lib/chamomile/components/list.rb, line 17 def self.next_id @id_mutex.synchronize do if Process.pid != @id_pid @id_pid = Process.pid @next_id = 0 @id_mutex = Mutex.new end @next_id += 1 "#{@id_pid}-lst-#{@next_id}" end end
Public Instance Methods
Source
# File lib/chamomile/components/list.rb, line 130 def cursor_down @cursor = if @infinite_scroll && @cursor >= filtered_count - 1 && filtered_count.positive? 0 else (@cursor + 1).clamp(0, [filtered_count - 1, 0].max) end update_paginator_page end
Source
# File lib/chamomile/components/list.rb, line 121 def cursor_up @cursor = if @infinite_scroll && @cursor.zero? && filtered_count.positive? filtered_count - 1 else (@cursor - 1).clamp(0, [filtered_count - 1, 0].max) end update_paginator_page end
Source
# File lib/chamomile/components/list.rb, line 161 def filter_value @filter_input.value end
Source
# File lib/chamomile/components/list.rb, line 114 def global_index return nil if @filtered_items.empty? item = selected_item @all_items.index(item) end
Source
# File lib/chamomile/components/list.rb, line 144 def goto_end @cursor = [filtered_count - 1, 0].max update_paginator_page end
Source
# File lib/chamomile/components/list.rb, line 139 def goto_start @cursor = 0 update_paginator_page end
Source
# File lib/chamomile/components/list.rb, line 215 def handle(msg) case msg when Chamomile::KeyEvent handle_key(msg) when SpinnerTickMsg @spinner.update(msg) nil when FilterMatchesMsg @filtered_items = msg.matches @cursor = @cursor.clamp(0, [filtered_count - 1, 0].max) recalculate nil when ListStatusTimeoutMsg @status_message = nil if msg.id == @id nil end end
Also aliased as: update
Source
# File lib/chamomile/components/list.rb, line 88 def insert_item(index, item) index = index.clamp(0, @all_items.length) @all_items.insert(index, item) apply_filter recalculate end
Source
# File lib/chamomile/components/list.rb, line 74 def items=(new_items) @all_items = new_items.dup apply_filter recalculate end
Source
# File lib/chamomile/components/list.rb, line 192 def new_status_message(text, lifetime: 1.0) @status_message = text captured_id = @id -> { sleep(lifetime) ListStatusTimeoutMsg.new(id: captured_id) } end
Source
# File lib/chamomile/components/list.rb, line 155 def next_page @paginator.next_page @cursor = @paginator.page * items_per_page @cursor = @cursor.clamp(0, [filtered_count - 1, 0].max) end
Source
# File lib/chamomile/components/list.rb, line 149 def prev_page @paginator.prev_page @cursor = @paginator.page * items_per_page @cursor = @cursor.clamp(0, [filtered_count - 1, 0].max) end
Source
# File lib/chamomile/components/list.rb, line 95 def remove_item(index) return nil if index.negative? || index >= @all_items.length removed = @all_items.delete_at(index) apply_filter recalculate removed end
Source
# File lib/chamomile/components/list.rb, line 165 def reset_filter @filter_input.value = "" @filter_state = FILTER_UNFILTERED @filter_input.blur @filtered_items = @all_items.dup @cursor = 0 recalculate end
Source
# File lib/chamomile/components/list.rb, line 104 def selected_item return nil if @filtered_items.empty? @filtered_items[@cursor] end
Source
# File lib/chamomile/components/list.rb, line 174 def set_filter_text(text) if text.nil? || text.empty? reset_filter return end @filter_input.value = text @filter_state = FILTER_APPLIED @filter_input.blur apply_filter recalculate end
Source
# File lib/chamomile/components/list.rb, line 80 def set_item(index, item) return if index.negative? || index >= @all_items.length @all_items[index] = item apply_filter recalculate end
Source
# File lib/chamomile/components/list.rb, line 211 def spinner_visible? @spinner_visible end
Source
# File lib/chamomile/components/list.rb, line 201 def start_spinner @spinner_visible = true @spinner.tick_cmd end
Source
# File lib/chamomile/components/list.rb, line 206 def stop_spinner @spinner_visible = false nil end
Source
# File lib/chamomile/components/list.rb, line 235 def view sections = [] sections << render_title if @show_title && !@title.empty? sections << render_filter if @show_filter && @filter_state != FILTER_UNFILTERED sections << render_status_bar if @show_status_bar sections << render_items sections << @paginator.view if @show_pagination && @paginator.total_pages > 1 sections << render_help if @show_help sections.compact.reject(&:empty?).join("\n") end
Source
# File lib/chamomile/components/list.rb, line 187 def visible_items start, length = @paginator.slice_bounds(filtered_count) @filtered_items[start, length] || [] end