Class: Harp::REPL

Inherits:
Object
  • Object
show all
Defined in:
lib/harp/repl.rb

Constant Summary collapse

Prompt =
"<3: "

Instance Method Summary collapse

Constructor Details

#initialize(command_manager, options = {}) ⇒ REPL

Returns a new instance of REPL.



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/harp/repl.rb', line 13

def initialize(command_manager, options={})
  @command_manager = command_manager
  Readline.completion_proc = self.method(:complete)
  if options[:history_file]
    limit = options[:history_limit] || 100
    if File.exist?(options[:history_file])
      string = File.read(options[:history_file])
      string.each_line do |line|
        Readline::HISTORY << line.chomp
      end
    end
    at_exit do
      File.open(options[:history_file], "w") do |f|
        Readline::HISTORY.to_a.last(limit).each do |line|
          f.puts line unless line.empty?
        end
      end
    end
  end
end

Instance Method Details

#command_complete(str) ⇒ Object



73
74
75
# File 'lib/harp/repl.rb', line 73

def command_complete(str)
  commands.grep(/^#{Regexp.escape(str)}/) 
end

#commandsObject



34
35
36
# File 'lib/harp/repl.rb', line 34

def commands
  @command_manager.commands.keys
end

#complete(str) ⇒ Object



38
39
40
41
42
43
44
45
46
47
48
# File 'lib/harp/repl.rb', line 38

def complete(str)
  case Readline.line_buffer
  when /^\s*!/
    # if we're in the middle of a bang-exec command, completion
    # should look at the file system.
    self.complete_path(str)
  else
    # otherwise use the internal dict.
    self.complete_term(str)
  end
end

#complete_path(str) ⇒ Object



50
51
52
# File 'lib/harp/repl.rb', line 50

def complete_path(str)
  Dir.glob("#{str}*")
end

#complete_term(str) ⇒ Object



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/harp/repl.rb', line 54

def complete_term(str)
  # Terms can be either commands or indexes into the configuration
  # data structure.  No command contains a ".", so that's the test
  # we use to distinguish.
  bits = str.split(".")
  if bits.size > 1
    # An attempt to allow completion of either full configuration index
    # strings, or of component parts.  E.g., if the configuration contains
    # foo.bar.baz, this code will offer both "foo" and "foo.bar.baz"
    # as completions for "fo".
    v1 = @completions.grep(/^#{Regexp.escape(str)}/)
    v2 = @completions.grep(/^#{Regexp.escape(bits.last)}/)
    (v1 + v2.map {|x| (bits.slice(0..-2) << x).join(".") }).uniq
  else
    self.command_complete(str) +
      @completions.grep(/^#{Regexp.escape(str)}/)
  end
end

#run(context) ⇒ Object



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
# File 'lib/harp/repl.rb', line 83

def run(context)
  @completions = context.completions rescue Set.new
  @run = true
  puts

  stty_save = `stty -g`.chomp
  kill_handler = proc do
    system("stty", stty_save)
    exit
  end
  trap("INT", kill_handler)
  trap("TERM", kill_handler)

  while @run && (line = Readline.readline(Prompt, true).strip)

    # Don't fill history with immediate duplicates.
    one, two = Readline::HISTORY.to_a.last(2)
    if one == two
      Readline::HISTORY.pop
    end

    # Treat ! as the shell out command
    if line[0] == "!"
      system(line.slice(1..-1))
      next
    end

    if line.empty?
      next
    end

    name, *args = line.split(/\s+/)

    begin
      @command_manager.handle(name, args, context)
    rescue ArgumentError => e
      puts e.message
    end
  end
end

#sanitize(str) ⇒ Object



77
78
79
80
81
# File 'lib/harp/repl.rb', line 77

def sanitize(str)
  # ANSI code stripper regex cargo culted from
  # http://www.commandlinefu.com/commands/view/3584/remove-color-codes-special-characters-with-sed
  str.gsub(/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]/, "")
end