Class: VER::Executor::Entry

Inherits:
VER::Entry
  • Object
show all
Includes:
Keymapped
Defined in:
lib/ver/executor/entry.rb

Constant Summary

Constants inherited from VER::Entry

VER::Entry::BACKWARD_WORD, VER::Entry::FORWARD_WORD

Instance Attribute Summary collapse

Attributes included from Keymapped

#major_mode

Instance Method Summary collapse

Methods included from Keymapped

#minor_mode, #minor_mode?

Methods inherited from VER::Entry

#beginning_of_history, #cursor=, #delete, #delete_motion, #end_of_history, #end_of_line, #error, #insert, #insert_selection, #insert_string, #insert_tab, #kill_end_of_line, #kill_motion, #kill_next_char, #kill_next_word, #kill_prev_char, #kill_prev_word, #message, #next_char, #next_history, #next_word, #prev_char, #prev_word, #previous_history, #quit, #sel_end_of_line, #sel_next_char, #sel_next_word, #sel_prev_char, #sel_prev_word, #sel_start_of_line, #start_of_line, #style, #transpose_chars, #value=, #virtual_movement

Constructor Details

#initialize(parent, options = {}) ⇒ Entry

Returns a new instance of Entry.



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/ver/executor/entry.rb', line 9

def initialize(parent, options = {})
  @callback = options.delete(:callback)
  @caller   = @callback.caller
  @tree     = @callback.tree
  @ybar     = @callback.ybar

  mode = options.delete(:mode)
  options[:style] ||= VER.obtain_style_name('ExEntry', 'TEntry')

  super

  self.parent = parent
  self.major_mode = :Executor
  self.minor_mode(:executor_label, mode) if mode

  self.tabcount = 0
  self.update_on_change = true

  bind('<<Inserted>>'){|event| on_insert(event) }
  bind('<<Deleted>>'){|event|  on_delete(event) }
end

Instance Attribute Details

#callbackObject

Returns the value of attribute callback.



6
7
8
# File 'lib/ver/executor/entry.rb', line 6

def callback
  @callback
end

#callerObject (readonly)

Returns the value of attribute caller.



7
8
9
# File 'lib/ver/executor/entry.rb', line 7

def caller
  @caller
end

#parentObject

Returns the value of attribute parent.



6
7
8
# File 'lib/ver/executor/entry.rb', line 6

def parent
  @parent
end

#tabcountObject

Returns the value of attribute tabcount.



6
7
8
# File 'lib/ver/executor/entry.rb', line 6

def tabcount
  @tabcount
end

#treeObject (readonly)

Returns the value of attribute tree.



7
8
9
# File 'lib/ver/executor/entry.rb', line 7

def tree
  @tree
end

#update_on_changeObject

Returns the value of attribute update_on_change.



6
7
8
# File 'lib/ver/executor/entry.rb', line 6

def update_on_change
  @update_on_change
end

#ybarObject (readonly)

Returns the value of attribute ybar.



7
8
9
# File 'lib/ver/executor/entry.rb', line 7

def ybar
  @ybar
end

Instance Method Details

#accept_line(event) ⇒ Object



147
148
149
150
# File 'lib/ver/executor/entry.rb', line 147

def accept_line(event)
  self.tabcount = 0
  catch(:invalid){ action(tree_selection_value) }
end

#action(value) ⇒ Object

Raises:

  • (NotImplementedError)


130
131
132
133
# File 'lib/ver/executor/entry.rb', line 130

def action(value)
  p action: value
  raise NotImplementedError, "Implement in subclass"
end

#after_updateObject



117
118
# File 'lib/ver/executor/entry.rb', line 117

def after_update
end

#cancel(event) ⇒ Object



135
136
137
# File 'lib/ver/executor/entry.rb', line 135

def cancel(event)
  callback.destroy
end

#completed=(values) ⇒ Object



66
67
68
# File 'lib/ver/executor/entry.rb', line 66

def completed=(values)
  self.value = values.first
end

#completion(event) ⇒ Object



156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/ver/executor/entry.rb', line 156

def completion(event)
  self.tabcount += 1

  if tabcount == 1
    update_only
  else
    items = tree.children(nil)

    if items.size == 1
      self.tabcount = 0
    else
      tree.line_down
    end
  end

  sync_value_with_tree_selection
end

#destroyObject



70
71
72
73
74
75
# File 'lib/ver/executor/entry.rb', line 70

def destroy
  style_name = style
  super
ensure
  VER.return_style_name(style_name)
end

#next_line(event) ⇒ Object



139
140
141
# File 'lib/ver/executor/entry.rb', line 139

def next_line(event)
  tree.line_down
end

#on_delete(event) ⇒ Object

Called on <<Deleted>> events.



38
39
40
41
# File 'lib/ver/executor/entry.rb', line 38

def on_delete(event)
  self.tabcount = 0
  update_only if update_on_change
end

#on_insert(event) ⇒ Object

Called on <<Inserted>> events.



32
33
34
35
# File 'lib/ver/executor/entry.rb', line 32

def on_insert(event)
  self.tabcount = 0
  update_only if update_on_change
end

#prev_line(event) ⇒ Object



143
144
145
# File 'lib/ver/executor/entry.rb', line 143

def prev_line(event)
  tree.line_up
end

#setupObject



63
64
# File 'lib/ver/executor/entry.rb', line 63

def setup
end

#speed_selection(event) ⇒ Object



152
153
154
# File 'lib/ver/executor/entry.rb', line 152

def speed_selection(event)
  accept_line(event)
end

#subset(needle, values, sort_index = 0) ⇒ Object

create a subset of the given values, filtered and sorted by checking relevance against the given needle. If values is an Array of arrays, we only use the first entry of each inner array. Since updating the list is rather cheap, we only sort for now. Sorting is done in a case-insensitive manner by a few simple scoring rules. The best score is given to values that have needle as their beginning. Then come values that include the needle somewhere inside. All others are sorted after that. To account for typos and give relevant similar results, we then refine the score with the levenshtein distance between needle and value. If two values have the same score, they are sorted alphabetically.



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
# File 'lib/ver/executor/entry.rb', line 90

def subset(needle, values, sort_index = 0)
  lower_needle = needle.to_s.downcase

  scored = values.map do |value|
    if value.respond_to?(:to_ary)
      value = value.to_ary
      decider = value[sort_index]
    else
      decider = value
    end

    score = 0
    lower_value = decider.downcase

    if lower_value.start_with?(lower_needle)
      score -= (needle.size + decider.size)
    elsif lower_value.include?(lower_needle)
      score -= decider.size
    end

    score += Levenshtein.distance(lower_needle, lower_value)
    [score, lower_value, value]
  end

  scored.sort.select{|score, lower, value| score < 1 }.map{|score, lower, value| value }
end

#sync_value_with_tree_selectionObject



125
126
127
128
# File 'lib/ver/executor/entry.rb', line 125

def sync_value_with_tree_selection
  return unless value = tree_selection_value
  self.value = value
end

#tree_selection_valueObject



120
121
122
123
# File 'lib/ver/executor/entry.rb', line 120

def tree_selection_value
  return unless item = tree.selection.first
  item.options[:values].first
end

#update_items(values) ⇒ Object



43
44
45
46
47
# File 'lib/ver/executor/entry.rb', line 43

def update_items(values)
  values.map{|value|
    tree.insert(nil, :end, values: [*value])
  }
end

#update_onlyObject



49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/ver/executor/entry.rb', line 49

def update_only
  values = choices(value)
  tree.clear

  items = update_items(values)

  return unless first = items.first

  first.focus
  first.selection_set

  after_update
end