module VimGolf GOLFDEBUG = ENV['GOLFDEBUG'].to_sym rescue false GOLFHOST = ENV['GOLFHOST'] || "http://vimgolf.com" GOLFDIFF = ENV['GOLFDIFF'] || 'diff' GOLFSHOWDIFF = ENV['GOLFSHOWDIFF'] || 'vim -d -n' GOLFVIM = ENV['GOLFVIM'] || 'vim' PROXY = ENV['http_proxy'] || '' class Error end class RetryException < Exception; end class UI def debug(*); end end class << self attr_accessor :ui def ui @ui ||= UI.new end end class CLI < Thor include Thor::Actions def self.start(*) Thor::Base.shell = VimGolf::CLI::UI VimGolf.ui = VimGolf::CLI::UI.new super end desc "setup", "configure your VimGolf credentials" long_desc <<-DESC To participate in the challenge please go to vimgolf.com and register an account. Once signed in, you will get your API key, which you need to setup the command client. If you have the key, simply run the setup and paste in your key. DESC def setup key = VimGolf.ui.ask "Please specify your VimGolf API key (register on vimgolf.com to get it):" if key =~ /[\w\d]{32}/ FileUtils.mkdir_p Config.path FileUtils.mkdir_p Config.put_path Config.save({'key' => key}) VimGolf.ui.info "Saved. Happy golfing!" else VimGolf.ui.error "Invalid key, please double check your key on vimgolf.com" end end desc "put [ID]", "launch Vim session" long_desc <<-DESC Launch a VimGolf session for the specified challenge ID. To find a currently active challenge ID, please visit vimgolf.com! DESC def put(id = nil) VimGolf.ui.warn "Downloading Vimgolf challenge: #{id}" VimGolf::Challenge.path(Config.put_path) challenge = Challenge.new(id) challenge.download begin VimGolf.ui.warn "Launching VimGolf session for challenge: #{id}" # - n - no swap file, memory only editing # - +0 - always start on line 0 # - --noplugin - don't load any plugins, lets be fair! # -i NONE - don't load .viminfo (for saved macros and the like) # - u - load vimgolf .vimrc to level the playing field vimcmd = "#{GOLFVIM} -Z -n --noplugin -i NONE +0 -u \"#{challenge.vimrc_path}\" -W \"#{challenge.log_path}\" \"#{challenge.work_path}\"" debug(vimcmd) system(vimcmd) if $?.exitstatus.zero? diff_files = "\"#{challenge.work_path}\" \"#{challenge.output_path}\"" diff = `#{GOLFDIFF} #{diff_files}` log = Keylog.new(IO.read(challenge.log_path)) if diff.size > 0 VimGolf.ui.warn "Uh oh, looks like your entry does not match the desired output." loop do case VimGolf.ui.ask_question "Would you like to see a [d]iff or [r]etry or [q]uit ?", :type => :warn, :choices => [:diff, :retry, :quit] when :diff VimGolf.ui.warn "Showing vimdiff of your attempt (left) and correct output (right)" system("#{GOLFSHOWDIFF} #{diff_files}") when :retry VimGolf.ui.warn "Your score for this (failed) attempt was: #{log.score}. Let's try again!!\n#{'#'*50}" challenge.start raise RetryException when :quit VimGolf.ui.warn "Please try again! Your score for this (failed) attempt was: #{log.score}" return end end end VimGolf.ui.info "Success! Your output matches. Your score: #{log.score}" if VimGolf.ui.yes? "Upload result to VimGolf? (yes / no)" VimGolf.ui.warn "Uploading to VimGolf..." if challenge.upload == :ok VimGolf.ui.info "Uploaded entry, thanks for golfing!" VimGolf.ui.info "View the leaderboard: #{GOLFHOST}/challenges/#{id}" else VimGolf.ui.error "Uh oh, upload failed. You're not cheating are you? :-)" end else VimGolf.ui.warn "Skipping upload. Thanks for playing. Give it another shot!" end else error = <<-MSG Uh oh, Vim did not exit properly. If the problem persists, please report the error on github.com/igrigorik/vimgolf MSG VimGolf.ui.error error end rescue RetryException => e retry end rescue Exception => e VimGolf.ui.error "Uh oh, something went wrong! Error: #{e}" VimGolf.ui.error "If the error persists, please report it to github.com/igrigorik/vimgolf" end private def debug(msg) p [caller.first, msg] if GOLFDEBUG end end end