vimamsa 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/exe/vimamsa +34 -0
- data/lang/hyperplaintext.lang +129 -0
- data/lib/vimamsa.rb +32 -0
- data/lib/vimamsa/ack.rb +35 -0
- data/lib/vimamsa/actions.rb +125 -0
- data/lib/vimamsa/buffer.rb +1731 -0
- data/lib/vimamsa/buffer_list.rb +207 -0
- data/lib/vimamsa/constants.rb +44 -0
- data/lib/vimamsa/debug.rb +142 -0
- data/lib/vimamsa/default_key_bindings.rb +445 -0
- data/lib/vimamsa/easy_jump.rb +161 -0
- data/lib/vimamsa/editor.rb +645 -0
- data/lib/vimamsa/encrypt.rb +47 -0
- data/lib/vimamsa/file_finder.rb +103 -0
- data/lib/vimamsa/file_history.rb +100 -0
- data/lib/vimamsa/file_manager.rb +144 -0
- data/lib/vimamsa/hook.rb +46 -0
- data/lib/vimamsa/hyper_plain_text.rb +61 -0
- data/lib/vimamsa/key_binding_tree.rb +603 -0
- data/lib/vimamsa/macro.rb +177 -0
- data/lib/vimamsa/main.rb +71 -0
- data/lib/vimamsa/rbvma.rb +1014 -0
- data/lib/vimamsa/search.rb +100 -0
- data/lib/vimamsa/search_replace.rb +333 -0
- data/lib/vimamsa/text_transforms.rb +32 -0
- data/lib/vimamsa/util.rb +101 -0
- data/lib/vimamsa/version.rb +1 -1
- data/styles/134272-molokai.xml +33 -0
- data/styles/dark.xml +152 -0
- data/styles/molokai_edit.xml +49 -0
- metadata +31 -2
@@ -0,0 +1,603 @@
|
|
1
|
+
# This file has everyting related to binding key (and other) events
|
2
|
+
# into actions.
|
3
|
+
|
4
|
+
# First letter is mode (C=Command, I=Insert, V=Visual)
|
5
|
+
#
|
6
|
+
# Examples:
|
7
|
+
#
|
8
|
+
# Change mode from INSERT into COMMAND when ctrl key is released immediately
|
9
|
+
# after it has been pressed (there are no other key events between key press and key release).
|
10
|
+
# 'I ctrl!'=> '$kbd.set_mode(:command)',
|
11
|
+
# 'C ctrl!'=> '$kbd.set_mode(:insert)',
|
12
|
+
|
13
|
+
#
|
14
|
+
# In command mode: press keys "," "r" "v" and "b" sequentially.
|
15
|
+
# 'C , r v b'=> 'revert_buffer',
|
16
|
+
#
|
17
|
+
# In insert mode: press and hold ctrl, press "a"
|
18
|
+
# 'I ctrl-a'=> '$buffer.jump(BEGINNING_OF_LINE)',
|
19
|
+
#
|
20
|
+
|
21
|
+
$cnf = {} # TODO
|
22
|
+
|
23
|
+
def conf(id)
|
24
|
+
return $cnf[id]
|
25
|
+
end
|
26
|
+
|
27
|
+
def set_conf(id, val)
|
28
|
+
$cnf[id] = val
|
29
|
+
end
|
30
|
+
|
31
|
+
def setcnf(id, val)
|
32
|
+
set_conf(id, val)
|
33
|
+
end
|
34
|
+
|
35
|
+
setcnf :indent_based_on_last_line, true
|
36
|
+
setcnf :extensions_to_open, [".txt", ".h", ".c", ".cpp", ".hpp", ".rb", ".inc", ".php", ".sh", ".m", ".gd", ".js"]
|
37
|
+
|
38
|
+
class State
|
39
|
+
attr_accessor :key_name, :eval_rule, :children, :action, :label, :major_modes
|
40
|
+
|
41
|
+
def initialize(key_name, eval_rule = "")
|
42
|
+
@key_name = key_name
|
43
|
+
@eval_rule = eval_rule
|
44
|
+
@children = []
|
45
|
+
@major_modes = []
|
46
|
+
@action = nil
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_s()
|
50
|
+
return @key_name
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class KeyBindingTree
|
55
|
+
attr_accessor :C, :I, :cur_state, :root, :match_state, :last_action, :cur_action
|
56
|
+
attr_reader :mode_root_state, :state_trail
|
57
|
+
|
58
|
+
def initialize()
|
59
|
+
@modes = {}
|
60
|
+
@root = State.new("ROOT")
|
61
|
+
@cur_state = @root # used for building the tree
|
62
|
+
@default_mode = nil
|
63
|
+
@mode_history = []
|
64
|
+
@state_trail = []
|
65
|
+
@last_action = nil
|
66
|
+
@cur_action = nil
|
67
|
+
|
68
|
+
@modifiers = [] # TODO: create a queue
|
69
|
+
@last_event = [nil, nil, nil, nil, nil]
|
70
|
+
end
|
71
|
+
|
72
|
+
def set_default_mode(label)
|
73
|
+
@match_state = [@modes[label]] # used for matching input
|
74
|
+
@mode_root_state = @modes[label]
|
75
|
+
@default_mode = label
|
76
|
+
end
|
77
|
+
|
78
|
+
def set_mode_to_default()
|
79
|
+
set_mode(@default_mode)
|
80
|
+
end
|
81
|
+
|
82
|
+
# $kbd.add_mode("I", :insert)
|
83
|
+
def add_mode(id, label)
|
84
|
+
mode = State.new(id)
|
85
|
+
@modes[label] = mode
|
86
|
+
@root.children << mode
|
87
|
+
if @default_mode == nil
|
88
|
+
set_default_mode(label)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def add_minor_mode(id, label, major_mode_label)
|
93
|
+
mode = State.new(id)
|
94
|
+
@modes[label] = mode
|
95
|
+
@root.children << mode
|
96
|
+
mode.major_modes << major_mode_label
|
97
|
+
end
|
98
|
+
|
99
|
+
def clear_modifiers()
|
100
|
+
@modifiers = []
|
101
|
+
end
|
102
|
+
|
103
|
+
def find_state(key_name, eval_rule)
|
104
|
+
@cur_state.children.each { |s|
|
105
|
+
if s.key_name == key_name and s.eval_rule == eval_rule
|
106
|
+
# TODO check eval
|
107
|
+
return s
|
108
|
+
end
|
109
|
+
}
|
110
|
+
return nil
|
111
|
+
end
|
112
|
+
|
113
|
+
def match(key_name)
|
114
|
+
new_state = []
|
115
|
+
@match_state.each { |parent|
|
116
|
+
parent.children.each { |c|
|
117
|
+
# printf(" KEY MATCH: ")
|
118
|
+
# puts [c.key_name, key_name].inspect
|
119
|
+
if c.key_name == key_name and c.eval_rule == ""
|
120
|
+
new_state << c
|
121
|
+
elsif c.key_name == key_name and c.eval_rule != ""
|
122
|
+
puts "CHECK EVAL: #{c.eval_rule}"
|
123
|
+
if eval(c.eval_rule)
|
124
|
+
new_state << c
|
125
|
+
puts "EVAL TRUE"
|
126
|
+
else
|
127
|
+
puts "EVAL FALSE"
|
128
|
+
end
|
129
|
+
end
|
130
|
+
}
|
131
|
+
}
|
132
|
+
if key_name == "o"
|
133
|
+
# Ripl.start :binding => binding
|
134
|
+
end
|
135
|
+
|
136
|
+
if new_state.any? # Match found
|
137
|
+
@match_state = new_state
|
138
|
+
return new_state
|
139
|
+
# return true
|
140
|
+
else # No match found
|
141
|
+
# @match_state = [@C] #TODO
|
142
|
+
return nil
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def set_mode(label)
|
147
|
+
@mode_history << @mode_root_state
|
148
|
+
|
149
|
+
# Check if label in form :label
|
150
|
+
if @modes.has_key?(label)
|
151
|
+
@mode_root_state = @modes[label]
|
152
|
+
set_state_to_root
|
153
|
+
else
|
154
|
+
# Check if label matches mode name in string format
|
155
|
+
for mode in @root.children
|
156
|
+
if mode.key_name == label
|
157
|
+
@mode_root_state = mode
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
$view.draw_cursor()
|
163
|
+
end
|
164
|
+
|
165
|
+
def cur_mode_str()
|
166
|
+
return @mode_root_state.key_name
|
167
|
+
end
|
168
|
+
|
169
|
+
def set_state(key_name, eval_rule = "")
|
170
|
+
new_state = find_state(key_name, eval_rule)
|
171
|
+
if new_state != nil
|
172
|
+
@cur_state = new_state
|
173
|
+
else
|
174
|
+
@cur_state = @mode_root_state # TODO
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
def set_state_to_root
|
179
|
+
if @mode_root_state.major_modes.size == 1
|
180
|
+
modelabel = @mode_root_state.major_modes[0]
|
181
|
+
mmode = @modes[modelabel]
|
182
|
+
@match_state = [@mode_root_state, mmode]
|
183
|
+
else
|
184
|
+
@match_state = [@mode_root_state]
|
185
|
+
end
|
186
|
+
|
187
|
+
@state_trail = [@mode_root_state]
|
188
|
+
# puts get_state_trail_str()
|
189
|
+
# $next_command_count = nil # TODO: set somewhere else?
|
190
|
+
end
|
191
|
+
|
192
|
+
# Print key bindings to show as documentation or for debugging
|
193
|
+
def to_s()
|
194
|
+
s = ""
|
195
|
+
# @cur_state = @root
|
196
|
+
stack = [[@root, ""]]
|
197
|
+
lines = []
|
198
|
+
while stack.any?
|
199
|
+
t, p = *stack.pop # t = current state, p = current path
|
200
|
+
if t.children.any?
|
201
|
+
t.children.reverse.each { |c|
|
202
|
+
if c.eval_rule.size > 0
|
203
|
+
new_p = "#{p} #{c.key_name}(#{c.eval_rule})"
|
204
|
+
else
|
205
|
+
new_p = "#{p} #{c.key_name}"
|
206
|
+
end
|
207
|
+
stack << [c, new_p]
|
208
|
+
}
|
209
|
+
# stack.concat[t.children]
|
210
|
+
else
|
211
|
+
# s += p + " : #{t.action}\n"
|
212
|
+
lines << p + " : #{t.action}"
|
213
|
+
end
|
214
|
+
end
|
215
|
+
s = lines.sort.join("\n")
|
216
|
+
return s
|
217
|
+
end
|
218
|
+
|
219
|
+
def get_state_trail_str
|
220
|
+
s = ""
|
221
|
+
s_trail = ""
|
222
|
+
last_state = @state_trail.last
|
223
|
+
last_state = last_state[0] if last_state.class == Array
|
224
|
+
for st in @state_trail
|
225
|
+
st = st[0] if st.class == Array
|
226
|
+
s_trail << " #{st.to_s}"
|
227
|
+
end
|
228
|
+
s << "CUR STATE: #{s_trail}\n"
|
229
|
+
for cstate in last_state.children
|
230
|
+
act_s = "..."
|
231
|
+
act_s = cstate.action.to_s if cstate.action != nil
|
232
|
+
s << " #{cstate.to_s} #{act_s}\n"
|
233
|
+
end
|
234
|
+
return s
|
235
|
+
end
|
236
|
+
|
237
|
+
# Modifies state of key binding tree (move to new state) based on received event
|
238
|
+
# Checks child nodes of current state if they match received event
|
239
|
+
# if yes, change state to child
|
240
|
+
# if no, go back to root
|
241
|
+
def match_key_conf(c, translated_c, event_type)
|
242
|
+
# $cur_key_dict = $key_bind_dict[$context[:mode]]
|
243
|
+
print "MATCH KEY CONF: #{[c, translated_c]}" if $debug
|
244
|
+
|
245
|
+
# Sometimes we get ASCII-8BIT encoding although content actually UTF-8
|
246
|
+
c = c.force_encoding("UTF-8"); # TODO:correct?
|
247
|
+
|
248
|
+
eval_s = nil
|
249
|
+
|
250
|
+
new_state = match(c)
|
251
|
+
# #TODO:
|
252
|
+
# new_state = match(translated_c)
|
253
|
+
# if new_state == nil and translated_c.index("shift") == 0
|
254
|
+
# new_state = match(c)
|
255
|
+
# end
|
256
|
+
|
257
|
+
if new_state == nil
|
258
|
+
s1 = match_state[0].children.select { |s| s.key_name.include?("<char>") } # TODO: [0]
|
259
|
+
if s1.any? and (c.size == 1) and event_type == :key_press
|
260
|
+
eval_s = s1.first.action.clone
|
261
|
+
# eval_s.gsub!("<char>","'#{c}'") #TODO: remove
|
262
|
+
new_state = [s1.first]
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
if new_state == nil
|
267
|
+
# Child is regexp like /[1-9]/ in:
|
268
|
+
# 'C /[1-9]/'=> 'set_next_command_count(<char>)',
|
269
|
+
# Execute child regexps one until matches
|
270
|
+
s1 = match_state[0].children.select { |s|
|
271
|
+
s.key_name =~ /^\/.*\/$/
|
272
|
+
} # TODO: [0]
|
273
|
+
|
274
|
+
if s1.any? and c.size == 1
|
275
|
+
s1.each { |x|
|
276
|
+
m = /^\/(.*)\/$/.match(x.key_name)
|
277
|
+
if m != nil
|
278
|
+
m2 = Regexp.new(m[1]).match(c)
|
279
|
+
if m2 != nil
|
280
|
+
eval_s = x.action.clone
|
281
|
+
new_state = [x]
|
282
|
+
break
|
283
|
+
end
|
284
|
+
|
285
|
+
return true
|
286
|
+
end
|
287
|
+
}
|
288
|
+
# eval_s = s1.first.action.clone
|
289
|
+
# eval_s.gsub!("<char>","'#{c}'")
|
290
|
+
# new_state = [s1.first]
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
if new_state != nil
|
295
|
+
@state_trail << new_state
|
296
|
+
puts get_state_trail_str()
|
297
|
+
# # puts "CUR STATE: #{@state_trail.collect{|x| x.to_s}.join}"
|
298
|
+
# s_trail = ""
|
299
|
+
# for st in @state_trail
|
300
|
+
# st = st[0] if st.class == Array
|
301
|
+
# s_trail << " #{st.to_s}"
|
302
|
+
# end
|
303
|
+
# puts "CUR STATE: #{s_trail}"
|
304
|
+
# for cstate in new_state[0].children
|
305
|
+
# act_s = "..."
|
306
|
+
# act_s = cstate.action.to_s if cstate.action != nil
|
307
|
+
# puts " #{cstate.to_s} #{act_s}"
|
308
|
+
# end
|
309
|
+
# Ripl.start :binding => binding
|
310
|
+
# new_state[0].children.collect{|x|x.to_s}
|
311
|
+
end
|
312
|
+
|
313
|
+
if new_state == nil
|
314
|
+
printf("NO MATCH") if $debug
|
315
|
+
if event_type == :key_press and c != "shift"
|
316
|
+
# TODO:include other modifiers in addition to shift?
|
317
|
+
set_state_to_root
|
318
|
+
printf(", BACK TO ROOT") if $debug
|
319
|
+
end
|
320
|
+
|
321
|
+
if event_type == :key_release and c == "shift!"
|
322
|
+
# Pressing a modifier key (shift) puts state back to root
|
323
|
+
# only on key release when no other key has been pressed
|
324
|
+
# after said modifier key (shift).
|
325
|
+
set_state_to_root
|
326
|
+
printf(", BACK TO ROOT") if $debug
|
327
|
+
end
|
328
|
+
|
329
|
+
printf("\n") if $debug
|
330
|
+
else
|
331
|
+
|
332
|
+
# Don't execute action if one of the states has children
|
333
|
+
state_with_children = new_state.select { |s| s.children.any? }
|
334
|
+
s_act = new_state.select { |s| s.action != nil }
|
335
|
+
|
336
|
+
if s_act.any? and !state_with_children.any?
|
337
|
+
eval_s = s_act.first.action if eval_s == nil
|
338
|
+
puts "FOUND MATCH:#{eval_s}"
|
339
|
+
puts "CHAR: #{c}"
|
340
|
+
c.gsub!("\\", %q{\\\\} * 4) # Escape \ -chars
|
341
|
+
c.gsub!("'", "#{'\\' * 4}'") # Escape ' -chars
|
342
|
+
|
343
|
+
eval_s.gsub!("<char>", "'#{c}'") if eval_s.class == String
|
344
|
+
puts eval_s
|
345
|
+
puts c
|
346
|
+
handle_key_bindigs_action(eval_s, c)
|
347
|
+
set_state_to_root
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
return true
|
352
|
+
end
|
353
|
+
|
354
|
+
# Receive keyboard event from Qt
|
355
|
+
def handle_key_event(event)
|
356
|
+
start_profiler
|
357
|
+
# puts "GOT KEY EVENT: #{key.inspect}"
|
358
|
+
debug "GOT KEY EVENT:: #{event} #{event[2]}"
|
359
|
+
debug "|#{event.inspect}|"
|
360
|
+
$debuginfo["cur_event"] = event
|
361
|
+
|
362
|
+
t1 = Time.now
|
363
|
+
|
364
|
+
keycode = event[0]
|
365
|
+
event_type = event[1]
|
366
|
+
modifierinfo = event[4]
|
367
|
+
|
368
|
+
event[3] = event[2]
|
369
|
+
# String representation of received key
|
370
|
+
key_str = event[2]
|
371
|
+
|
372
|
+
@modifiers.delete(Qt::Key_Alt) if event[4] & ALTMODIFIER == 0
|
373
|
+
@modifiers.delete(Qt::Key_Control) if event[4] & CONTROLMODIFIER == 0
|
374
|
+
@modifiers.delete(Qt::Key_Shift) if event[4] & SHIFTMODIFIER == 0
|
375
|
+
|
376
|
+
# Add as modifier if ctrl, alt or shift
|
377
|
+
if modifierinfo & ALTMODIFIER != 0 or modifierinfo & CONTROLMODIFIER != 0 or modifierinfo & SHIFTMODIFIER != 0
|
378
|
+
# And keypress and not already a modifier
|
379
|
+
if event_type == KEY_PRESS and !@modifiers.include?(keycode)
|
380
|
+
@modifiers << keycode
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
# puts "----D------------"
|
385
|
+
# puts @modifiers.inspect
|
386
|
+
# puts event.inspect
|
387
|
+
# puts event[4] & ALTMODIFIER
|
388
|
+
# puts "-----------------"
|
389
|
+
|
390
|
+
@modifiers.delete(keycode) if event_type == KEY_RELEASE
|
391
|
+
|
392
|
+
# uval = keyval_to_unicode(event[0])
|
393
|
+
# event[3] = [uval].pack('c*').force_encoding('UTF-8') #TODO: 32bit?
|
394
|
+
# debug("key_code_to_uval: uval: #{uval} uchar:#{event[3]}")
|
395
|
+
|
396
|
+
if $event_keysym_translate_table.include?(keycode)
|
397
|
+
key_str = $event_keysym_translate_table[keycode]
|
398
|
+
end
|
399
|
+
|
400
|
+
# Prefix string representation with modifiers, e.g. ctrl-shift-a
|
401
|
+
key_prefix = ""
|
402
|
+
@modifiers.each { |pressed_key|
|
403
|
+
if $event_keysym_translate_table[pressed_key]
|
404
|
+
key_prefix += $event_keysym_translate_table[pressed_key] + "-"
|
405
|
+
end
|
406
|
+
}
|
407
|
+
|
408
|
+
# Get char based on keycode
|
409
|
+
# to produce prefixed_key_str "shift-ctrl-a" instead of "shift-ctrl-\x01"
|
410
|
+
key_str2 = key_str
|
411
|
+
if $translate_table.include?(keycode)
|
412
|
+
key_str2 = $translate_table[keycode].downcase
|
413
|
+
end
|
414
|
+
# puts "key_str=|#{key_str}| key_str=|#{key_str.inspect}| key_str2=|#{key_str2}|"
|
415
|
+
prefixed_key_str = key_prefix + key_str2
|
416
|
+
|
417
|
+
# Space is only key in $event_keysym_translate_table
|
418
|
+
# which is representable by single char
|
419
|
+
key_str = " " if key_str == "space" # HACK
|
420
|
+
|
421
|
+
# if keycode == @last_event[0] and event_type == KEY_RELEASE
|
422
|
+
# puts "KEY! key_str=|#{key_str}| prefixed_key_str=|#{prefixed_key_str}|"
|
423
|
+
# end
|
424
|
+
|
425
|
+
if key_str != "" or prefixed_key_str != ""
|
426
|
+
if keycode == @last_event[0] and event_type == KEY_RELEASE
|
427
|
+
# If key is released immediately after pressed with no other events between
|
428
|
+
match_key_conf(key_str + "!", prefixed_key_str + "!", event_type)
|
429
|
+
elsif event_type == KEY_PRESS
|
430
|
+
match_key_conf(key_str, prefixed_key_str, event_type)
|
431
|
+
end
|
432
|
+
@last_event = event #TODO: outside if?
|
433
|
+
end
|
434
|
+
|
435
|
+
# qt_refresh_cursor
|
436
|
+
|
437
|
+
event_handle_time = Time.now - t1
|
438
|
+
debug "RB key event handle time: #{event_handle_time}" if event_handle_time > 1 / 40.0
|
439
|
+
render_buffer($buffer)
|
440
|
+
end_profiler
|
441
|
+
end
|
442
|
+
|
443
|
+
def bindkey(key, action)
|
444
|
+
if key.class != Array
|
445
|
+
key = key.split("||")
|
446
|
+
end
|
447
|
+
|
448
|
+
a = action
|
449
|
+
if action.class == Array
|
450
|
+
label = a[0]
|
451
|
+
a = label
|
452
|
+
proc = action[1]
|
453
|
+
msg = action[2]
|
454
|
+
reg_act(label, proc, msg)
|
455
|
+
end
|
456
|
+
key.each { |k| _bindkey(k, a) }
|
457
|
+
end
|
458
|
+
|
459
|
+
def _bindkey(key, action)
|
460
|
+
key.strip!
|
461
|
+
key.gsub!(/\s+/, " ")
|
462
|
+
|
463
|
+
# if key.class == Array
|
464
|
+
# key.each { |k| bindkey(k, action) }
|
465
|
+
# return
|
466
|
+
# end
|
467
|
+
# $action_list << { :action => action, :key => key }
|
468
|
+
if !$actions.has_key?(action)
|
469
|
+
if action.class == String
|
470
|
+
reg_act(action, proc { eval(action) }, action)
|
471
|
+
end
|
472
|
+
end
|
473
|
+
|
474
|
+
m = key.match(/^(\S+)\s(\S.*)$/)
|
475
|
+
if m
|
476
|
+
modetmp = m[1]
|
477
|
+
puts [key, modetmp, m].inspect
|
478
|
+
modes = modetmp.split("") if modetmp.match(/^\p{Lu}+$/) # Uppercase
|
479
|
+
modes = [modetmp] if modetmp.match(/^\p{Ll}+$/) # Lowercase
|
480
|
+
keydef = m[2]
|
481
|
+
else
|
482
|
+
fatal_error("Error in keydef #{key.inspect}")
|
483
|
+
end
|
484
|
+
|
485
|
+
modes.each { |mode_id|
|
486
|
+
mode_bind_key(mode_id, keydef, action)
|
487
|
+
}
|
488
|
+
end
|
489
|
+
|
490
|
+
def mode_bind_key(mode_id, keydef, action)
|
491
|
+
set_state(mode_id, "") # TODO: check is ok?
|
492
|
+
start_state = @cur_state
|
493
|
+
|
494
|
+
k_arr = keydef.split
|
495
|
+
|
496
|
+
prev_state = nil
|
497
|
+
s1 = start_state
|
498
|
+
k_arr.each { |i|
|
499
|
+
# check if key has rules for context like q has in
|
500
|
+
# "C q(cntx.recording_macro==true)"
|
501
|
+
match = /(.+)\((.*)\)/.match(i)
|
502
|
+
eval_rule = ""
|
503
|
+
if match
|
504
|
+
key_name = match[1]
|
505
|
+
eval_rule = match[2]
|
506
|
+
else
|
507
|
+
key_name = i
|
508
|
+
end
|
509
|
+
|
510
|
+
prev_state = s1
|
511
|
+
# Create a new state for key if it doesn't exist
|
512
|
+
s1 = find_state(key_name, eval_rule)
|
513
|
+
if s1 == nil
|
514
|
+
new_state = State.new(key_name, eval_rule)
|
515
|
+
s1 = new_state
|
516
|
+
@cur_state.children << new_state
|
517
|
+
end
|
518
|
+
|
519
|
+
set_state(key_name, eval_rule) # TODO: check is ok?
|
520
|
+
}
|
521
|
+
if action == :delete_state
|
522
|
+
prev_state.children.delete(cur_state)
|
523
|
+
else
|
524
|
+
@cur_state.action = action
|
525
|
+
end
|
526
|
+
@cur_state = @root
|
527
|
+
end
|
528
|
+
|
529
|
+
def handle_key_bindigs_action(action, c)
|
530
|
+
$method_handles_repeat = false #TODO:??
|
531
|
+
n = 1
|
532
|
+
if $next_command_count and !(action.class == String and action.include?("set_next_command_count"))
|
533
|
+
n = $next_command_count
|
534
|
+
# $next_command_count = nil
|
535
|
+
debug("COUNT command #{n} times")
|
536
|
+
end
|
537
|
+
|
538
|
+
begin
|
539
|
+
n.times do
|
540
|
+
ret = exec_action(action)
|
541
|
+
|
542
|
+
if $macro.is_recording and ret != false
|
543
|
+
$macro.record_action(action)
|
544
|
+
end
|
545
|
+
break if $method_handles_repeat
|
546
|
+
# Some methods have specific implementation for repeat,
|
547
|
+
# like '5yy' => copy next five lines. (copy_line())
|
548
|
+
# By default the same command is just repeated n times
|
549
|
+
# like '20j' => go to next line 20 times.
|
550
|
+
end
|
551
|
+
rescue SyntaxError
|
552
|
+
debug("SYNTAX ERROR with eval cmd #{action}: " + $!.to_s)
|
553
|
+
# rescue NoMethodError
|
554
|
+
# debug("NoMethodError with eval cmd #{action}: " + $!.to_s)
|
555
|
+
# rescue NameError
|
556
|
+
# debug("NameError with eval cmd #{action}: " + $!.to_s)
|
557
|
+
# raise
|
558
|
+
rescue Exception => e
|
559
|
+
puts "BACKTRACE"
|
560
|
+
puts e.backtrace
|
561
|
+
puts e.inspect
|
562
|
+
puts "BACKTRACE END"
|
563
|
+
if $!.class == SystemExit
|
564
|
+
exit
|
565
|
+
else
|
566
|
+
crash("Error with action: #{action}: ", e)
|
567
|
+
end
|
568
|
+
end
|
569
|
+
|
570
|
+
if action.class == String and !action.include?("set_next_command_count")
|
571
|
+
$next_command_count = nil
|
572
|
+
end
|
573
|
+
end
|
574
|
+
end
|
575
|
+
|
576
|
+
def bindkey(key, action)
|
577
|
+
$kbd.bindkey(key, action)
|
578
|
+
end
|
579
|
+
|
580
|
+
$action_list = []
|
581
|
+
|
582
|
+
def exec_action(action)
|
583
|
+
$kbd.last_action = $kbd.cur_action
|
584
|
+
$kbd.cur_action = action
|
585
|
+
if action.class == Symbol
|
586
|
+
return call(action)
|
587
|
+
elsif action.class == Proc
|
588
|
+
return action.call
|
589
|
+
else
|
590
|
+
return eval(action)
|
591
|
+
end
|
592
|
+
end
|
593
|
+
|
594
|
+
# Try to clear modifiers when program loses focus
|
595
|
+
# e.g. after alt-tab
|
596
|
+
def focus_out
|
597
|
+
debug "RB Clear modifiers"
|
598
|
+
$kbd.clear_modifiers()
|
599
|
+
end
|
600
|
+
|
601
|
+
def handle_key_event(event)
|
602
|
+
$kbd.handle_key_event(event)
|
603
|
+
end
|