134 lines
2.5 KiB
Ruby
134 lines
2.5 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
|
||
|
|
||
|
Readline.vi_editing_mode rescue NotImplementedError
|
||
|
Readline.completion_append_character = " "
|
||
|
Readline.completion_proc = method :complete
|
||
|
|
||
|
prepare_sub cl.subs
|
||
|
cl.cmd :exit, "exit", min: 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.desc[3..-1]}", min: 2 do
|
||
|
@cur = n.parent
|
||
|
end
|
||
|
n.cmd '', "", min: 2, aliases: [nil] do
|
||
|
@cur = n
|
||
|
end
|
||
|
n.subs.delete ''
|
||
|
n.aliases['?'] = n.subs['help']
|
||
|
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 ::UsageError
|
||
|
STDERR.puts "! #$!"
|
||
|
end
|
||
|
true
|
||
|
end
|
||
|
|
||
|
def run
|
||
|
while step
|
||
|
end
|
||
|
end
|
||
|
end
|