Вывод прогресса на месте в терминале или консоли
Когда ты бежишь git clone
, он обновляет прогресс на месте. Например, процент полученных объектов изменяется на месте.
user@athena:~/cloj/src$ git clone git://git.boinkor.net/slime.git
Initialized empty Git repository in /home/user/cloj/src/slime/.git/
remote: Counting objects: 15936, done.
remote: Compressing objects: 100% (5500/5500), done.
Receiving objects: 28% (4547/15936), 3.16 MiB | 165 KiB/s
Как это достигается? Использует ли он ncurses или что-то еще более простое, например, комбинацию символов возврата и обычного вывода символов?
Меня особенно интересует, как этот вид вывода на консоль может быть получен из Ruby.
РЕДАКТИРОВАТЬ
На мой оригинальный вопрос ответили. Но вот дополнение. Например, когда вы используете MPlayer, он обновляет не только строку, чтобы показать текущий прогресс, но и предыдущую строку (например, когда вы нажимаете паузу).
===== PAUSE =====
A: 79.9 (01:19.9) of 4718.0 ( 1:18:38.0) 0.3%
Как бы вы обновили две строки вывода на месте?
5 ответов
...
eol = done ? done : " \r";
...
fprintf(stderr, "...%s", ..., eol);
fflush(stderr);
Git просто выдает возврат каретки без перевода строки, который терминал интерпретирует как "перейти к первому столбцу".
Вам придется использовать другой метод (например, Curses), чтобы обновить две строки на месте.
ablogaboutcode.com | web.archive.org
...а также...
http://www.ruby-doc.org/stdlib-1.9.3/libdoc/curses/rdoc/Curses.html
Я написал небольшой класс для многострочного обновления вывода:
class ConsoleReset
# Unix
# Contains a string to clear the line in the shell
CLR = "\e[0K"
# ANSI escape sequence for hiding terminal cursor
ESC_CURS_INVIS = "\e[?25l"
# ANSI escape sequence for showing terminal cursor
ESC_CURS_VIS = "\e[?25h"
# ANSI escape sequence for clearing line in terminal
ESC_R_AND_CLR = "\r#{CLR}"
# ANSI escape sequence for going up a line in terminal
ESC_UP_A_LINE = "\e[1A"
def initialize
@first_call = true
end
def reset_line(text = '')
# Initialise ANSI escape string
escape = ""
# The number of lines the previous message spanned
lines = text.strip.lines.count - 1
# Clear and go up a line
lines.times { escape += "#{ESC_R_AND_CLR}#{ESC_UP_A_LINE}" }
# Clear the line that is to be printed on
# escape += "#{ESC_R_AND_CLR}"
# Console is clear, we can print!
STDOUT.print escape if !@first_call
@first_call = false
print text
end
def hide_cursor
STDOUT.print(ESC_CURS_INVIS)
end
def show_cursor
STDOUT.print(ESC_CURS_VIS)
end
def test
hide_cursor
5.times do |i|
line = ['===========================================']
(1..10).each do |num|
line << ["#{num}:\t#{rand_num}"]
end
line << ['===========================================']
line = line.join("\n")
reset_line(line)
sleep 1
end
show_cursor
puts ''
end
private
def rand_num
rand(10 ** rand(10))
end
end
Вдохновленный prydonius/spinning_cursor
, Увидеть test
метод для примера использования.
Есть несколько проклятий-библиотек для Ruby. Я считаю, что rbbcurse является наиболее поддерживаемым.