1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
|
#
# irb/multi-irb.rb - multiple irb module
# $Release Version: 0.9.6$
# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
# --
#
#
#
IRB.fail CantShiftToMultiIrbMode unless defined?(Thread)
require "thread"
module IRB
class JobManager
@RCS_ID='-$Id$-'
# Creates a new JobManager object
def initialize
# @jobs = [[thread, irb],...]
@jobs = []
@current_job = nil
end
# The active irb session
attr_accessor :current_job
# The total number of irb sessions, used to set +irb_name+ of the current
# Context.
def n_jobs
@jobs.size
end
# Returns the thread for the given +key+ object, see #search for more
# information.
def thread(key)
th, = search(key)
th
end
# Returns the irb session for the given +key+ object, see #search for more
# information.
def irb(key)
_, irb = search(key)
irb
end
# Returns the top level thread.
def main_thread
@jobs[0][0]
end
# Returns the top level irb session.
def main_irb
@jobs[0][1]
end
# Add the given +irb+ session to the jobs Array.
def insert(irb)
@jobs.push [Thread.current, irb]
end
# Changes the current active irb session to the given +key+ in the jobs
# Array.
#
# Raises an IrbAlreadyDead exception if the given +key+ is no longer alive.
#
# If the given irb session is already active, an IrbSwitchedToCurrentThread
# exception is raised.
def switch(key)
th, irb = search(key)
IRB.fail IrbAlreadyDead unless th.alive?
IRB.fail IrbSwitchedToCurrentThread if th == Thread.current
@current_job = irb
th.run
Thread.stop
@current_job = irb(Thread.current)
end
# Terminates the irb sessions specified by the given +keys+.
#
# Raises an IrbAlreadyDead exception if one of the given +keys+ is already
# terminated.
#
# See Thread#exit for more information.
def kill(*keys)
for key in keys
th, _ = search(key)
IRB.fail IrbAlreadyDead unless th.alive?
th.exit
end
end
# Returns the associated job for the given +key+.
#
# If given an Integer, it will return the +key+ index for the jobs Array.
#
# When an instance of Irb is given, it will return the irb session
# associated with +key+.
#
# If given an instance of Thread, it will return the associated thread
# +key+ using Object#=== on the jobs Array.
#
# Otherwise returns the irb session with the same top-level binding as the
# given +key+.
#
# Raises a NoSuchJob exception if no job can be found with the given +key+.
def search(key)
job = case key
when Integer
@jobs[key]
when Irb
@jobs.find{|k, v| v.equal?(key)}
when Thread
@jobs.assoc(key)
else
@jobs.find{|k, v| v.context.main.equal?(key)}
end
IRB.fail NoSuchJob, key if job.nil?
job
end
# Deletes the job at the given +key+.
def delete(key)
case key
when Integer
IRB.fail NoSuchJob, key unless @jobs[key]
@jobs[key] = nil
else
catch(:EXISTS) do
@jobs.each_index do
|i|
if @jobs[i] and (@jobs[i][0] == key ||
@jobs[i][1] == key ||
@jobs[i][1].context.main.equal?(key))
@jobs[i] = nil
throw :EXISTS
end
end
IRB.fail NoSuchJob, key
end
end
until assoc = @jobs.pop; end unless @jobs.empty?
@jobs.push assoc
end
# Outputs a list of jobs, see the irb command +irb_jobs+, or +jobs+.
def inspect
ary = []
@jobs.each_index do
|i|
th, irb = @jobs[i]
next if th.nil?
if th.alive?
if th.stop?
t_status = "stop"
else
t_status = "running"
end
else
t_status = "exited"
end
ary.push format("#%d->%s on %s (%s: %s)",
i,
irb.context.irb_name,
irb.context.main,
th,
t_status)
end
ary.join("\n")
end
end
@JobManager = JobManager.new
# The current JobManager in the session
def IRB.JobManager
@JobManager
end
# The current Context in this session
def IRB.CurrentContext
IRB.JobManager.irb(Thread.current).context
end
# Creates a new IRB session, see Irb.new.
#
# The optional +file+ argument is given to Context.new, along with the
# workspace created with the remaining arguments, see WorkSpace.new
def IRB.irb(file = nil, *main)
workspace = WorkSpace.new(*main)
parent_thread = Thread.current
Thread.start do
begin
irb = Irb.new(workspace, file)
rescue
print "Subirb can't start with context(self): ", workspace.main.inspect, "\n"
print "return to main irb\n"
Thread.pass
Thread.main.wakeup
Thread.exit
end
@CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
@JobManager.insert(irb)
@JobManager.current_job = irb
begin
system_exit = false
catch(:IRB_EXIT) do
irb.eval_input
end
rescue SystemExit
system_exit = true
raise
#fail
ensure
unless system_exit
@JobManager.delete(irb)
if @JobManager.current_job == irb
if parent_thread.alive?
@JobManager.current_job = @JobManager.irb(parent_thread)
parent_thread.run
else
@JobManager.current_job = @JobManager.main_irb
@JobManager.main_thread.run
end
end
end
end
end
Thread.stop
@JobManager.current_job = @JobManager.irb(Thread.current)
end
# class Context
# def set_last_value(value)
# @last_value = value
# @workspace.evaluate "_ = IRB.JobManager.irb(Thread.current).context.last_value"
# if @eval_history #and !@__.equal?(@last_value)
# @eval_history_values.push @line_no, @last_value
# @workspace.evaluate "__ = IRB.JobManager.irb(Thread.current).context.instance_eval{@eval_history_values}"
# end
# @last_value
# end
# end
# module ExtendCommand
# def irb_context
# IRB.JobManager.irb(Thread.current).context
# end
# # alias conf irb_context
# end
@CONF[:SINGLE_IRB_MODE] = false
@JobManager.insert(@CONF[:MAIN_CONTEXT].irb)
@JobManager.current_job = @CONF[:MAIN_CONTEXT].irb
class Irb
def signal_handle
unless @context.ignore_sigint?
print "\nabort!!\n" if @context.verbose?
exit
end
case @signal_status
when :IN_INPUT
print "^C\n"
IRB.JobManager.thread(self).raise RubyLex::TerminateLineInput
when :IN_EVAL
IRB.irb_abort(self)
when :IN_LOAD
IRB.irb_abort(self, LoadAbort)
when :IN_IRB
# ignore
else
# ignore other cases as well
end
end
end
trap("SIGINT") do
@JobManager.current_job.signal_handle
Thread.stop
end
end
|