Writing over previously output lines in the command prompt with ruby
Use \r
to move the cursor to the beginning of the line. And you should not be using puts
as it adds \n
, use print
instead. Like this:
print "11MB 294K/s"
print "\r"
print "12MB 307K/s"
One thing to keep in mind though: \r
doesn't delete anything, it just moves the cursor back, so you would need to pad the output with spaces to overwrite the previous output (in case it was longer).
By default when \n
is printed to the standard output the buffer is flushed. Now you might need to use STDOUT.flush
after print
to make sure the text get printed right away.
Ruby windows command prompt previous lines
Yes you can, on a Windows Vista, 7 and probably 8 and also in some third-party extended command-interpreters like 4NT and Take Command you can recall previous commands by using the up-key, edit the line and re-execute the line. I don't see what Ruby has got to do with this. If you want to let Ruby type keystrokes in a console that is possible using the auto-it Active-X control.
EDIT: here a sample using Autoit to edit the console, downlaod and install it first and then run the following script. To make sure the script doesn't interact with other open consoles i copied mu cmd.exe to a cmd2.exe which is started up first.
require 'win32ole'
title = "C:\\Windows\\System32\\cmd2.exe"
STDOUT.sync = true
ai = WIN32OLE.new("AutoItX3.Control")
ai.winwait(title)
ai.WinActivate(title, "")
ai.Send "cls{ENTER}"
1.upto(4) do |i|
ai.Send "line#{i}{ENTER}"
end
1.upto(4) do |i|
ai.Send "{UP}"
sleep 1
end
ai.Send "line one {ENTER}"
How to override or edit the last printed lines in a ruby CLI script?
A while ago I created a class to be a status text on which you can change part of the content of the text within the line. It might be useful to you.
The class with an example use are:
class StatusText
def initialize(parms={})
@previous_size = 0
@stream = parms[:stream]==nil ? $stdout : parms[:stream]
@parms = parms
@parms[:verbose] = true if parms[:verbose] == nil
@header = []
@onChange = nil
pushHeader(@parms[:base]) if @parms[:base]
end
def setText(complement)
text = "#{@header.join(" ")}#{@parms[:before]}#{complement}#{@parms[:after]}"
printText(text)
end
def cleanAll
printText("")
end
def cleanContent
printText "#{@parms[:base]}"
end
def nextLine(text=nil)
if @parms[:verbose]
@previous_size = 0
@stream.print "\n"
end
if text!=nil
line(text)
end
end
def line(text)
printText(text)
nextLine
end
#Callback in the case the status text changes
#might be useful to log the status changes
#The callback function receives the new text
def onChange(&block)
@on_change = block
end
def pushHeader(head)
@header.push(head)
end
def popHeader
@header.pop
end
def setParm(parm, value)
@parms[parm] = value
if parm == :base
@header.last = value
end
end
private
def printText(text)
#If not verbose leave without printing
if @parms[:verbose]
if @previous_size > 0
#go back
@stream.print "\033[#{@previous_size}D"
#clean
@stream.print(" " * @previous_size)
#go back again
@stream.print "\033[#{@previous_size}D"
end
#print
@stream.print text
@stream.flush
#store size
@previous_size = text.gsub(/\e\[\d+m/,"").size
end
#Call callback if existent
@on_change.call(text) if @on_change
end
end
a = StatusText.new(:before => "Evolution (", :after => ")")
(1..100).each {|i| a.setText(i.to_s); sleep(1)}
a.nextLine
Just copy, paste in a ruby file and try it out. I use escape sequences to reposition the cursor.
The class has lots of features I needed at the time (like piling up elements in the status bar) that you can use to complement your solution, or you can just clean it up to its core.
I hope it helps.
How to overwrite a printed line in the shell with Ruby?
You can use the \r
escape sequence at the end of the line (the next line will overwrite this line). Following your example:
require 'time'
loop do
time = Time.now.to_s + "\r"
print time
$stdout.flush
sleep 1
end
Ruby outputting to the same line as the previous output
Yes, use print var
instead; puts
automatically appends a new line, print
doesn't.
How to overwrite the current console line after gets in Ruby?
Overwriting current line (printing "\r"
) works just fine with gets
. The thing is, gets
reads a line until (and including) a linebreak. So it is you, pressing ENTER
, who moves cursor to a next line. And then this next, already empty, line is rewinded by \r
.
Moving to a previous line is not possible in the regular mode. (see comments) You need to use a lower-level terminal window access. curses
is a popular library. Ruby has bindings for it. I suggest you start with this blog post (and follow-ups to it): http://graysoftinc.com/terminal-tricks/random-access-terminal
How to code press key to continue
You can use STDIN from the IO class, rather than gets
.
require 'io/console'
def continue_story
print "press any key"
STDIN.getch
print " \r" # extra space to overwrite in case next sentence is short
end
puts "An awesome story begins..."
continue_story
puts "And ends after 2 lines"
This has the added bonus that it only requires one character to be entered (getch
- get character) allowing the 'press any key' to work without a return or enter.
Deleting multiple lines of terminal output using ruby
Well, for simple things, if you can assume an ANSI-compatible terminal (usually a good bet), you can just directly output ANSI codes. For instance,
5.times do |item|
print "\r" + ("\e[A\e[K"*3) if item > 0
puts "#{item+1}\nHello!"
end
Where \r
moves the cursor to the start of the line, \e[A
moves the cursor up one line, and \e[K
clears from the cursor position to the end of the line. If you don't need anything further down the screen, you can also just send \e[J
once you have the cursor where you want; that clears all the way to the end of the screen.
For more sophisticated stuff, you could start by taking a look at the Highline gem.
Persistent Command Line Display
Depending on your needs, erasing the screen and creating the grid again could be good enough :
def show_grid
line = '+---+---+---+---+---+---+---+---+---+'
puts line
9.times do
row = (1..9).map { rand(9) + 1 }
puts '| ' + row.join(' | ') + ' |'
puts line
end
end
def clear_screen
system('clear') || system('cls')
end
loop do
clear_screen
show_grid
sleep 1
end
It outputs
+---+---+---+---+---+---+---+---+---+
| 1 | 2 | 7 | 3 | 4 | 9 | 8 | 6 | 5 |
+---+---+---+---+---+---+---+---+---+
| 1 | 8 | 1 | 7 | 6 | 2 | 2 | 1 | 3 |
+---+---+---+---+---+---+---+---+---+
| 2 | 2 | 1 | 2 | 2 | 8 | 2 | 3 | 6 |
+---+---+---+---+---+---+---+---+---+
| 5 | 3 | 6 | 1 | 5 | 3 | 2 | 7 | 9 |
+---+---+---+---+---+---+---+---+---+
| 9 | 7 | 7 | 4 | 7 | 2 | 2 | 9 | 1 |
+---+---+---+---+---+---+---+---+---+
| 5 | 9 | 1 | 9 | 3 | 7 | 8 | 3 | 1 |
+---+---+---+---+---+---+---+---+---+
| 8 | 5 | 4 | 7 | 3 | 2 | 2 | 5 | 3 |
+---+---+---+---+---+---+---+---+---+
| 4 | 7 | 1 | 1 | 4 | 8 | 4 | 1 | 1 |
+---+---+---+---+---+---+---+---+---+
| 1 | 1 | 8 | 4 | 2 | 4 | 8 | 3 | 8 |
+---+---+---+---+---+---+---+---+---+
then
+---+---+---+---+---+---+---+---+---+
| 6 | 4 | 4 | 3 | 5 | 5 | 8 | 9 | 1 |
+---+---+---+---+---+---+---+---+---+
| 7 | 7 | 7 | 3 | 3 | 2 | 8 | 7 | 6 |
+---+---+---+---+---+---+---+---+---+
| 6 | 2 | 2 | 1 | 4 | 7 | 1 | 1 | 9 |
+---+---+---+---+---+---+---+---+---+
| 3 | 8 | 7 | 7 | 7 | 9 | 7 | 4 | 4 |
+---+---+---+---+---+---+---+---+---+
| 4 | 1 | 2 | 8 | 6 | 7 | 1 | 9 | 3 |
+---+---+---+---+---+---+---+---+---+
| 6 | 7 | 7 | 5 | 1 | 7 | 6 | 7 | 4 |
+---+---+---+---+---+---+---+---+---+
| 8 | 2 | 3 | 5 | 3 | 5 | 4 | 7 | 2 |
+---+---+---+---+---+---+---+---+---+
| 5 | 9 | 3 | 2 | 4 | 2 | 9 | 6 | 3 |
+---+---+---+---+---+---+---+---+---+
| 1 | 7 | 8 | 9 | 4 | 3 | 4 | 1 | 5 |
+---+---+---+---+---+---+---+---+---+
then...
It should work on Windows/Linux/MacOs.
For anything more complex, you'll need an ncurses gem.
Pre-Filled Prompt in Ruby
You can do it with RbReadline:
require 'rubygems'
require 'rb-readline'
module RbReadline
def self.prefill_prompt(str)
@rl_prefill = str
@rl_startup_hook = :rl_prefill_hook
end
def self.rl_prefill_hook
rl_insert_text @rl_prefill if @rl_prefill
@rl_startup_hook = nil
end
end
RbReadline.prefill_prompt("Previous query")
str = Readline.readline("Enter query: ", true)
puts "You entered: #{str}"
Related Topics
Is There a Literal Notation for an Array of Symbols
What Do the Different Brackets in Ruby Mean
How to Make a Ruby String Safe for a Filesystem
Create Array of N Items Based on Integer Value
How to Use Watir::Waiter::Wait_Until to Force Chrome to Wait
What Does :: (Double Colon) Mean in Ruby
How to Add a Virtual Attribute to a Model in Ruby on Rails
Migrating from Rails 2 to Rails 3
How to Convert from a String to Object Attribute Name
-%>' (Minus Sign) at the End of a Erb Sequence
How to Run Rails Console in the Test Environment and Load Test_Helper.Rb
Modify Ruby Hash in Place( Rails Strong Params)
Ruby - Replace the First Occurrence of a Substring with Another String
What Is the %W "Thing" in Ruby
How to Test If a Div Has a Certain CSS Style in Rspec/Capybara