#-- # rbmh/command.rb : rbmhshow 0.4.2 # # Copyright (C) 2004--2005 Merlin Hughes # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # #++ # Pager commands # TODO: # support for repl formatting.. require 'rbmh/ansi' require 'merlin/each' module RBMH class Command def initialize(parameter, context) @parameter = parameter @context = context @color_execute = RBMH::ANSI.color(*(@context.profile['rbmh-color-execute'] or '').split(' ')) @uncolor = RBMH::ANSI.uncolor end # throw :abort ignored # throw :show repeats show def execute(message) end attr_reader :parameter, :context end def Command.expand(value) value and value.gsub(/\\(.)|\$(\w+)/) { |match| escape, variable = $1, $2 escape or ENV[variable] } end # -- commands below - class ExitCommand < Command def initialize(parameter, context) super(parameter, context) end def execute(message) code = Command.expand(parameter) exit(code ? code.to_i : 0) end end class ExecCommand < Command def execute(message) command = context.prompter.prompt("exec", "", Command.expand(parameter), "RBMH_EXEC") return if command.nil? # puts "#{@color_execute}#{command}#{@uncolor}" exec(command) end end # could handle command failure differently; e.g., prompt user class SystemCommand < Command def execute(message) command = context.prompter.prompt("system", "", Command.expand(parameter), "RBMH_SYSTEM") return if command.nil? # puts "#{@color_execute}#{command}#{@uncolor}" # system(command) # raise RBMH::Exception, "command failed - #{command}" if $?.exitstatus != 0 # TODO: add verbose flag? error handling flag? # result = `#{command} 3>&2 2>&1 1>&3` system(command) context.error("#{command} failed") if $?.exitstatus != 0 end end class EchoCommand < Command def execute(message) message = context.prompter.prompt("echo", "", Command.expand(parameter), "RBMH_ECHO") return if message.nil? puts(message) end end class ShowCommand < Command def execute(message) show = context.prompter.prompt("show", "", Command.expand(parameter), "RBMH_SHOW") return if show.nil? msgs = '' show.scan(/[^\|]+/).each_with_status { |what, status| what.strip! begin context.show(what) throw :show rescue RBMH::Exception msgs << (status.first? ? '' : status.last? ? ' or ' : ', ') << what end } # TODO: if range_str is long (e.g., show `pick all`) where = context.range_str ? "sequence #{context.range_str}" : "folder #{context.folder}" context.error("no #{msgs} message in #{where}") return nil end end class RefileCommand < Command def execute(message) folder = context.prompter.prompt("refile", "+", Command.expand(parameter), "RBMH_REFILE") return if folder.nil? # TODO: check whether the folder exists myself puts "#{@color_execute}refile +#{folder}#{@uncolor}" result = `refile +#{folder} 3>&2 2>&1 1>&3` if $?.exitstatus != 0 context.error(result.empty? ? "refile failed" : result.chop) end end end class StoreCommand < Command def execute(message) @context.shower.toc(message, STDOUT) directory = context.prompter.prompt("directory", "", Command.expand(parameter), "RBMH_STORE") return if directory.nil? parts = context.prompter.prompt("parts", "^", "?", nil) return if parts.nil? if parts =~ RangesRE ranges = parts.scan(RangeRE).collect { |start, finish| finish ? (start.to_i .. finish.to_i).to_a : start } parts = "(#{ranges.join('|')})(\\D|$)" end begin message.store(/^#{parts}/, directory) rescue RBMH::Exception context.error($!.message) end end RangeRE = /(\d+)(?:\s*-\s*(\d+))?/ RangesRE = /^\s*#{RangeRE.source}\s*(,\s*#{RangeRE.source})*\s*$/ end class EnvCommand < Command def initialize(parameter, context) super(parameter, context) raise RBMH::Exception, "missing parameter to env" if parameter.nil? raise RBMH::Exception, "invalid parameter to env - #{parameter}" unless parameter =~ EnvRE end def execute(message) Command.expand(parameter) =~ EnvRE variable, assignment, value = $1, $2, $3 if ('=' == assignment) || (('^=' == assignment) && (value != ENV[variable])) ENV[variable] = value else ENV.delete(variable) end end EnvRE = /^(\w+)\s*(=|\^=|\/=)\s*(.*)$/ end def Command.lookup(command, parameter, context) impl = CommandTable[command] if impl.is_a?(Class) impl.new(parameter, context) elsif impl.is_a?(String) raise RBMH::Exception, "unexpected parameter to #{command} - #{parameter}" if parameter lookup(impl, command, context) else raise RBMH::Exception, "unknown command - #{command}" end end CommandTable = { "exit" => ExitCommand, "exec" => ExecCommand, "system" => SystemCommand, "echo" => EchoCommand, "show" => ShowCommand, "refile" => RefileCommand, "store" => StoreCommand, "env" => EnvCommand, "cur" => "show", # show(cur) "next" => "show", # show(next) "prev" => "show", # show(prev) "last" => "show", # show(last) "first" => "show", # show(first) } end # module RBMH