rum 0.0.1-universal-darwin-10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. data/CHANGELOG +3 -0
  2. data/README +30 -0
  3. data/Rakefile +134 -0
  4. data/bin/rum-client +124 -0
  5. data/doc/basic.rb +10 -0
  6. data/doc/doc.html +602 -0
  7. data/doc/example.rb +59 -0
  8. data/doc/reference.rb +415 -0
  9. data/doc/resources/bg.png +0 -0
  10. data/doc/resources/bottom.png +0 -0
  11. data/doc/resources/build.rb +235 -0
  12. data/doc/resources/doc.haml +167 -0
  13. data/doc/resources/emacs-auto-completion.png +0 -0
  14. data/doc/resources/flash.png +0 -0
  15. data/doc/resources/highlight.css +94 -0
  16. data/doc/resources/intro.rb +17 -0
  17. data/doc/resources/left.png +0 -0
  18. data/doc/resources/logo.png +0 -0
  19. data/doc/resources/screen.css +420 -0
  20. data/doc/resources/screenshot.png +0 -0
  21. data/doc/resources/top.png +0 -0
  22. data/ext/mac/keyboard_hook/English.lproj/InfoPlist.strings +0 -0
  23. data/ext/mac/keyboard_hook/Event.h +17 -0
  24. data/ext/mac/keyboard_hook/Event.m +18 -0
  25. data/ext/mac/keyboard_hook/EventTap.h +11 -0
  26. data/ext/mac/keyboard_hook/EventTap.m +77 -0
  27. data/ext/mac/keyboard_hook/Info.plist +26 -0
  28. data/ext/mac/keyboard_hook/KeyboardHook.xcodeproj/TemplateIcon.icns +0 -0
  29. data/ext/mac/keyboard_hook/KeyboardHook.xcodeproj/project.pbxproj +323 -0
  30. data/ext/mac/keyboard_hook/KeyboardHook_Prefix.pch +7 -0
  31. data/ext/mac/keyboard_hook/version.plist +16 -0
  32. data/ext/windows/keyboard_hook/extconf.rb +2 -0
  33. data/ext/windows/keyboard_hook/keyboard_hook.c +126 -0
  34. data/ext/windows/system/autohotkey_stuff.c +255 -0
  35. data/ext/windows/system/autohotkey_stuff.h +2 -0
  36. data/ext/windows/system/clipboard_watcher.c +58 -0
  37. data/ext/windows/system/clipboard_watcher.h +2 -0
  38. data/ext/windows/system/extconf.rb +3 -0
  39. data/ext/windows/system/input_box.c +239 -0
  40. data/ext/windows/system/input_box.h +4 -0
  41. data/ext/windows/system/system.c +273 -0
  42. data/lib/rum.rb +4 -0
  43. data/lib/rum/apps.rb +4 -0
  44. data/lib/rum/barrel.rb +157 -0
  45. data/lib/rum/barrel/emacs.rb +44 -0
  46. data/lib/rum/barrel/emacs_client.rb +74 -0
  47. data/lib/rum/core.rb +125 -0
  48. data/lib/rum/dsl.rb +109 -0
  49. data/lib/rum/gui.rb +93 -0
  50. data/lib/rum/help.rb +128 -0
  51. data/lib/rum/hotkey_core.rb +479 -0
  52. data/lib/rum/mac.rb +18 -0
  53. data/lib/rum/mac/app.rb +4 -0
  54. data/lib/rum/mac/apps.rb +19 -0
  55. data/lib/rum/mac/gui.rb +26 -0
  56. data/lib/rum/mac/gui/CocoaDialog.app/Contents/Info.plist +28 -0
  57. data/lib/rum/mac/gui/CocoaDialog.app/Contents/MacOS/CocoaDialog +0 -0
  58. data/lib/rum/mac/gui/CocoaDialog.app/Contents/Resources/Info.plist +28 -0
  59. data/lib/rum/mac/gui/CocoaDialog.app/Contents/Resources/InfoPlist.strings +0 -0
  60. data/lib/rum/mac/gui/CocoaDialog.app/Contents/Resources/Inputbox.nib/classes.nib +51 -0
  61. data/lib/rum/mac/gui/CocoaDialog.app/Contents/Resources/Inputbox.nib/info.nib +16 -0
  62. data/lib/rum/mac/gui/CocoaDialog.app/Contents/Resources/Inputbox.nib/keyedobjects.nib +0 -0
  63. data/lib/rum/mac/gui/CocoaDialog.app/Contents/Resources/MainMenu.nib/classes.nib +7 -0
  64. data/lib/rum/mac/gui/CocoaDialog.app/Contents/Resources/MainMenu.nib/info.nib +21 -0
  65. data/lib/rum/mac/gui/CocoaDialog.app/Contents/Resources/MainMenu.nib/info.nib.orig +21 -0
  66. data/lib/rum/mac/gui/CocoaDialog.app/Contents/Resources/MainMenu.nib/objects.nib +0 -0
  67. data/lib/rum/mac/gui/CocoaDialog.app/Contents/Resources/MainMenu.nib/objects.nib.orig +0 -0
  68. data/lib/rum/mac/gui/CocoaDialog.app/Contents/Resources/Msgbox.nib/classes.nib +27 -0
  69. data/lib/rum/mac/gui/CocoaDialog.app/Contents/Resources/Msgbox.nib/info.nib +16 -0
  70. data/lib/rum/mac/gui/CocoaDialog.app/Contents/Resources/Msgbox.nib/keyedobjects.nib +0 -0
  71. data/lib/rum/mac/gui/Growl.framework/Growl +0 -0
  72. data/lib/rum/mac/gui/Growl.framework/Versions/A/Growl +0 -0
  73. data/lib/rum/mac/gui/Growl.framework/Versions/A/Headers/Growl.h +6 -0
  74. data/lib/rum/mac/gui/Growl.framework/Versions/A/Headers/GrowlApplicationBridge-Carbon.h +780 -0
  75. data/lib/rum/mac/gui/Growl.framework/Versions/A/Headers/GrowlApplicationBridge.h +575 -0
  76. data/lib/rum/mac/gui/Growl.framework/Versions/A/Headers/GrowlDefines.h +348 -0
  77. data/lib/rum/mac/gui/Growl.framework/Versions/A/Resources/Info.plist +24 -0
  78. data/lib/rum/mac/gui/growl.rb +54 -0
  79. data/lib/rum/mac/irb/completion.rb +207 -0
  80. data/lib/rum/mac/keyboard_hook.rb +73 -0
  81. data/lib/rum/mac/keyboard_hook/KeyboardHook.framework/KeyboardHook +0 -0
  82. data/lib/rum/mac/keyboard_hook/KeyboardHook.framework/Versions/A/KeyboardHook +0 -0
  83. data/lib/rum/mac/keyboard_hook/KeyboardHook.framework/Versions/A/Resources/English.lproj/InfoPlist.strings +0 -0
  84. data/lib/rum/mac/keyboard_hook/KeyboardHook.framework/Versions/A/Resources/Info.plist +22 -0
  85. data/lib/rum/mac/layouts.rb +146 -0
  86. data/lib/rum/mac/system.rb +45 -0
  87. data/lib/rum/remote.rb +48 -0
  88. data/lib/rum/server.rb +92 -0
  89. data/lib/rum/windows.rb +23 -0
  90. data/lib/rum/windows/app.rb +72 -0
  91. data/lib/rum/windows/apps.rb +25 -0
  92. data/lib/rum/windows/gui.rb +116 -0
  93. data/lib/rum/windows/keyboard.rb +80 -0
  94. data/lib/rum/windows/keyboard_hook.rb +20 -0
  95. data/lib/rum/windows/layouts.rb +232 -0
  96. data/lib/rum/windows/system.rb +310 -0
  97. data/lib/rum/windows/system_foreign_functions.rb +129 -0
  98. data/rum.gemspec +14 -0
  99. metadata +166 -0
@@ -0,0 +1,4 @@
1
+ require 'rum/core'
2
+ require 'rum/dsl'
3
+
4
+ puts "Rum loaded."
@@ -0,0 +1,4 @@
1
+ case Platform
2
+ when :mac then require 'rum/mac/apps'
3
+ when :windows then require 'rum/windows/apps'
4
+ end
@@ -0,0 +1,157 @@
1
+ # encoding: utf-8
2
+
3
+ module Rum
4
+ class Path
5
+ def self.contents dir
6
+ paths = []
7
+ dir = File.join(dir, '')
8
+ dir_dots = /(?:^|\/)\.\.?$/ # /.. or /.
9
+ Dir.glob(dir + '**/*', File::FNM_DOTMATCH).each do |path|
10
+ sub_path = path[(dir.length)..-1].encode(Encoding::UTF_8, \
11
+ Encoding::ISO_8859_1)
12
+ paths << sub_path unless sub_path =~ dir_dots
13
+ end
14
+ paths
15
+ end
16
+
17
+ def self.select dir
18
+ path = Gui.choose(nil, contents(dir))
19
+ (File.join(dir, path)) if path
20
+ end
21
+
22
+ def self.run path
23
+ start path
24
+ end
25
+
26
+ def self.select_and_run dir
27
+ path = select(dir)
28
+ run path if path
29
+ end
30
+
31
+ def self.sanitize path
32
+ path.gsub(/[\/\\|?*><":]/, '-')
33
+ end
34
+
35
+ def self.normalize path
36
+ path.gsub('\\', '/')
37
+ end
38
+ end
39
+
40
+ module AppDir
41
+ class << self
42
+ attr_accessor :base_dir
43
+
44
+ def get(exe)
45
+ File.join(@base_dir, exe, '')
46
+ end
47
+
48
+ def get_or_create(exe)
49
+ dir = get(exe)
50
+ if File.exists? dir
51
+ dir
52
+ else
53
+ prompt = "App-Dir für #{exe.capitalize} anlegen?"
54
+ if "Erzeugen" == Gui.choose(prompt, ["Erzeugen", "Nicht erzeugen"])
55
+ Dir.mkdir dir
56
+ dir
57
+ end
58
+ end
59
+ end
60
+
61
+ def current
62
+ get_or_create(active_window.exe_name)
63
+ end
64
+
65
+ def visit
66
+ dir = current
67
+ Dopus.go dir if dir
68
+ end
69
+
70
+ def select
71
+ dir = current
72
+ Path.select_and_run dir if dir
73
+ end
74
+ end
75
+ end
76
+
77
+ module Commands
78
+ class Command
79
+ def initialize(name, proc)
80
+ @name = name
81
+ @proc = proc
82
+ end
83
+
84
+ def to_s
85
+ @name
86
+ end
87
+
88
+ def run
89
+ @proc.call
90
+ end
91
+ end
92
+
93
+ class << self
94
+ attr_accessor :default_tag
95
+ attr_accessor :commands
96
+ Commands.commands = {}
97
+
98
+ def command(name, *args, &block)
99
+ args = args.first
100
+ tag = args[:tag] if args
101
+ tags = []
102
+ tags << tag if tag
103
+ tags << default_tag
104
+ tags.uniq!
105
+
106
+ if args and (hotkey = args[:hotkey])
107
+ apps = tags.select { |tag| tag.is_a? App }
108
+ apps.each { |app| hotkey.do(app, &block) }
109
+ end
110
+
111
+ cmd = Command.new(name, block)
112
+ tags.each do |tag|
113
+ commands_for_tag = (commands[tag] ||= {})
114
+ commands_for_tag[name] = cmd
115
+ end
116
+ end
117
+
118
+ def [] (tag=nil)
119
+ if (cmds = @commands[tag])
120
+ cmds.values
121
+ else
122
+ []
123
+ end
124
+ end
125
+
126
+ def select(tag=nil)
127
+ cmd = Gui.choose(nil, self[tag])
128
+ cmd.run if cmd
129
+ end
130
+
131
+ def for_active_window
132
+ cmds = []
133
+ exe = active_window.exe_name
134
+ app = App.for_exe(exe)
135
+ cmds.concat self[app] if app
136
+ if (dir = AppDir.get(exe))
137
+ cmds.concat Path.contents(dir)
138
+ end
139
+ if (chosen = Gui.choose(nil, cmds))
140
+ case chosen
141
+ when String
142
+ Path.run(dir + chosen)
143
+ else
144
+ chosen.run
145
+ end
146
+ end
147
+ end
148
+ end
149
+ end
150
+
151
+ def Commands(tag=nil, &block)
152
+ Commands.default_tag = tag
153
+ Commands.instance_eval(&block)
154
+ ensure
155
+ Commands.default_tag = nil
156
+ end
157
+ end
@@ -0,0 +1,44 @@
1
+ require 'rum/barrel/emacs_client'
2
+
3
+ class << Emacs
4
+ attr_accessor :client, :eval_in_user_buffer
5
+
6
+ Emacs.client = EmacsClient.new
7
+
8
+ def eval(elisp)
9
+ # MacRuby hack
10
+ # @client.eval fails
11
+ elisp = "(with-current-buffer (window-buffer) #{elisp})" if @eval_in_user_buffer
12
+ Emacs.client.eval(elisp)
13
+ end
14
+
15
+ def funcall(*args)
16
+ eval("(#{args.join(' ')})")
17
+ end
18
+
19
+ Quoting = [["\n", '\n'],
20
+ ['"', '\\"']]
21
+
22
+ def quote(str)
23
+ str.gsub!('\\', '\\\\\\\\')
24
+ Quoting.each { |from, to| str.gsub!(from, to) }
25
+ '"' << str << '"'
26
+ end
27
+
28
+ def unquote(str)
29
+ Quoting.reverse.each { |from, to| str.gsub!(to, from) }
30
+ str.gsub('\\\\', '\\').chomp[1..-2]
31
+ end
32
+
33
+ def find_file(path, line)
34
+ line = if line.is_a? Fixnum
35
+ "(goto-line #{line})"
36
+ end
37
+ eval("(progn (find-file \"#{path}\")#{line})")
38
+ end
39
+
40
+ def open_file(path, line=nil)
41
+ Emacs.activate
42
+ Emacs.find_file(path, line)
43
+ end
44
+ end
@@ -0,0 +1,74 @@
1
+ require 'socket'
2
+
3
+ # Ruby implementation of
4
+ # emacs_source/lib-src/emacsclient.c
5
+
6
+ class EmacsClient
7
+ def eval(elisp)
8
+ socket = connect
9
+ socket.puts "-eval #{quote(elisp)}"
10
+ result = unquote(socket.read)
11
+ socket.close
12
+ format(result)
13
+ end
14
+
15
+ def format(str)
16
+ str[/.*? (.*)/, 1]
17
+ end
18
+
19
+ def quote str
20
+ r = str.gsub(/&|^-/, '&\&').gsub("\n", '&n').gsub(' ', '&_')
21
+ end
22
+
23
+ def unquote str
24
+ str.gsub(/&(.)/) do
25
+ case $1
26
+ when 'n'; "\n"
27
+ when '_'; ' '
28
+ else $1
29
+ end
30
+ end
31
+ end
32
+
33
+ if RUBY_PLATFORM =~ /mswin|mingw/
34
+ attr_accessor :ip, :port, :auth_string
35
+
36
+ def initialize
37
+ @server_file = File.join(ENV['HOME'], '.emacs.d', 'server', 'server')
38
+ read_config
39
+ end
40
+
41
+ def read_config
42
+ @server_active = File.exists? @server_file
43
+ return unless @server_active
44
+ lines = File.readlines(@server_file)
45
+ @ip, @port = lines.first.match(/(.*?):(\d+)/).captures
46
+ @auth_string = lines.last
47
+ end
48
+
49
+ def create_socket
50
+ return unless @server_active
51
+ begin
52
+ socket = TCPSocket.open(@ip, @port)
53
+ socket.write "-auth #@auth_string "
54
+ socket
55
+ rescue SystemCallError
56
+ end
57
+ end
58
+
59
+ def connect
60
+ create_socket or (read_config and create_socket) \
61
+ or raise "Can't connect to Emacs Server."
62
+ end
63
+ else # Unix
64
+ def initialize
65
+ @socket_path = File.join(ENV['TMPDIR'], "emacs#{Process::Sys.geteuid}", 'server')
66
+ end
67
+
68
+ def connect
69
+ UNIXSocket.open(@socket_path)
70
+ rescue SystemCallError => error
71
+ raise "Can't connect to Emacs Server\n" << error.message
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,125 @@
1
+ require 'rum/hotkey_core'
2
+ require 'rum/help'
3
+ require 'rum/gui'
4
+ require 'rum/barrel'
5
+ require 'thread'
6
+
7
+ case RUBY_DESCRIPTION
8
+ when /mswin|mingw/ then require 'rum/windows'
9
+ when /MacRuby/ then require 'rum/mac'
10
+ else raise "Platform not yet supported: #{RUBY_PLATFORM}"
11
+ end
12
+
13
+ Encoding.default_external = Encoding::UTF_8
14
+
15
+ module Rum
16
+ autoload :Server, 'rum/server'
17
+
18
+ class << self
19
+ attr_writer :layout
20
+ attr_reader :hotkey_set, :hotkey_processor, \
21
+ :work_queue, :worker_thread
22
+
23
+ def layout
24
+ @layout ||= Layouts.default_layout
25
+ end
26
+
27
+ def setup
28
+ return if setup_completed?
29
+ @hotkey_set = HotkeySet.new(layout)
30
+ @hotkey_processor = HotkeyProcessor.new(@hotkey_set)
31
+ end
32
+
33
+ def setup_completed?
34
+ !!@hotkey_set
35
+ end
36
+
37
+ def start
38
+ setup
39
+ Thread.abort_on_exception = true
40
+ @work_queue = Action.work_queue = Queue.new
41
+ @worker_thread = start_worker_thread(@work_queue)
42
+
43
+ KeyboardHook.start &@hotkey_processor.method(:process_event)
44
+ end
45
+
46
+ def stop
47
+ KeyboardHook.stop
48
+ end
49
+
50
+ def start_worker_thread(queue)
51
+ Thread.new do
52
+ while action = queue.deq
53
+ begin
54
+ action.call
55
+ rescue => exception
56
+ display_exception exception
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ def display_exception(exception)
63
+ error_message = ["#{exception.class}:", exception,
64
+ '', *exception.backtrace].join("\n")
65
+
66
+ file, line = parse_stack_frame(exception.backtrace.first)
67
+ if file
68
+ file = File.expand_path(file)
69
+ callback = lambda do
70
+ Gui.message("Click here to jump to the last error:\n\n#{file}:#{line}") do
71
+ Gui.message error_message, :sticky
72
+ Gui.open_file file, line
73
+ end
74
+ end
75
+ end
76
+
77
+ Gui.message error_message, :sticky, &callback
78
+ end
79
+
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
91
+ end
92
+
93
+ def switch_worker_thread
94
+ return unless Thread.current == @worker_thread
95
+ old = @work_queue
96
+ new = @work_queue = Action.work_queue = Queue.new
97
+ new.enq(old.deq) until old.length == 0
98
+ @worker_thread = start_worker_thread(new)
99
+ old.enq nil # Signal the worker thread to stop
100
+ end
101
+ end
102
+
103
+ WorkingDir = Dir.pwd
104
+
105
+ def restart
106
+ Dir.chdir WorkingDir
107
+ if Thread.current == Rum::Server.thread
108
+ Thread.new do
109
+ sleep 0.01 # Allow server to respond. Slightly hacky.
110
+ restart_platform_specific
111
+ end
112
+ true
113
+ else
114
+ restart_platform_specific
115
+ end
116
+ end
117
+
118
+ def show
119
+ System.terminal_window.show
120
+ end
121
+
122
+ def hide
123
+ System.terminal_window.hide
124
+ end
125
+ end
@@ -0,0 +1,109 @@
1
+ include Rum
2
+ include System
3
+ include Keyboard
4
+
5
+ module Rum
6
+ class Action
7
+ def register
8
+ Rum.hotkey_set.register(self)
9
+ end
10
+
11
+ def unregister
12
+ Rum.hotkey_set.unregister(self)
13
+ end
14
+ end
15
+
16
+ class FileLocation
17
+ def initialize(file, line)
18
+ @file = file
19
+ @line = line
20
+ end
21
+
22
+ def self.from_stack_frame(frame)
23
+ file, line = Rum.parse_stack_frame(frame)
24
+ if file
25
+ file = File.expand_path(file) if File.dirname(file) == '.'
26
+ new(file, line)
27
+ end
28
+ end
29
+
30
+ def show
31
+ Gui.open_file(@file, @line)
32
+ true
33
+ end
34
+ end
35
+ end
36
+
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)
44
+ end
45
+ private method_name
46
+ end
47
+ end
48
+ include GuiMixin
49
+
50
+ def wait(timeout=5, interval=0.01)
51
+ start = Time.new
52
+ loop do
53
+ return true if yield
54
+ sleep interval
55
+ return false if Time.new - start > timeout
56
+ end
57
+ end
58
+
59
+ class String
60
+ def do(*options, &action)
61
+ repeated = true
62
+ options.reject! do |option|
63
+ case option
64
+ when :no_repeat
65
+ repeated = false
66
+ when String
67
+ action = lambda { Keyboard.type option }
68
+ end
69
+ end
70
+ if (condition = options.first) and condition.respond_to? :to_matcher
71
+ matcher = condition.to_matcher
72
+ condition = lambda { matcher.active? }
73
+ end
74
+ location = FileLocation.from_stack_frame(caller.first)
75
+ Rum.hotkey_set.add_hotkey(self, action, condition, repeated, location)
76
+ end
77
+
78
+ def unregister
79
+ Rum.hotkey_set.remove_hotkey(self)
80
+ end
81
+
82
+ def translate condition=nil, to
83
+ if condition and condition.respond_to? :to_matcher
84
+ matcher = condition.to_matcher
85
+ condition = lambda { matcher.active? }
86
+ end
87
+ Rum.hotkey_set.add_translation(self, to, condition,
88
+ FileLocation.from_stack_frame(caller.first))
89
+ end
90
+ end
91
+
92
+ class String
93
+ # Prepare a special version of #do that is only active when the user
94
+ # calls #do for the first time.
95
+ # After running Rum.setup it calls and restores the default version of #do.
96
+ alias :old_do :do
97
+ def do(*args, &block)
98
+ Rum.setup
99
+ String.class_eval do
100
+ alias :do :old_do
101
+ undef_method :old_do
102
+ end
103
+ action = self.do(*args, &block)
104
+ # The original location has been invalidated by the
105
+ # extra call to #do. Replace it.
106
+ action.location = FileLocation.from_stack_frame(caller.first)
107
+ action
108
+ end
109
+ end