Class: Textbringer::CompletionPopup

Inherits:
Object
  • Object
show all
Defined in:
lib/textbringer/completion_popup.rb,
sig/lib/textbringer/completion_popup.rbs

Constant Summary collapse

MAX_VISIBLE_ITEMS =
10
MIN_WIDTH =
20
MAX_WIDTH =
60

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeCompletionPopup

Returns a new instance of CompletionPopup.



13
14
15
16
17
18
19
# File 'lib/textbringer/completion_popup.rb', line 13

def initialize
  @floating_window = nil
  @items = []
  @selected_index = 0
  @start_point = nil
  @prefix = ""
end

Instance Attribute Details

#itemsObject (readonly)

Returns the value of attribute items.



7
8
9
# File 'lib/textbringer/completion_popup.rb', line 7

def items
  @items
end

#selected_indexObject (readonly)

Returns the value of attribute selected_index.



7
8
9
# File 'lib/textbringer/completion_popup.rb', line 7

def selected_index
  @selected_index
end

#start_pointObject (readonly)

Returns the value of attribute start_point.



7
8
9
# File 'lib/textbringer/completion_popup.rb', line 7

def start_point
  @start_point
end

Class Method Details

.instanceTextbringer::CompletionPopup



9
10
11
# File 'lib/textbringer/completion_popup.rb', line 9

def self.instance
  @instance ||= new
end

Instance Method Details

#acceptHash[untyped, untyped] #acceptnil

Overloads:

  • #acceptHash[untyped, untyped]

    Returns:

    • (Hash[untyped, untyped])
  • #acceptnil

    Returns:

    • (nil)


67
68
69
70
71
72
# File 'lib/textbringer/completion_popup.rb', line 67

def accept
  return nil unless visible? && !@items.empty?
  item = current_item
  close
  item
end

#calculate_scroll_offset(visible_count) ⇒ Integer

Parameters:

  • (Integer)

Returns:

  • (Integer)


149
150
151
152
153
154
155
# File 'lib/textbringer/completion_popup.rb', line 149

def calculate_scroll_offset(visible_count)
  if @selected_index < visible_count
    0
  else
    @selected_index - visible_count + 1
  end
end

#calculate_widthInteger

Returns:

  • (Integer)


108
109
110
111
112
113
114
115
116
# File 'lib/textbringer/completion_popup.rb', line 108

def calculate_width
  max_label_width = @items.map { |item| display_width(item[:label]) }.max || 0
  max_detail_width = @items.map { |item|
    item[:detail] ? display_width(item[:detail]) + 2 : 0
  }.max || 0

  width = max_label_width + max_detail_width + 2  # padding
  [[width, MIN_WIDTH].max, MAX_WIDTH].min
end

#cancelnil

Returns:

  • (nil)


74
75
76
77
# File 'lib/textbringer/completion_popup.rb', line 74

def cancel
  close
  nil
end

#closeString

Returns:

  • (String)


38
39
40
41
42
43
44
45
46
47
# File 'lib/textbringer/completion_popup.rb', line 38

def close
  if @floating_window
    @floating_window.close
    @floating_window = nil
  end
  @items = []
  @selected_index = 0
  @start_point = nil
  @prefix = ""
end

#create_or_update_windowTextbringer::FloatingWindow



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/textbringer/completion_popup.rb', line 86

def create_or_update_window
  lines = visible_item_count
  columns = calculate_width

  if @floating_window && !@floating_window.deleted?
    @floating_window.resize(lines, columns)
    y, x = FloatingWindow.calculate_cursor_position(lines, columns, Window.current)
    @floating_window.move_to(y: y, x: x)
  else
    @floating_window = FloatingWindow.at_cursor(
      lines: lines,
      columns: columns,
      face: :completion_popup,
      current_line_face: :completion_popup_selected
    )
  end
end

#current_itemHash[untyped, untyped] #current_itemnil

Overloads:

  • #current_itemHash[untyped, untyped]

    Returns:

    • (Hash[untyped, untyped])
  • #current_itemnil

    Returns:

    • (nil)


79
80
81
82
# File 'lib/textbringer/completion_popup.rb', line 79

def current_item
  return nil if @items.empty?
  @items[@selected_index]
end

#display_width(str) ⇒ Integer

Parameters:

  • (String)

Returns:

  • (Integer)


118
119
120
121
# File 'lib/textbringer/completion_popup.rb', line 118

def display_width(str)
  return 0 unless str
  Buffer.display_width(str)
end

#format_item(item) ⇒ String

Parameters:

  • (Hash[untyped, untyped])

Returns:

  • (String)


157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/textbringer/completion_popup.rb', line 157

def format_item(item)
  label = item[:label] || ""
  detail = item[:detail]

  # Build the display string
  result = label
  if detail
    result = "#{label}  #{detail}"
  end

  # Truncate if too long
  width = calculate_width
  if display_width(result) > width
    result = truncate_to_width(result, width - 1) + ""
  end

  result
end

#hideTextbringer::FloatingWindow



34
35
36
# File 'lib/textbringer/completion_popup.rb', line 34

def hide
  @floating_window&.hide
end

#renderInteger

Returns:

  • (Integer)


123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/textbringer/completion_popup.rb', line 123

def render
  buffer = @floating_window.buffer
  buffer.read_only = false
  begin
    buffer.clear

    # Calculate visible range with scroll
    visible_count = visible_item_count
    scroll_offset = calculate_scroll_offset(visible_count)

    visible_items = @items[scroll_offset, visible_count]
    visible_items.each_with_index do |item, index|
      line = format_item(item)
      buffer.insert(line)
      buffer.insert("\n")
    end

    # Go to the selected line so current_line_face highlights it
    relative_index = @selected_index - scroll_offset
    buffer.goto_line(relative_index + 1)
    buffer.beginning_of_line
  ensure
    buffer.read_only = true
  end
end

#select_nextnil

Returns:

  • (nil)


53
54
55
56
57
58
# File 'lib/textbringer/completion_popup.rb', line 53

def select_next
  return unless visible? && !@items.empty?
  @selected_index = (@selected_index + 1) % @items.size
  render
  @floating_window.redisplay
end

#select_previousnil

Returns:

  • (nil)


60
61
62
63
64
65
# File 'lib/textbringer/completion_popup.rb', line 60

def select_previous
  return unless visible? && !@items.empty?
  @selected_index = (@selected_index - 1) % @items.size
  render
  @floating_window.redisplay
end

#show(items:, start_point:, prefix:) ⇒ Textbringer::FloatingWindow #show(items:, start_point:, prefix:) ⇒ nil

Overloads:

  • #show(items:, start_point:, prefix:) ⇒ Textbringer::FloatingWindow

    Parameters:

    • items: (Array[untyped])
    • start_point: (Integer)
    • prefix: (String)

    Returns:

  • #show(items:, start_point:, prefix:) ⇒ nil

    Parameters:

    • items: (Array[untyped])
    • start_point: (Integer)
    • prefix: (String)

    Returns:

    • (nil)


21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/textbringer/completion_popup.rb', line 21

def show(items:, start_point:, prefix: "")
  @items = items
  @start_point = start_point
  @prefix = prefix
  @selected_index = 0

  return if @items.empty?

  create_or_update_window
  render
  @floating_window.show
end

#visible?Boolean

Returns:

  • (Boolean)


49
50
51
# File 'lib/textbringer/completion_popup.rb', line 49

def visible?
  @floating_window&.visible? || false
end

#visible_item_countInteger

Returns:

  • (Integer)


104
105
106
# File 'lib/textbringer/completion_popup.rb', line 104

def visible_item_count
  [@items.size, MAX_VISIBLE_ITEMS].min
end