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/change-ws.rb | 45 ++++++ jni/ruby/lib/irb/ext/history.rb | 118 ++++++++++++++++ jni/ruby/lib/irb/ext/loader.rb | 128 +++++++++++++++++ jni/ruby/lib/irb/ext/math-mode.rb | 47 +++++++ jni/ruby/lib/irb/ext/multi-irb.rb | 265 +++++++++++++++++++++++++++++++++++ jni/ruby/lib/irb/ext/save-history.rb | 103 ++++++++++++++ jni/ruby/lib/irb/ext/tracer.rb | 71 ++++++++++ jni/ruby/lib/irb/ext/use-loader.rb | 73 ++++++++++ jni/ruby/lib/irb/ext/workspaces.rb | 66 +++++++++ 9 files changed, 916 insertions(+) create mode 100644 jni/ruby/lib/irb/ext/change-ws.rb create mode 100644 jni/ruby/lib/irb/ext/history.rb create mode 100644 jni/ruby/lib/irb/ext/loader.rb create mode 100644 jni/ruby/lib/irb/ext/math-mode.rb create mode 100644 jni/ruby/lib/irb/ext/multi-irb.rb create mode 100644 jni/ruby/lib/irb/ext/save-history.rb create mode 100644 jni/ruby/lib/irb/ext/tracer.rb create mode 100644 jni/ruby/lib/irb/ext/use-loader.rb create mode 100644 jni/ruby/lib/irb/ext/workspaces.rb (limited to 'jni/ruby/lib/irb/ext') diff --git a/jni/ruby/lib/irb/ext/change-ws.rb b/jni/ruby/lib/irb/ext/change-ws.rb new file mode 100644 index 0000000..866a710 --- /dev/null +++ b/jni/ruby/lib/irb/ext/change-ws.rb @@ -0,0 +1,45 @@ +# +# irb/ext/cb.rb - +# $Release Version: 0.9.6$ +# $Revision: 47114 $ +# by Keiju ISHITSUKA(keiju@ruby-lang.org) +# +# -- +# +# +# + +module IRB # :nodoc: + class Context + + # Inherited from +TOPLEVEL_BINDING+. + def home_workspace + if defined? @home_workspace + @home_workspace + else + @home_workspace = @workspace + end + end + + # Changes the current workspace to given object or binding. + # + # If the optional argument is omitted, the workspace will be + # #home_workspace which is inherited from +TOPLEVEL_BINDING+ or the main + # object, IRB.conf[:MAIN_CONTEXT] when irb was initialized. + # + # See IRB::WorkSpace.new for more information. + def change_workspace(*_main) + if _main.empty? + @workspace = home_workspace + return main + end + + @workspace = WorkSpace.new(_main[0]) + + if !(class<= 0 + @contents.find{|no, val| no == idx}[1] + else + @contents[idx][1] + end + rescue NameError + nil + end + end + + def push(no, val) + @contents.push [no, val] + @contents.shift if @size != 0 && @contents.size > @size + end + + alias real_inspect inspect + + def inspect + if @contents.empty? + return real_inspect + end + + unless (last = @contents.pop)[1].equal?(self) + @contents.push last + last = nil + end + str = @contents.collect{|no, val| + if val.equal?(self) + "#{no} ...self-history..." + else + "#{no} #{val.inspect}" + end + }.join("\n") + if str == "" + str = "Empty." + end + @contents.push last if last + str + end + end +end + + diff --git a/jni/ruby/lib/irb/ext/loader.rb b/jni/ruby/lib/irb/ext/loader.rb new file mode 100644 index 0000000..4c6b2ba --- /dev/null +++ b/jni/ruby/lib/irb/ext/loader.rb @@ -0,0 +1,128 @@ +# +# loader.rb - +# $Release Version: 0.9.6$ +# $Revision: 47266 $ +# by Keiju ISHITSUKA(keiju@ruby-lang.org) +# +# -- +# +# +# + + +module IRB # :nodoc: + # Raised in the event of an exception in a file loaded from an Irb session + class LoadAbort < Exception;end + + # Provides a few commands for loading files within an irb session. + # + # See ExtendCommandBundle for more information. + module IrbLoader + + alias ruby_load load + alias ruby_require require + + # Loads the given file similarly to Kernel#load + def irb_load(fn, priv = nil) + path = search_file_from_ruby_path(fn) + raise LoadError, "No such file to load -- #{fn}" unless path + + load_file(path, priv) + end + + def search_file_from_ruby_path(fn) # :nodoc: + if /^#{Regexp.quote(File::Separator)}/ =~ fn + return fn if File.exist?(fn) + return nil + end + + for path in $: + if File.exist?(f = File.join(path, fn)) + return f + end + end + return nil + end + + # Loads a given file in the current session and displays the source lines + # + # See Irb#suspend_input_method for more information. + def source_file(path) + irb.suspend_name(path, File.basename(path)) do + irb.suspend_input_method(FileInputMethod.new(path)) do + |back_io| + irb.signal_status(:IN_LOAD) do + if back_io.kind_of?(FileInputMethod) + irb.eval_input + else + begin + irb.eval_input + rescue LoadAbort + print "load abort!!\n" + end + end + end + end + end + end + + # Loads the given file in the current session's context and evaluates it. + # + # See Irb#suspend_input_method for more information. + def load_file(path, priv = nil) + irb.suspend_name(path, File.basename(path)) do + + if priv + ws = WorkSpace.new(Module.new) + else + ws = WorkSpace.new + end + irb.suspend_workspace(ws) do + irb.suspend_input_method(FileInputMethod.new(path)) do + |back_io| + irb.signal_status(:IN_LOAD) do + if back_io.kind_of?(FileInputMethod) + irb.eval_input + else + begin + irb.eval_input + rescue LoadAbort + print "load abort!!\n" + end + end + end + end + end + end + end + + def old # :nodoc: + back_io = @io + back_path = @irb_path + back_name = @irb_name + back_scanner = @irb.scanner + begin + @io = FileInputMethod.new(path) + @irb_name = File.basename(path) + @irb_path = path + @irb.signal_status(:IN_LOAD) do + if back_io.kind_of?(FileInputMethod) + @irb.eval_input + else + begin + @irb.eval_input + rescue LoadAbort + print "load abort!!\n" + end + end + end + ensure + @io = back_io + @irb_name = back_name + @irb_path = back_path + @irb.scanner = back_scanner + end + end + end +end + diff --git a/jni/ruby/lib/irb/ext/math-mode.rb b/jni/ruby/lib/irb/ext/math-mode.rb new file mode 100644 index 0000000..33e9968 --- /dev/null +++ b/jni/ruby/lib/irb/ext/math-mode.rb @@ -0,0 +1,47 @@ +# +# math-mode.rb - +# $Release Version: 0.9.6$ +# $Revision: 47112 $ +# by Keiju ISHITSUKA(keiju@ruby-lang.org) +# +# -- +# +# +# +require "mathn" + +module IRB + class Context + # Returns whether bc mode is enabled. + # + # See #math_mode= + attr_reader :math_mode + # Alias for #math_mode + alias math? math_mode + + # Sets bc mode, which loads +lib/mathn.rb+ so fractions or matrix are + # available. + # + # Also available as the +-m+ command line option. + # + # See IRB@Command+line+options and the unix manpage bc(1) for + # more information. + def math_mode=(opt) + if @math_mode == true && !opt + IRB.fail CantReturnToNormalMode + return + end + + @math_mode = opt + if math_mode + main.extend Math + print "start math mode\n" if verbose? + end + end + + def inspect? + @inspect_mode.nil? && !@math_mode or @inspect_mode + end + end +end + 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 diff --git a/jni/ruby/lib/irb/ext/save-history.rb b/jni/ruby/lib/irb/ext/save-history.rb new file mode 100644 index 0000000..575b276 --- /dev/null +++ b/jni/ruby/lib/irb/ext/save-history.rb @@ -0,0 +1,103 @@ +# save-history.rb - +# $Release Version: 0.9.6$ +# $Revision: 47266 $ +# by Keiju ISHITSUKA(keiju@ruby-lang.org) +# +# -- +# +# +# + +require "readline" + +module IRB + module HistorySavingAbility # :nodoc: + end + + class Context + def init_save_history# :nodoc: + unless (class<<@io;self;end).include?(HistorySavingAbility) + @io.extend(HistorySavingAbility) + end + end + + # A copy of the default IRB.conf[:SAVE_HISTORY] + def save_history + IRB.conf[:SAVE_HISTORY] + end + + # Sets IRB.conf[:SAVE_HISTORY] to the given +val+ and calls + # #init_save_history with this context. + # + # Will store the number of +val+ entries of history in the #history_file + # + # Add the following to your +.irbrc+ to change the number of history + # entries stored to 1000: + # + # IRB.conf[:SAVE_HISTORY] = 1000 + def save_history=(val) + IRB.conf[:SAVE_HISTORY] = val + if val + main_context = IRB.conf[:MAIN_CONTEXT] + main_context = self unless main_context + main_context.init_save_history + end + end + + # A copy of the default IRB.conf[:HISTORY_FILE] + def history_file + IRB.conf[:HISTORY_FILE] + end + + # Set IRB.conf[:HISTORY_FILE] to the given +hist+. + def history_file=(hist) + IRB.conf[:HISTORY_FILE] = hist + end + end + + module HistorySavingAbility # :nodoc: + include Readline + + def HistorySavingAbility.extended(obj) + IRB.conf[:AT_EXIT].push proc{obj.save_history} + obj.load_history + obj + end + + def load_history + if history_file = IRB.conf[:HISTORY_FILE] + history_file = File.expand_path(history_file) + end + history_file = IRB.rc_file("_history") unless history_file + if File.exist?(history_file) + open(history_file) do |f| + f.each {|l| HISTORY << l.chomp} + end + end + end + + def save_history + if num = IRB.conf[:SAVE_HISTORY] and (num = num.to_i) > 0 + if history_file = IRB.conf[:HISTORY_FILE] + history_file = File.expand_path(history_file) + end + history_file = IRB.rc_file("_history") unless history_file + + # Change the permission of a file that already exists[BUG #7694] + begin + if File.stat(history_file).mode & 066 != 0 + File.chmod(0600, history_file) + end + rescue Errno::ENOENT + rescue + raise + end + + open(history_file, 'w', 0600 ) do |f| + hist = HISTORY.to_a + f.puts(hist[-num..-1] || hist) + end + end + end + end +end diff --git a/jni/ruby/lib/irb/ext/tracer.rb b/jni/ruby/lib/irb/ext/tracer.rb new file mode 100644 index 0000000..691215a --- /dev/null +++ b/jni/ruby/lib/irb/ext/tracer.rb @@ -0,0 +1,71 @@ +# +# irb/lib/tracer.rb - +# $Release Version: 0.9.6$ +# $Revision: 47112 $ +# by Keiju ISHITSUKA(keiju@ruby-lang.org) +# +# -- +# +# +# +require "tracer" + +module IRB + + # initialize tracing function + def IRB.initialize_tracer + Tracer.verbose = false + Tracer.add_filter { + |event, file, line, id, binding, *rests| + /^#{Regexp.quote(@CONF[:IRB_LIB_PATH])}/ !~ file and + File::basename(file) != "irb.rb" + } + end + + class Context + # Whether Tracer is used when evaluating statements in this context. + # + # See +lib/tracer.rb+ for more information. + attr_reader :use_tracer + alias use_tracer? use_tracer + + # Sets whether or not to use the Tracer library when evaluating statements + # in this context. + # + # See +lib/tracer.rb+ for more information. + def use_tracer=(opt) + if opt + Tracer.set_get_line_procs(@irb_path) { + |line_no, *rests| + @io.line(line_no) + } + elsif !opt && @use_tracer + Tracer.off + end + @use_tracer=opt + end + end + + class WorkSpace + alias __evaluate__ evaluate + # Evaluate the context of this workspace and use the Tracer library to + # output the exact lines of code are being executed in chronological order. + # + # See +lib/tracer.rb+ for more information. + def evaluate(context, statements, file = nil, line = nil) + if context.use_tracer? && file != nil && line != nil + Tracer.on + begin + __evaluate__(context, statements, file, line) + ensure + Tracer.off + end + else + __evaluate__(context, statements, file || __FILE__, line || __LINE__) + end + end + end + + IRB.initialize_tracer +end + diff --git a/jni/ruby/lib/irb/ext/use-loader.rb b/jni/ruby/lib/irb/ext/use-loader.rb new file mode 100644 index 0000000..7282995 --- /dev/null +++ b/jni/ruby/lib/irb/ext/use-loader.rb @@ -0,0 +1,73 @@ +# +# use-loader.rb - +# $Release Version: 0.9.6$ +# $Revision: 47112 $ +# by Keiju ISHITSUKA(keiju@ruby-lang.org) +# +# -- +# +# +# + +require "irb/cmd/load" +require "irb/ext/loader" + +class Object + alias __original__load__IRB_use_loader__ load + alias __original__require__IRB_use_loader__ require +end + +module IRB + module ExtendCommandBundle + # Loads the given file similarly to Kernel#load, see IrbLoader#irb_load + def irb_load(*opts, &b) + ExtendCommand::Load.execute(irb_context, *opts, &b) + end + # Loads the given file similarly to Kernel#require + def irb_require(*opts, &b) + ExtendCommand::Require.execute(irb_context, *opts, &b) + end + end + + class Context + + IRB.conf[:USE_LOADER] = false + + # Returns whether +irb+'s own file reader method is used by + # +load+/+require+ or not. + # + # This mode is globally affected (irb-wide). + def use_loader + IRB.conf[:USE_LOADER] + end + + alias use_loader? use_loader + + # Sets IRB.conf[:USE_LOADER] + # + # See #use_loader for more information. + def use_loader=(opt) + + if IRB.conf[:USE_LOADER] != opt + IRB.conf[:USE_LOADER] = opt + if opt + if !$".include?("irb/cmd/load") + end + (class<<@workspace.main;self;end).instance_eval { + alias_method :load, :irb_load + alias_method :require, :irb_require + } + else + (class<<@workspace.main;self;end).instance_eval { + alias_method :load, :__original__load__IRB_use_loader__ + alias_method :require, :__original__require__IRB_use_loader__ + } + end + end + print "Switch to load/require#{unless use_loader; ' non';end} trace mode.\n" if verbose? + opt + end + end +end + + diff --git a/jni/ruby/lib/irb/ext/workspaces.rb b/jni/ruby/lib/irb/ext/workspaces.rb new file mode 100644 index 0000000..a11cea3 --- /dev/null +++ b/jni/ruby/lib/irb/ext/workspaces.rb @@ -0,0 +1,66 @@ +# +# push-ws.rb - +# $Release Version: 0.9.6$ +# $Revision: 47112 $ +# by Keiju ISHITSUKA(keiju@ruby-lang.org) +# +# -- +# +# +# + +module IRB # :nodoc: + class Context + + # Size of the current WorkSpace stack + def irb_level + workspace_stack.size + end + + # WorkSpaces in the current stack + def workspaces + if defined? @workspaces + @workspaces + else + @workspaces = [] + end + end + + # Creates a new workspace with the given object or binding, and appends it + # onto the current #workspaces stack. + # + # See IRB::Context#change_workspace and IRB::WorkSpace.new for more + # information. + def push_workspace(*_main) + if _main.empty? + if workspaces.empty? + print "No other workspace\n" + return nil + end + ws = workspaces.pop + workspaces.push @workspace + @workspace = ws + return workspaces + end + + workspaces.push @workspace + @workspace = WorkSpace.new(@workspace.binding, _main[0]) + if !(class<