require 'io/console' height, width = $stdout.winsize # No cursor, input 1 char at a time print "\e[?25l"; at_exit { print "\e[?25h" } $stdin.raw!; at_exit { $stdin.cooked! } # Load or create the new canvas if ARGV[0] canvas = File.read(ARGV[0]).lines.map { |line| line.chomp.chars.map(&:to_i) } else canvas = Array.new(height-1) { Array.new width-1, 0 } end # To save it once done (doing it this way so we have access to the canvas local var) define_method :save do filename = ARGV[0]||'image' File.write filename, canvas.map(&:join).join("\n") print "\r\nSaved in #{filename.inspect}" end # Promt whether to save, upon exit at_exit do print "\e[1;1HSAVE? " save if $stdin.getc == 'y' end # Edit the canvas x = y = 0 loop do # Draw each square the colour specified image = canvas.map { |ns| ns.map { |n| "\e[4#{n}m " }.join }.join("\e[0m\r\n") print "\e[2;1H#{image}\e[#{y+2};#{x+1}H\e[4#{canvas[y][x]}m#{canvas[y][x]}" # Depending on what they press, we'll either quit, save, move, or colour the canvas char = $stdin.getc case char when "\x03", "q" then break when 's' then save when 'h' then x -= 1 when 'j' then y += 1 when 'k' then y -= 1 when 'l' then x += 1 when /\d/ then canvas[y][x] = char.to_i end end