139 lines
2.7 KiB
Ruby
139 lines
2.7 KiB
Ruby
require_relative '../dencli'
|
|
|
|
class DenCli::Interactive
|
|
attr_reader :cl, :prompt, :cur, :histfile
|
|
|
|
def initialize cl, prompt, histfile: nil
|
|
require 'readline'
|
|
@cl, self.prompt = cl, prompt
|
|
@cur = cl.subs
|
|
cur.instance_variable_set :@name, ''
|
|
|
|
@histfile =
|
|
case histfile
|
|
when nil then nil
|
|
when Pathname then histfile
|
|
else Pathname.new histfile.to_s
|
|
end
|
|
read_history if @histfile
|
|
|
|
begin
|
|
Readline.vi_editing_mode
|
|
rescue NotImplementedError
|
|
end
|
|
Readline.completion_append_character = " "
|
|
Readline.completion_proc = method :complete
|
|
|
|
prepare_sub cl.subs
|
|
cl.cmd :exit, "exit", min: cl.has?(:ex) ? cl.has?(:exi) ? 4 : 3 : 2 do
|
|
exit 0
|
|
end
|
|
cl.subs.aliases['?'] = cl.subs.subs['help']
|
|
cl.subs.subs.delete 'cli'
|
|
|
|
stty_save = %x`stty -g`.chomp
|
|
trap "INT" do
|
|
system "stty", stty_save
|
|
Readline.refresh_line
|
|
end
|
|
end
|
|
|
|
def history_file file = nil
|
|
file =
|
|
case file
|
|
when Pathname then file
|
|
when nil then @histfile
|
|
else Pathname.new file.to_s
|
|
end
|
|
end
|
|
|
|
def read_history file = nil
|
|
file = history_file file
|
|
return unless file and file.exist?
|
|
file.each_line do |line|
|
|
Readline::HISTORY.push line.chomp
|
|
end
|
|
end
|
|
|
|
def write_history file = nil
|
|
file = history_file file
|
|
return unless file
|
|
file.open 'w+' do |f|
|
|
Readline::HISTORY.each do |line|
|
|
f.puts line
|
|
end
|
|
end
|
|
end
|
|
|
|
def prompt= s
|
|
@prompt = s.to_s
|
|
end
|
|
|
|
def complete s
|
|
ws = words Readline.line_buffer
|
|
@cur.complete *ws[0...-1], s
|
|
end
|
|
|
|
def sub *args, cur: nil
|
|
args.inject( cur || @cur) do |r, a|
|
|
return nil unless r.is_a? DenCli::Sub
|
|
r[a]
|
|
end
|
|
end
|
|
private :sub
|
|
|
|
def words line = nil
|
|
r = line.split " "
|
|
r.push '' if ' ' == line[-1]
|
|
r
|
|
end
|
|
private :words
|
|
|
|
def prepare_sub c
|
|
c.subs.values.each do |n|
|
|
case n
|
|
when DenCli::Sub
|
|
n.cmd :exit,
|
|
"<- #{n.parent.full_cmd.join ' '} - #{n.parent.description[3..-1]}",
|
|
min: n.has?(:ex) ? n.has?( :exi) ? 4 : 3 : 2,
|
|
&lambda {|| @cur = n.parent }
|
|
n.aliases.delete nil
|
|
n.subs.delete nil
|
|
n.cmd '', "", min: 2, aliases: [nil] do
|
|
@cur = n
|
|
end
|
|
n.aliases['?'] = n[:help] if n.has? :help and not n.has? '?'
|
|
prepare_sub n
|
|
when DenCli::CMD
|
|
else raise "Unsupported sub-type: #{x}"
|
|
end
|
|
end
|
|
end
|
|
|
|
def read
|
|
line = Readline.readline( "#{prompt}#{cur.full_cmd.join ' '}> ", true)
|
|
return nil if line.nil?
|
|
Readline::HISTORY.pop if /^\s*$/ =~ line
|
|
if 0 < Readline::HISTORY.length-2 and Readline::HISTORY[Readline::HISTORY.length-2] == line
|
|
Readline::HISTORY.pop
|
|
end
|
|
line.split " "
|
|
end
|
|
|
|
def step
|
|
line = read
|
|
return nil if line.nil?
|
|
begin
|
|
cur.call *line
|
|
rescue ::DenCli::UsageError
|
|
$stderr.puts "! #$!"
|
|
end
|
|
true
|
|
end
|
|
|
|
def run
|
|
while step
|
|
end
|
|
end
|
|
end
|