rum 0.0.1-universal-darwin-10 → 0.0.3-universal-darwin-10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/CHANGELOG +9 -0
  2. data/README.md +35 -0
  3. data/Rakefile +22 -19
  4. data/bin/rum-client +4 -4
  5. data/doc/basic.rb +1 -1
  6. data/doc/doc.html +619 -602
  7. data/doc/example.rb +1 -1
  8. data/doc/reference.rb +29 -16
  9. data/doc/resources/build.rb +14 -12
  10. data/doc/resources/doc.haml +8 -3
  11. data/ext/mac/keyboard_hook/EventTap.h +1 -1
  12. data/ext/mac/keyboard_hook/EventTap.m +9 -9
  13. data/ext/mac/keyboard_hook/KeyboardHook.xcodeproj/project.pbxproj +12 -9
  14. data/ext/windows/keyboard_hook/keyboard_hook.c +3 -3
  15. data/ext/windows/system/autohotkey_stuff.c +12 -10
  16. data/ext/windows/system/clipboard_watcher.c +2 -2
  17. data/ext/windows/system/extconf.rb +1 -0
  18. data/ext/windows/system/input_box.c +9 -9
  19. data/ext/windows/system/system.c +51 -46
  20. data/lib/rum/barrel.rb +46 -16
  21. data/lib/rum/barrel/emacs.rb +1 -1
  22. data/lib/rum/barrel/emacs_client.rb +32 -5
  23. data/lib/rum/core.rb +24 -22
  24. data/lib/rum/dsl.rb +15 -16
  25. data/lib/rum/gui.rb +3 -3
  26. data/lib/rum/help.rb +10 -8
  27. data/lib/rum/hotkey_core.rb +35 -25
  28. data/lib/rum/mac.rb +1 -1
  29. data/lib/rum/mac/gui.rb +1 -1
  30. data/lib/rum/mac/gui/growl.rb +3 -3
  31. data/lib/rum/mac/irb/completion.rb +13 -13
  32. data/lib/rum/mac/keyboard_hook.rb +8 -5
  33. data/lib/rum/mac/keyboard_hook/KeyboardHook.framework/KeyboardHook +0 -0
  34. data/lib/rum/mac/keyboard_hook/KeyboardHook.framework/Versions/A/KeyboardHook +0 -0
  35. data/lib/rum/mac/keyboard_hook/KeyboardHook.framework/Versions/A/Resources/English.lproj/InfoPlist.strings +0 -0
  36. data/lib/rum/mac/keyboard_hook/KeyboardHook.framework/Versions/A/Resources/Info.plist +16 -0
  37. data/lib/rum/mac/layouts.rb +4 -4
  38. data/lib/rum/mac/system.rb +2 -2
  39. data/lib/rum/remote.rb +3 -3
  40. data/lib/rum/server.rb +2 -3
  41. data/lib/rum/windows.rb +2 -1
  42. data/lib/rum/windows/app.rb +12 -7
  43. data/lib/rum/windows/apps.rb +3 -8
  44. data/lib/rum/windows/gui.rb +8 -8
  45. data/lib/rum/windows/keyboard.rb +34 -9
  46. data/lib/rum/windows/layouts.rb +6 -6
  47. data/lib/rum/windows/system.rb +71 -28
  48. data/lib/rum/windows/system_foreign_functions.rb +44 -20
  49. data/rum.gemspec +2 -2
  50. metadata +32 -53
  51. data/README +0 -30
@@ -14,7 +14,7 @@ Encoding.default_external = Encoding::UTF_8
14
14
 
15
15
  module Rum
16
16
  autoload :Server, 'rum/server'
17
-
17
+
18
18
  class << self
19
19
  attr_writer :layout
20
20
  attr_reader :hotkey_set, :hotkey_processor, \
@@ -23,7 +23,7 @@ module Rum
23
23
  def layout
24
24
  @layout ||= Layouts.default_layout
25
25
  end
26
-
26
+
27
27
  def setup
28
28
  return if setup_completed?
29
29
  @hotkey_set = HotkeySet.new(layout)
@@ -60,8 +60,8 @@ module Rum
60
60
  end
61
61
 
62
62
  def display_exception(exception)
63
- error_message = ["#{exception.class}:", exception,
64
- '', *exception.backtrace].join("\n")
63
+ error_message = ["#{exception.class}:\n#{exception}",
64
+ *exception.backtrace].join("\n\n")
65
65
 
66
66
  file, line = parse_stack_frame(exception.backtrace.first)
67
67
  if file
@@ -73,21 +73,8 @@ module Rum
73
73
  end
74
74
  end
75
75
  end
76
-
77
- Gui.message error_message, :sticky, &callback
78
- end
79
76
 
80
- def parse_stack_frame(frame)
81
- if match = frame.match(/^(.+?):(\d+)/)
82
- file, line = match.captures
83
- # Different file names in IRB stackframes:
84
- # Ruby 1.9.1: (eval)
85
- # Ruby 1.9.2: <main>
86
- # MacRuby 0.10: /working_directory/(eval)
87
- if file !~ /\(eval\)$/ and file != '<main>'
88
- [file, line.to_i]
89
- end
90
- end
77
+ Gui.message error_message, :sticky, &callback
91
78
  end
92
79
 
93
80
  def switch_worker_thread
@@ -98,12 +85,27 @@ module Rum
98
85
  @worker_thread = start_worker_thread(new)
99
86
  old.enq nil # Signal the worker thread to stop
100
87
  end
88
+
89
+ def parse_stack_frame(frame)
90
+ if match = frame.match(/^(.+?):(\d+)/)
91
+ file, line = match.captures
92
+ [file, line.to_i] if physical_file? file
93
+ end
94
+ end
95
+
96
+ def physical_file? file
97
+ # Different file names in IRB stackframes:
98
+ # Ruby 1.9.1: (eval)
99
+ # Ruby 1.9.2: <main>
100
+ # MacRuby 0.10: /working_directory/(eval)
101
+ file !~ /\(eval\)$/ and file != '<main>'
102
+ end
101
103
  end
102
104
 
103
- WorkingDir = Dir.pwd
104
-
105
+ InitialWorkingDir = Dir.pwd
106
+
105
107
  def restart
106
- Dir.chdir WorkingDir
108
+ Dir.chdir InitialWorkingDir
107
109
  if Thread.current == Rum::Server.thread
108
110
  Thread.new do
109
111
  sleep 0.01 # Allow server to respond. Slightly hacky.
@@ -114,7 +116,7 @@ module Rum
114
116
  restart_platform_specific
115
117
  end
116
118
  end
117
-
119
+
118
120
  def show
119
121
  System.terminal_window.show
120
122
  end
@@ -1,13 +1,13 @@
1
1
  include Rum
2
- include System
3
- include Keyboard
2
+ include Rum::System
3
+ include Rum::Keyboard
4
4
 
5
5
  module Rum
6
6
  class Action
7
7
  def register
8
8
  Rum.hotkey_set.register(self)
9
9
  end
10
-
10
+
11
11
  def unregister
12
12
  Rum.hotkey_set.unregister(self)
13
13
  end
@@ -27,25 +27,26 @@ module Rum
27
27
  end
28
28
  end
29
29
 
30
- def show
30
+ def visit
31
31
  Gui.open_file(@file, @line)
32
32
  true
33
33
  end
34
34
  end
35
- end
36
35
 
37
- module GuiMixin
38
- # Delegating to Gui instead of directly including Gui avoids dealing
39
- # with module hierarchy corner cases that appear when other modules
40
- # are later dynamically included into Gui via Gui.use.
41
- [:message, :alert, :read, :choose, :open_file, :browse, :goto].each do |method_name|
42
- define_method(method_name) do |*args, &block|
43
- Gui.send(method_name, *args, &block)
36
+ module GuiMixin
37
+ # Delegating to Gui instead of directly including Gui avoids dealing
38
+ # with module hierarchy corner cases that appear when other modules
39
+ # are later dynamically included into Gui via Gui.use.
40
+ [:message, :alert, :read, :choose, :open_file, :browse, :goto].each do |method_name|
41
+ define_method(method_name) do |*args, &block|
42
+ Gui.send(method_name, *args, &block)
43
+ end
44
+ private method_name
44
45
  end
45
- private method_name
46
46
  end
47
47
  end
48
- include GuiMixin
48
+
49
+ include Rum::GuiMixin
49
50
 
50
51
  def wait(timeout=5, interval=0.01)
51
52
  start = Time.new
@@ -87,9 +88,7 @@ class String
87
88
  Rum.hotkey_set.add_translation(self, to, condition,
88
89
  FileLocation.from_stack_frame(caller.first))
89
90
  end
90
- end
91
91
 
92
- class String
93
92
  # Prepare a special version of #do that is only active when the user
94
93
  # calls #do for the first time.
95
94
  # After running Rum.setup it calls and restores the default version of #do.
@@ -1,7 +1,7 @@
1
1
  module Rum
2
2
  module Gui
3
3
  extend self
4
-
4
+
5
5
  def self.use gui_module, *methods
6
6
  if methods.empty?
7
7
  include gui_module
@@ -56,7 +56,7 @@ module Rum
56
56
  private
57
57
 
58
58
  def alert_backend prompt, title
59
- result = dialog('ok-msgbox', '--text', prompt.to_s, '--title', title.to_s)
59
+ result = dialog('ok-msgbox', '--text', prompt.to_s, '--title', title.to_s)
60
60
  result.first == '1'
61
61
  end
62
62
 
@@ -77,7 +77,7 @@ module Rum
77
77
  result = dialog('standard-dropdown', '--items', *choices.map(&:to_s), *prompt)
78
78
  choices[result[1].to_i] if result.first == '1'
79
79
  end
80
-
80
+
81
81
  def dialog *args
82
82
  IO.popen([@@binary, *args]) { |p| p.read }.split
83
83
  end
@@ -4,16 +4,17 @@ module Rum
4
4
  'doc', 'reference.rb')
5
5
  Gui.open_file reference
6
6
  end
7
-
7
+
8
8
  def self.read_key &proc
9
9
  KeyReader.start(hotkey_processor, proc)
10
10
  end
11
11
 
12
- def self.show_hotkey
12
+ def self.visit_hotkey
13
13
  read_key { |hotkey| Gui.message "'#{hotkey}' not active" }
14
14
  Action.hook = lambda do |action|
15
15
  KeyReader.remove_hooks
16
- action.show_definition or Gui.message "Definition location unkown."
16
+ action.visit_definition or Gui.message "Can't visit definition.\n"\
17
+ "Hotkey was not defined in a file."
17
18
  # Must return true for the key that triggered the action to be
18
19
  # retained by the processor.
19
20
  true
@@ -36,7 +37,7 @@ module Rum
36
37
  module KeyReader
37
38
  extend self
38
39
  attr_accessor :pressed_modifiers
39
-
40
+
40
41
  Hook = proc do
41
42
  @pass_key = false
42
43
  if @key.modifier?
@@ -44,7 +45,7 @@ module Rum
44
45
  KeyReader.pressed_modifiers << @key
45
46
  elsif seen_key = KeyReader.pressed_modifiers.delete(@key)
46
47
  if @key == @last_key
47
- KeyReader.stop(@key, @pressed_modifiers)
48
+ KeyReader.stop(@key, @pressed_modifiers)
48
49
  elsif @pressed_modifiers.values.compact.empty?
49
50
  KeyReader.stop
50
51
  end
@@ -55,7 +56,7 @@ module Rum
55
56
  KeyReader.stop(@key, @pressed_modifiers)
56
57
  end
57
58
  end
58
-
59
+
59
60
  def start(hotkey_processor, proc)
60
61
  @hotkey_processor = hotkey_processor
61
62
  @proc = proc
@@ -85,7 +86,7 @@ module Rum
85
86
 
86
87
  module WindowInfo
87
88
  module_function
88
-
89
+
89
90
  def start
90
91
  return if @thread
91
92
  register_stop_key
@@ -96,7 +97,8 @@ module Rum
96
97
  break if @stop
97
98
  new = active_window
98
99
  if new != old
99
- Gui.message new.report
100
+ window_report = new.report
101
+ Gui.message(window_report) { System::Clipboard.set window_report }
100
102
  old = new
101
103
  end
102
104
  sleep 0.1
@@ -1,14 +1,14 @@
1
1
  module Rum
2
2
  class Key
3
3
  attr_accessor :name, :id, :aliases, :modifier
4
-
4
+
5
5
  def initialize name, aliases, id
6
6
  @name = name
7
7
  @id = id
8
8
  @aliases = aliases
9
9
  @modifier = false
10
10
  end
11
-
11
+
12
12
  def modifier?
13
13
  @modifier
14
14
  end
@@ -21,7 +21,7 @@ module Rum
21
21
  class Layout
22
22
  attr_accessor :ids, :names, :aliases, :modifiers, :core_modifiers, \
23
23
  :action_modifiers, :translations
24
-
24
+
25
25
  def initialize
26
26
  @ids = {}
27
27
  @names = {}
@@ -37,7 +37,7 @@ module Rum
37
37
  @ids.values.uniq
38
38
  end
39
39
 
40
- def lookup_id id
40
+ def lookup_key id
41
41
  @ids[id]
42
42
  end
43
43
 
@@ -60,10 +60,11 @@ module Rum
60
60
  name = args.shift
61
61
  aliases = args
62
62
  key = Key.new(name, aliases, id)
63
-
63
+
64
64
  @ids[id] = key
65
65
  @names[name] = key
66
66
  aliases.each { |key_alias| @aliases[key_alias] = key }
67
+ key
67
68
  end
68
69
 
69
70
  def alias key, key_alias
@@ -109,7 +110,7 @@ module Rum
109
110
 
110
111
  class Hotkey
111
112
  attr_accessor :key, :modifiers, :actions, :direction # todo: unveränderlich machen
112
-
113
+
113
114
  def initialize key, modifiers=[], fuzzy=false, actions=[]
114
115
  @key = key
115
116
  @modifiers = modifiers
@@ -136,7 +137,7 @@ module Rum
136
137
  attr_accessor :action, :condition, :hotkey, :location
137
138
 
138
139
  @@hook = nil
139
-
140
+
140
141
  def self.work_queue= queue
141
142
  @@work_queue = queue
142
143
  end
@@ -148,7 +149,7 @@ module Rum
148
149
  def self.hook
149
150
  @@hook
150
151
  end
151
-
152
+
152
153
  def initialize(action, condition, repeated, location)
153
154
  @action = action
154
155
  @condition = condition
@@ -168,8 +169,8 @@ module Rum
168
169
  end
169
170
  end
170
171
 
171
- def show_definition
172
- @location.show if @location
172
+ def visit_definition
173
+ @location.visit if @location
173
174
  end
174
175
  end
175
176
 
@@ -211,7 +212,7 @@ module Rum
211
212
  down_hotkey.direction = :down
212
213
  up_hotkey.direction = :up
213
214
  to_key = @layout[to]
214
-
215
+
215
216
  catch_modifier_up = proc do
216
217
  if down_hotkey.modifiers.include? @key
217
218
  send_key_event(to_key, false)
@@ -248,11 +249,11 @@ module Rum
248
249
  end
249
250
  end
250
251
  modifiers = modifiers.sort_by &:id
251
-
252
+
252
253
  # Lookup key
253
254
  key = @layout[key_alias]
254
255
  raise "#{key_alias} is no valid key." unless key
255
-
256
+
256
257
  Hotkey.new(key, modifiers, fuzzy)
257
258
  end
258
259
 
@@ -269,7 +270,7 @@ module Rum
269
270
  end
270
271
  action
271
272
  end
272
-
273
+
273
274
  def unregister action
274
275
  if hotkey = action.hotkey
275
276
  hotkey.actions.delete(action)
@@ -304,7 +305,7 @@ module Rum
304
305
  end
305
306
  [dict, dict_key]
306
307
  end
307
-
308
+
308
309
  def key_signature hotkey
309
310
  hotkey.modifiers.dup << hotkey.key
310
311
  end
@@ -317,7 +318,7 @@ module Rum
317
318
  def register_hotkey hotkey
318
319
  dict, dict_key = get_dict(hotkey)
319
320
  existing_hotkey = dict[dict_key] and return existing_hotkey
320
-
321
+
321
322
  dict[dict_key] = hotkey
322
323
  if hotkey.key.modifier? # Modifier hotkeys aren't allowed to be fuzzy.
323
324
  @modifier_hotkeys[dict_key] = hotkey
@@ -393,11 +394,12 @@ module Rum
393
394
  @modifiers = @hotkey_set.modifiers
394
395
  @layout = @hotkey_set.layout
395
396
  @pressed_modifiers = {}
397
+ @pressed_core_modifier_ids = {}
396
398
  @was_executed = {}
397
399
  @key_signature = nil
398
400
  @hooks = []
399
401
  @pass_key = true
400
-
402
+
401
403
  @key = nil
402
404
  @last_key = nil
403
405
  @down = nil
@@ -409,12 +411,12 @@ module Rum
409
411
  @hooks.unshift hook
410
412
  hook
411
413
  end
412
-
414
+
413
415
  # Return removed hook.
414
416
  def remove_hook(hook)
415
417
  @hooks.delete hook
416
418
  end
417
-
419
+
418
420
  def key_signature key
419
421
  @modifiers.select { |modifier| @pressed_modifiers[modifier] } << key
420
422
  end
@@ -428,7 +430,7 @@ module Rum
428
430
 
429
431
  def process_event event
430
432
  puts event
431
- @key = @layout.lookup_id(event.id)
433
+ @key = @layout.lookup_key(event.id)
432
434
  @down = event.down?
433
435
  unless @key
434
436
  puts "Unknown Key\n"
@@ -441,10 +443,10 @@ module Rum
441
443
  @key_signature = key_signature(@key)
442
444
  end
443
445
  @last_event_up = !@down
444
-
446
+
445
447
  print "[#{@key_signature.map { |key| key.name.capitalize }.join(', ')}]"
446
448
  print ' (again)' if @key == @last_key; puts
447
-
449
+
448
450
  if @down
449
451
  repeated = @was_executed[@key]
450
452
  eat = @was_executed[@key] = true if execute(true, repeated)
@@ -452,11 +454,13 @@ module Rum
452
454
  eat = true
453
455
  elsif modifier # if repeated, the modifier has already been added to pressed_modifiers
454
456
  @pressed_modifiers[@key] = true
457
+ @pressed_core_modifier_ids[event.id] = true if @layout.core_modifiers[@key]
455
458
  end
456
459
  else #up
457
460
  @was_executed[@key] = true if execute(false, false)
458
461
  if modifier
459
- @pressed_modifiers[@key] = nil
462
+ @pressed_modifiers[@key] = nil
463
+ @pressed_core_modifier_ids[event.id] = nil if @layout.core_modifiers[@key]
460
464
  if @layout.action_modifiers[@key] and \
461
465
  (!@pass_key or @was_executed[@key])
462
466
  inhibit_modifier_action
@@ -464,7 +468,7 @@ module Rum
464
468
  end
465
469
  eat = @was_executed.delete(@key)
466
470
  end
467
-
471
+
468
472
  @pass_key = if modifier
469
473
  @layout.core_modifiers[@key]
470
474
  else
@@ -473,7 +477,13 @@ module Rum
473
477
  @hooks.dup.each { |hook| instance_eval &hook }
474
478
  @last_key = @key
475
479
  puts
476
- @pass_key
480
+ @pass_key
481
+ end
482
+
483
+ def release_core_modifiers
484
+ @pressed_core_modifier_ids.each do |id, pressed|
485
+ send_key_event_for_id id, false if pressed
486
+ end
477
487
  end
478
488
  end
479
489
  end