From fcbf63e62c627deae76c1b8cb8c0876c536ed811 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Mon, 16 Mar 2020 18:49:26 +0900 Subject: Fresh start --- jni/ruby/lib/irb/ext/multi-irb.rb | 265 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 265 insertions(+) create mode 100644 jni/ruby/lib/irb/ext/multi-irb.rb (limited to 'jni/ruby/lib/irb/ext/multi-irb.rb') diff --git a/jni/ruby/lib/irb/ext/multi-irb.rb b/jni/ruby/lib/irb/ext/multi-irb.rb new file mode 100644 index 0000000..294f4e2 --- /dev/null +++ b/jni/ruby/lib/irb/ext/multi-irb.rb @@ -0,0 +1,265 @@ +# +# irb/multi-irb.rb - multiple irb module +# $Release Version: 0.9.6$ +# $Revision: 47266 $ +# by Keiju ISHITSUKA(keiju@ruby-lang.org) +# +# -- +# +# +# +IRB.fail CantShiftToMultiIrbMode unless defined?(Thread) +require "thread" + +module IRB + class JobManager + + # Creates a new JobManager object + def initialize + @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 + + @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 -- cgit v1.2.3