muby 0.6.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/LICENSE +339 -0
  2. data/bin/muby +37 -0
  3. data/contrib/aardmud.org_4000/README.txt +39 -0
  4. data/contrib/aardmud.org_4000/aard-config.rb +234 -0
  5. data/contrib/aardmud.org_4000/aard-helpers.rb +464 -0
  6. data/contrib/aardmud.org_4000/aliases/aard-aliases.rb +205 -0
  7. data/contrib/aardmud.org_4000/gags/aard-gags.rb +182 -0
  8. data/contrib/aardmud.org_4000/misc/aard-affects.rb +252 -0
  9. data/contrib/aardmud.org_4000/misc/aard-know.rb +147 -0
  10. data/contrib/aardmud.org_4000/misc/aard-poznai_sebia.rb +191 -0
  11. data/contrib/aardmud.org_4000/misc/aard-prompts.rb +65 -0
  12. data/contrib/aardmud.org_4000/misc/aard-status_toggling.rb +156 -0
  13. data/contrib/aardmud.org_4000/misc/aard_consider_substitutions.rb +319 -0
  14. data/contrib/aardmud.org_4000/speedwalks/aard-sw-areas-hero.rb +86 -0
  15. data/contrib/aardmud.org_4000/speedwalks/aard-sw-areas-newbie.rb +98 -0
  16. data/contrib/aardmud.org_4000/speedwalks/aard-sw-areas-noble.rb +170 -0
  17. data/contrib/aardmud.org_4000/speedwalks/aard-sw-areas-vidblain.rb +88 -0
  18. data/contrib/aardmud.org_4000/speedwalks/aard-sw-areas.rb +850 -0
  19. data/contrib/aardmud.org_4000/speedwalks/aard-sw-clans.rb +43 -0
  20. data/contrib/aardmud.org_4000/speedwalks/aard-sw-guilds.rb +13 -0
  21. data/contrib/aardmud.org_4000/speedwalks/aard-sw.rb +45 -0
  22. data/contrib/aardmud.org_4000/triggers/aard-triggers-items.rb +254 -0
  23. data/contrib/aardmud.org_4000/triggers/aard-triggers.rb +227 -0
  24. data/contrib/sy/cce.rb +120 -0
  25. data/lib/muby.rb +15 -0
  26. data/lib/muby/application.rb +66 -0
  27. data/lib/muby/completer.rb +62 -0
  28. data/lib/muby/configuration.rb +379 -0
  29. data/lib/muby/connection.rb +332 -0
  30. data/lib/muby/displayer.rb +60 -0
  31. data/lib/muby/help.rb +88 -0
  32. data/lib/muby/helper_methods.rb +46 -0
  33. data/lib/muby/inputwindow.rb +173 -0
  34. data/lib/muby/logger.rb +28 -0
  35. data/lib/muby/outputwindow.rb +189 -0
  36. data/lib/muby/style.rb +142 -0
  37. data/lib/muby/user_methods.rb +463 -0
  38. metadata +90 -0
@@ -0,0 +1,332 @@
1
+ #
2
+ # The class that encapsulates the actual Connection
3
+ #
4
+ class Muby::Connection
5
+
6
+ include Muby::Logger
7
+ include Muby::Configurable
8
+ include Muby::Displayer
9
+
10
+ #
11
+ # Set it up with windows, handle and host info.
12
+ #
13
+ def initialize(inputWindow, outputWindow, host, port)
14
+ @inputWindow = inputWindow
15
+ @outputWindow = outputWindow
16
+ status("Connecting to " + host.inspect + ":" + port.inspect)
17
+ @host = host
18
+ @port = port
19
+ @socket = TCPSocket.open(host, port) if host && port
20
+ conf.connect_triggers.each do |command|
21
+ @inputWindow.execute(command, @inputWindow, @outputWindow)
22
+ end
23
+ status("Connected to " + host.inspect + ":" + port.inspect)
24
+ @matchBuffer = ""
25
+ @showBuffer = []
26
+ @used_triggers = {}
27
+ @listener = Thread.new do
28
+ begin
29
+ status("Listening thread started")
30
+ listen
31
+ status("Listening thread finished")
32
+ rescue Exception => e
33
+ exception(e)
34
+ ensure
35
+ close
36
+ end
37
+ end if @socket
38
+ end
39
+
40
+ #
41
+ # Display a status message in the outputwindow if wanted (conf.connection_status)
42
+ #
43
+ def status(message)
44
+ if conf.connection_status
45
+ @outputWindow.print_on_newline(*[message + "\n"])
46
+ end
47
+ end
48
+
49
+ #
50
+ # Check if we want to gag the current matchBuffer and debug about it.
51
+ #
52
+ # Remove the gag regexp if it is broken.
53
+ #
54
+ def gag(matchBuffer)
55
+ returnValue = false
56
+ conf.gags.each do |gag|
57
+ begin
58
+ if matchBuffer.match(gag)
59
+ trace(matchBuffer + " matches " + gag.inspect + ": gag active")
60
+ returnValue = true
61
+ end
62
+ rescue RegexpError => error
63
+ conf.gags.delete(key)
64
+ exception(e)
65
+ end
66
+ end
67
+ returnValue
68
+ end
69
+
70
+ #
71
+ # Check if we should definitely NOT gag the current matchBuffer, and debug about it.
72
+ #
73
+ # Remove the nongag regexp if it is broken.
74
+ #
75
+ def nongag(matchBuffer)
76
+ returnValue = false
77
+ conf.anti_gags.each do |nongag|
78
+ begin
79
+ if matchBuffer.match(nongag)
80
+ trace(matchBuffer + " matches " + nongag.inspect + ": nongag active")
81
+ returnValue = true
82
+ end
83
+ rescue RegexpError => error
84
+ conf.anti_gags.delete(key)
85
+ exception(e)
86
+ end
87
+ end
88
+ returnValue
89
+ end
90
+
91
+ #
92
+ # Check if we should trigger a Proc on the current matchBuffer, and debug about it.
93
+ #
94
+ # Remove the trigger regexp if it is broken.
95
+ #
96
+ def trigger(matchBuffer, hash, skip_used = true)
97
+ hash.each do |key, value|
98
+ if skip_used && @used_triggers.include?(key)
99
+ trace("#{key.inspect} has already been matched on this line, skipping it")
100
+ else
101
+ trace("checking if " + matchBuffer + " matches " + key.inspect)
102
+ begin
103
+ if match = matchBuffer.match(key)
104
+ trace(matchBuffer + " matches " + key.inspect + ": .call'ing Proc")
105
+ # Run the procedure associated with that trigger:
106
+ @inputWindow.execute(value, @inputWindow, @outputWindow, match)
107
+ @used_triggers[key] = true if skip_used
108
+ end
109
+ # If we received an error with the regular expression:
110
+ rescue RegexpError => error
111
+ hash.delete(key)
112
+ exception(error)
113
+ end
114
+ end
115
+ end
116
+ end
117
+
118
+ def feed(s)
119
+ s.unpack("C*").each do |c|
120
+ handle(c)
121
+ end
122
+ nil
123
+ end
124
+
125
+ def getc
126
+ c = @socket.getc
127
+ log_input(c.chr) if c
128
+ c
129
+ end
130
+
131
+ def handle(c)
132
+ #
133
+ # The telnet support (just so we dont explode or something)
134
+ #
135
+ # We are just plain ignoring it atm.
136
+ #
137
+ if c == 255 # telnet interpret as command (IAC)
138
+ c = getc # get the request (DO|DONT)
139
+ c = getc # get the latest part whatever that is
140
+ elsif c == 27 # escape char! this is probably some ANSI color or shite
141
+ c = getc
142
+ if c.chr == "[" # this is an ansi-something that is more than one char long
143
+ ansiString = ""
144
+ while !"cnRhl()HABCfsurhgKJipm".include?((c = getc).chr)
145
+ ansiString << c.chr
146
+ end
147
+ if c.chr == "m" && Ncurses.has_colors? # ah, text property! i understand this!
148
+ properties = ansiString.split(";")
149
+ attributes = 0
150
+ bgcolor = false
151
+ fgcolor = false
152
+ reset = properties.index("0")
153
+ if reset
154
+ properties.delete("0")
155
+ end
156
+ properties.each do |property|
157
+ case property.to_i
158
+ when 1
159
+ attributes = attributes | Ncurses.const_get("A_BOLD")
160
+ when 2
161
+ attributes = attributes | Ncurses.const_get("A_DIM")
162
+ when 4
163
+ attributes = attributes | Ncurses.const_get("A_UNDERLINE")
164
+ when 5
165
+ attributes = attributes | Ncurses.const_get("A_BLINK") unless conf.disable_blink
166
+ when 7
167
+ attributes = attributes | Ncurses.const_get("A_REVERSE")
168
+ when 8
169
+ attributes = attributes | Ncurses.const_get("A_INVIS")
170
+ when 30
171
+ fgcolor = Ncurses.const_get("COLOR_BLACK")
172
+ when 31
173
+ fgcolor = Ncurses.const_get("COLOR_RED")
174
+ when 32
175
+ fgcolor = Ncurses.const_get("COLOR_GREEN")
176
+ when 33
177
+ fgcolor = Ncurses.const_get("COLOR_YELLOW")
178
+ when 34
179
+ fgcolor = Ncurses.const_get("COLOR_BLUE")
180
+ when 35
181
+ fgcolor = Ncurses.const_get("COLOR_MAGENTA")
182
+ when 36
183
+ fgcolor = Ncurses.const_get("COLOR_CYAN")
184
+ when 37
185
+ fgcolor = Ncurses.const_get("COLOR_WHITE")
186
+ when 40
187
+ bgcolor = Ncurses.const_get("COLOR_BLACK")
188
+ when 41
189
+ bgcolor = Ncurses.const_get("COLOR_RED")
190
+ when 42
191
+ bgcolor = Ncurses.const_get("COLOR_GREEN")
192
+ when 43
193
+ bgcolor = Ncurses.const_get("COLOR_YELLOW")
194
+ when 44
195
+ bgcolor = Ncurses.const_get("COLOR_BLUE")
196
+ when 45
197
+ bgcolor = Ncurses.const_get("COLOR_MAGENTA")
198
+ when 46
199
+ bgcolor = Ncurses.const_get("COLOR_CYAN")
200
+ when 47
201
+ bgcolor = Ncurses.const_get("COLOR_WHITE")
202
+ end
203
+ end
204
+ style = nil
205
+ if reset
206
+ style = Muby::Style.new(attributes, fgcolor, bgcolor, false)
207
+ else
208
+ style = Muby::Style.new(attributes, fgcolor, bgcolor, true)
209
+ end
210
+ @showBuffer.push(style)
211
+ end
212
+ end
213
+ elsif ! conf.broken_keycodes.include?(c)
214
+ #
215
+ # This is not telnet command OR ansi, lets treat it as nice MUD text!
216
+ #
217
+ # Debug about it, add it to match buffer, add it to show buffer and show if we want to show.
218
+ # Then check it for triggers.
219
+ #
220
+ @matchBuffer = @matchBuffer + c.chr
221
+ append_show_buffer(c.chr)
222
+ manage_buffers(c)
223
+ end
224
+ end
225
+
226
+ def append_show_buffer(c)
227
+ if String === @showBuffer.last
228
+ @showBuffer.last << c
229
+ else
230
+ @showBuffer << c
231
+ end
232
+ end
233
+
234
+ #
235
+ # Keep listening to the remote socket and react accordingly.
236
+ #
237
+ def listen
238
+ c = true
239
+ # We have to look at each byte for ncurses reasons as well as triggers etc.
240
+ while c
241
+ while select([@socket],nil,nil,1) && c = getc
242
+ handle(c)
243
+ end
244
+ if conf.flush
245
+ display_buffer
246
+ end
247
+ end
248
+ status("Connection closed by remote end")
249
+ @inputWindow.disconnect
250
+ end
251
+
252
+ def close
253
+ if Thread.current != @listener && @listener && @listener.alive?
254
+ status("Killing listening thread")
255
+ @listener.kill
256
+ end
257
+ if @socket && !@socket.closed?
258
+ status("Disconnecting our end")
259
+ @socket.close if @socket
260
+ end
261
+ end
262
+
263
+ def manage_buffers(c)
264
+ trigger(@matchBuffer, conf.remote_character_triggers, true)
265
+ if c == 10
266
+ trigger(@matchBuffer, conf.remote_triggers, false)
267
+ display_buffer
268
+ @matchBuffer = ""
269
+ @used_triggers = {}
270
+ @showBuffer = []
271
+ end
272
+ end
273
+
274
+ def homemade_split(s, r)
275
+ rval = []
276
+ rest = s
277
+ while match = rest.match(/(.*?)#{r.source}(.*)/)
278
+ rval << match[1]
279
+ rest = match[2]
280
+ end
281
+ rval << rest
282
+ rval
283
+ end
284
+
285
+ def substitute(buffer, hash)
286
+ return_value = []
287
+ buffer.each do |part|
288
+ if String === part
289
+ part_to_append = [part]
290
+ hash.each do |regexp, substitution|
291
+ case substitution
292
+ when String
293
+ part_to_append = [part.gsub(regexp, substitution)]
294
+ when Array
295
+ if part.match(regexp)
296
+ split_part = homemade_split(part, regexp)
297
+ part_to_append = split_part.zip([substitution] * (split_part.size - 1)).flatten.compact
298
+ end
299
+ end
300
+ end
301
+ return_value += part_to_append
302
+ else
303
+ return_value << part
304
+ end
305
+ end
306
+ return_value
307
+ end
308
+
309
+ def display_buffer
310
+ unless @showBuffer.empty?
311
+ if !gag(@matchBuffer) || nongag(@matchBuffer)
312
+ @showBuffer = substitute(@showBuffer, conf.remote_substitutions)
313
+ Muby::Completer.get_instance.store(@matchBuffer) if conf.feed_completer_with_input
314
+ @outputWindow.print(*@showBuffer)
315
+ end
316
+ @showBuffer = []
317
+ end
318
+ end
319
+
320
+ #
321
+ # Just plain send the string we got.
322
+ #
323
+ def send(s)
324
+ log_output(s)
325
+ conf.local_substitutions.each do |key, value|
326
+ # It might be useful to allow colour codes for highlighting local substitutions.. but only when echo is on.
327
+ # No, cause this only gets sent to the server, it never shows up to the user.
328
+ s.gsub!(key, value)
329
+ end
330
+ @socket.print(s) if @socket
331
+ end
332
+ end # class Connection
@@ -0,0 +1,60 @@
1
+
2
+ module Muby
3
+
4
+ module Displayer
5
+
6
+ def exception(e)
7
+ error("#{e.class}: #{e.message}")
8
+ debug(e.backtrace.join("\n"))
9
+ end
10
+
11
+ def trace(s)
12
+ if Muby::OutputWindow.get_instance.ready?
13
+ Muby::OutputWindow.get_instance.show(:trace, s)
14
+ elsif Muby::Configuration.get.display?(:trace)
15
+ puts s
16
+ end
17
+ end
18
+
19
+ def debug(s)
20
+ if Muby::OutputWindow.get_instance.ready?
21
+ Muby::OutputWindow.get_instance.show(:debug, s)
22
+ elsif Muby::Configuration.get.display?(:debug)
23
+ puts s
24
+ end
25
+ end
26
+
27
+ def info(s)
28
+ if Muby::OutputWindow.get_instance.ready?
29
+ Muby::OutputWindow.get_instance.show(:info, s)
30
+ elsif Muby::Configuration.get.display?(:info)
31
+ puts s
32
+ end
33
+ end
34
+
35
+ def warn(s)
36
+ if Muby::OutputWindow.get_instance.ready?
37
+ Muby::OutputWindow.get_instance.show(:warn, s)
38
+ elsif Muby::Configuration.get.display?(:warn)
39
+ puts s
40
+ end
41
+ end
42
+
43
+ def error(s)
44
+ if Muby::OutputWindow.get_instance.ready?
45
+ Muby::OutputWindow.get_instance.show(:error, s)
46
+ elsif Muby::Configuration.get.display?(:error)
47
+ puts s
48
+ end
49
+ end
50
+
51
+ module_function :trace
52
+ module_function :debug
53
+ module_function :info
54
+ module_function :warn
55
+ module_function :error
56
+ module_function :exception
57
+
58
+ end
59
+
60
+ end
@@ -0,0 +1,88 @@
1
+ module Muby
2
+
3
+ module Help
4
+ def self.configuration
5
+ {
6
+ :feed_completer_with_history => "If true, the completion command will use history to calculate possible completions.",
7
+ :feed_completer_with_input => "If true, the completion command will use everything seen from the remote end to calculate possible completions.",
8
+ :extra_completions => "Fill this array with words that you allways want to be able to complete to.",
9
+ :extra_verbosity_settings => "The settings we want to toggle to when running the toggle_verbosity! method.",
10
+ :echo_keycodes => "Whether to echo the keycode for every key pressed or not.",
11
+ :echo => "Whether to print what is sent to the server to the outputwindow.",
12
+ :show_level => "What level of information to provide the user.
13
+ :trace may tell you each and every step the app takes.
14
+ :debug may tell the user most everything that happens.
15
+ :info will tell the user basically what we are doing.
16
+ :warn will only tell the user when we think he/she may gain from it.
17
+ :error will only tell the user when an error occurs.",
18
+ :timestamp => "Whether to timestamp all messages in the output window.",
19
+ :connection_status => "Whether to give status reports on the connections.",
20
+ :timeformat => "What type of timestamp to use.",
21
+ :loaded_rc_file => "This will be set to whichever mubyrc file was loaded upon startup.",
22
+ :disable_blink => "Set this to true if you NEVER want to see BLINKING text from the server.",
23
+ :broken_keycodes => "Which characters to filter out completely.",
24
+ :max_history => "The maximum length of the history buffer.",
25
+ :user_edited_config_file => "Change this to true when you dont want to see the help message anymore.",
26
+ :default_attributes => "The default ncurses attributes for text.",
27
+ :default_colors => "The default ncurses colors for text.",
28
+ :echo_attributes => "The default ncurses attributes for echoed (typed by you, showed in the output window) text.",
29
+ :echo_colors => "The default ncurses colors for echoed (typed by you, showed in the output window) text.",
30
+ :trace_attributes => "The default ncurses attributes for messages shown under trace loglevel.",
31
+ :trace_colors => "The default ncurses colors attributes for messages shown under trace loglevel.",
32
+ :debug_attributes => "The default ncurses attributes for messages shown under debug loglevel.",
33
+ :debug_colors => "The default ncurses colors attributes for messages shown under debug loglevel.",
34
+ :info_attributes => "The default ncurses attributes for messages shown under info loglevel.",
35
+ :info_colors => "The default ncurses colors attributes for messages shown under info loglevel.",
36
+ :warn_attributes => "The default ncurses attributes for messages shown under warn loglevel.",
37
+ :warn_colors => "The default ncurses colors attributes for messages shown under warn loglevel.",
38
+ :error_attributes => "The default ncurses attributes for messages shown under error loglevel.",
39
+ :error_colors => "The default ncurses colors attributes for messages shown under error loglevel.",
40
+ :flush => "Whether to display every char we get as soon as there is a pause in the transfer or a newline.
41
+ In contrast to only displaying the input characters when there is a newline.",
42
+ :gags => "The gags. All lines from the server are checked against these regular expressions.
43
+ If any one matches that line will not be shown. Note that if you have flush == true, the characters may already have been shown.",
44
+ :remote_substitutions => "The remote substitutions.
45
+ The same buffer that the remote_triggers work on will be searched for matches to the keys in this hash.
46
+ All values to matching keys will replace the keys in the buffer.",
47
+ :local_substitutions => "The local substitutions.
48
+ The text you send to the server will be searched for matches to the keys in this hash.
49
+ All values to matching keys will replace the keys in the text.",
50
+ :anti_gags => "The anti gags.
51
+ If flush == false the lines matching these regular expressions will be shown as soon as they are matched.
52
+ A line matching an anti gag and a gag will also be shown.",
53
+ :shutdown_triggers => "The shutdown triggers. Code in this array will be run in order at shutdown.",
54
+ :connect_triggers => "The connect triggers. Code in this array will be run in order when a connection is made.",
55
+ :startup_triggers => "The startup triggers. Code in this array will be run in order after the windows have been properly initialized.",
56
+ :remote_triggers => 'The remote triggers.
57
+ Each line received from the server will be checked against all regular expression keys in this hash, and all values to matching keys will be executed with three parameters: the input window, the output window and the match object.
58
+ Example: conf.remote_triggers[/^You feel dazed$/] = Proc.new do |inwin, outwin, match| inwin.set_status_message("dazed") end',
59
+ :remote_character_triggers => 'The remote character triggers.
60
+ All input from the server is added to a buffer that is cleared on newline and each time a new character is added to that buffer the buffer will be checked against all the regular expression keys in the remote_character_triggers.
61
+ All code values belonging to matching keys will be executed with three parameters: the input window, the output window and the match object.
62
+ Example: conf.remote_character_triggers[/^(\S+) attacks you$/] = Proc.new do |inwin, outwin, match| inwin.send("kill #{match[1]}") end',
63
+ :local_triggers => 'The local triggers.
64
+ Every line that is to be sent to the server is matched against the regular expression keys in this hash before they are sent.
65
+ All code values belonging to matching keys will be executed with three parameters: the input window, the output window and the match object.
66
+ Only if the return value of this execution is not false will the line be sent to the server.
67
+ Example: conf.local_triggers[/^bp (\S+)$/] = Proc.new do |inwin, outwin, match| inwin.send("put #{match[1]} in backpack") end',
68
+ :key_commands => 'The key commands.
69
+ Each key pressed will have its keycode checked against the integer keys of this hash.
70
+ If no key match and the keycode is below 256, the character corresponding to this code will be appended to the input line.
71
+ If a key matches the value in the hash will be checked.
72
+ If the value is another hash a new key will be waited for, and the same procedure will take place with the value hash instead.
73
+ If the value is not a hash it will be executed as code with three parameters: the input window, the output window and the matching key.
74
+ Example: conf.key_commands[65] = Proc.new do |inwin, outwin, char| inwin.echo("I just pressed A") end',
75
+ :userdir => 'The user directory. All *.rb files in this directory will be loaded on startup and on reload_application!
76
+ The root of the user directory takes precidence over (overrides) sub-directories.
77
+ Symbolic links (files and directories) are also used.
78
+ Directories beginning with a period are ignored.',
79
+ :history_file => 'The file where we will store the history of entered commands.',
80
+ :output_buffer => 'The number of rows that will be buffered in the output window for scrollback.',
81
+ :input_height => 'The number of rows in the input window.',
82
+ :input_logfile => 'The IO object that will receive everything we receive from the remote end.',
83
+ :output_logfile => 'The IO object that will receive everything we send to the remote end.'
84
+ }
85
+ end
86
+ end
87
+
88
+ end