Class: VER::MinorMode

Inherits:
Struct
  • Object
show all
Includes:
Keymap::Results
Defined in:
lib/ver/minor_mode.rb

Overview

A minor mode contains modifications for major modes. It supports unidirectional inheritance to form a tree-like structure together with other instance of MinorMode. Every minor mode maintains its own keymap and performs lookup within that. When no match can be found, the parents will be asked until a definite result is returned.

A MinorMode is expected to interact with the WidgetMajorMode only, not with MajorMode directly.

Modification of a MinorMode will not be fully reflected until the

WidgetMajorMode#synchronize

method has been called and the minor mode is

part of the tree of minors of this major mode.

Constant Summary collapse

MODES =
{}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name) ⇒ MinorMode

Returns a new instance of MinorMode.



43
44
45
46
47
48
49
50
# File 'lib/ver/minor_mode.rb', line 43

def initialize(name)
  self.name = name.to_sym
  self.parents = []
  self.keymap = Keymap.new
  self.receiver = nil

  MODES[self.name] = self
end

Instance Attribute Details

#enter_actionObject

Returns the value of attribute enter_action

Returns:

  • (Object)

    the current value of enter_action



21
22
23
# File 'lib/ver/minor_mode.rb', line 21

def enter_action
  @enter_action
end

#fallback_actionObject

Returns the value of attribute fallback_action

Returns:

  • (Object)

    the current value of fallback_action



21
22
23
# File 'lib/ver/minor_mode.rb', line 21

def fallback_action
  @fallback_action
end

#keymapObject

Returns the value of attribute keymap

Returns:

  • (Object)

    the current value of keymap



21
22
23
# File 'lib/ver/minor_mode.rb', line 21

def keymap
  @keymap
end

#leave_actionObject

Returns the value of attribute leave_action

Returns:

  • (Object)

    the current value of leave_action



21
22
23
# File 'lib/ver/minor_mode.rb', line 21

def leave_action
  @leave_action
end

#nameObject

Returns the value of attribute name

Returns:

  • (Object)

    the current value of name



21
22
23
# File 'lib/ver/minor_mode.rb', line 21

def name
  @name
end

#parentsObject

Returns the value of attribute parents

Returns:

  • (Object)

    the current value of parents



21
22
23
# File 'lib/ver/minor_mode.rb', line 21

def parents
  @parents
end

#receiverObject

Returns the value of attribute receiver

Returns:

  • (Object)

    the current value of receiver



21
22
23
# File 'lib/ver/minor_mode.rb', line 21

def receiver
  @receiver
end

Class Method Details

.[](name) ⇒ Object

Find or create the minor mode for the given name.



28
29
30
31
32
33
34
35
36
# File 'lib/ver/minor_mode.rb', line 28

def self.[](name)
  name = name.to_sym

  if MODES.key?(name)
    MODES[name]
  else
    new(name)
  end
end

.clearObject

Delete all minor modes.



39
40
41
# File 'lib/ver/minor_mode.rb', line 39

def self.clear
  MODES.clear
end

Instance Method Details

#actionsObject



192
193
194
# File 'lib/ver/minor_mode.rb', line 192

def actions
  unfold.map{|minor| minor.keymap.actions }
end

#become(other, *sequences) ⇒ Object



89
90
91
92
93
94
95
# File 'lib/ver/minor_mode.rb', line 89

def become(other, *sequences)
  action = Action.new(receiver, :minor_mode, [self, other])

  sequences.each do |sequence|
    keymap[sequence] = action
  end
end

#enter(invocation, &block) ⇒ Object



113
114
115
116
# File 'lib/ver/minor_mode.rb', line 113

def enter(invocation, &block)
  action = Action.new(receiver, *invocation, &block)
  self.enter_action = action
end

#handler(object) ⇒ Object



123
124
125
# File 'lib/ver/minor_mode.rb', line 123

def handler(object)
  self.receiver = object
end

#inherits(*names) ⇒ Object

Add a parent for this minor mode.



81
82
83
84
85
86
87
# File 'lib/ver/minor_mode.rb', line 81

def inherits(*names)
  names.each do |name|
    minor = self.class[name]
    self.parents << minor unless minor == self
  end
  self.parents.uniq!
end

#inspectObject



200
201
202
# File 'lib/ver/minor_mode.rb', line 200

def inspect
  "#<VER::MinorMode name=%p>" % [name]
end

#leave(invocation, &block) ⇒ Object



118
119
120
121
# File 'lib/ver/minor_mode.rb', line 118

def leave(invocation, &block)
  action = Action.new(receiver, *invocation, &block)
  self.leave_action = action
end

#map(invocation, *sequences, &block) ⇒ Object



97
98
99
100
101
102
103
# File 'lib/ver/minor_mode.rb', line 97

def map(invocation, *sequences, &block)
  action = Action.new(receiver, *invocation, &block)

  sequences.each do |sequence|
    keymap[sequence] = action
  end
end

#missing(invocation, &block) ⇒ Object



105
106
107
108
109
110
111
# File 'lib/ver/minor_mode.rb', line 105

def missing(invocation, &block)
  action = Action.new(receiver, *invocation, &block)
  self.fallback_action = action
  (KEYSYMS.values - keymap.keys.to_a).each do |name|
    keymap[name] = action
  end
end

#replace_parent(widget_major, old, new) ⇒ Object



127
128
129
130
131
132
133
134
135
136
137
# File 'lib/ver/minor_mode.rb', line 127

def replace_parent(widget_major, old, new)
  parents.dup.each do |parent|
    if parent == old
      new.replaces widget_major, old do
        parents[parents.index(old)] = new
      end
    else
      parent.replace_parent(widget_major, old, new)
    end
  end
end

#replaced_by(widget_major, other) ⇒ Object



145
146
147
148
149
150
151
152
# File 'lib/ver/minor_mode.rb', line 145

def replaced_by(widget_major, other)
  return unless widget_major.respond_to?(:widget)
  widget = widget_major.widget
  leave_action.call(widget, self, other) if leave_action
  Tk::Event.generate(widget, "<<LeaveMode>>", data: name)
  Tk::Event.generate(widget, "<<LeaveMinorMode>>", data: name)
  Tk::Event.generate(widget, "<<LeaveMinorMode#{to_camel_case}>>", data: name)
end

#replaces(widget_major, other) ⇒ Object



139
140
141
142
143
# File 'lib/ver/minor_mode.rb', line 139

def replaces(widget_major, other)
  other.replaced_by(widget_major, self) if other
  yield if block_given?
  self.replacing(widget_major, other)
end

#replacing(widget_major, other) ⇒ Object



154
155
156
157
158
159
160
161
# File 'lib/ver/minor_mode.rb', line 154

def replacing(widget_major, other)
  return unless widget_major.respond_to?(:widget)
  widget = widget_major.widget
  enter_action.call(widget, other, self) if enter_action
  Tk::Event.generate(widget, "<<EnterMinorMode#{to_camel_case}>>", data: name)
  Tk::Event.generate(widget, "<<EnterMinorMode>>", data: name)
  Tk::Event.generate(widget, "<<EnterMode>>", data: name)
end

#resolve(sequence) ⇒ Object

recursively try to find the sequence in the minor mode and its parents.



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/ver/minor_mode.rb', line 53

def resolve(sequence)
  case found = keymap[sequence]
  when Incomplete
    parents.each do |parent|
      next if parent == self
      case resolved = parent.resolve(sequence)
      when Incomplete
        found.merge!(resolved)
      end
    end
  when Impossible
    parents.find do |parent|
      next if parent == self
      found = parent.resolve(sequence)
      !found.kind_of?(Impossible)
    end
  else
    found = [self, found]
  end

  if found.kind_of?(Impossible) && fa = self.fallback_action
    return self, fa
  else
    return found
  end
end

#synchronize(widget_major) ⇒ Object



169
170
171
172
173
# File 'lib/ver/minor_mode.rb', line 169

def synchronize(widget_major)
  keymap.keys.each do |key|
    widget_major.bind_key(key)
  end
end

#synchronize_recursively(widget_major) ⇒ Object



163
164
165
166
167
# File 'lib/ver/minor_mode.rb', line 163

def synchronize_recursively(widget_major)
  unfold.each do |minor|
    minor.synchronize(widget_major)
  end
end

#to_camel_caseObject



188
189
190
# File 'lib/ver/minor_mode.rb', line 188

def to_camel_case
  name.to_s.split('_').map{|e| e.capitalize}.join
end

#to_symObject



196
197
198
# File 'lib/ver/minor_mode.rb', line 196

def to_sym
  name
end

#unfold(all = [self]) ⇒ Object



175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/ver/minor_mode.rb', line 175

def unfold(all = [self])
  pending = self.parents.dup

  while current = pending.shift
    unless all.include?(current)
      all << current
      pending.concat(current.unfold(all)).flatten!
    end
  end

  all
end