muby 0.6.6

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 (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