Overwriting previous terminal output with built-in functions

It looks like REPL.Terminals has what I am looking for in the functions starting with cmove:

julia> REPL.Terminals.cmove

cmove            cmove_col        cmove_down
cmove_left       cmove_line_down  cmove_line_up
cmove_right      cmove_up

It just requires a terminal as the first argument, which you can get a handle to via the following line (From this discourse discussion on the topic):

import REPL
terminal = REPL.Terminals.TTYTerminal(string(), stdin, stdout, stderr)

By inspecting the source, it turns out the these functions are exactly just pretty packaging of the escape sequences. Here are lines 113 to 121 from the file defining REPL.Terminals.clear_line

const CSI = "\x1b["

cmove_up(t::UnixTerminal, n) = write(t.out_stream, "$(CSI)$(n)A")
cmove_down(t::UnixTerminal, n) = write(t.out_stream, "$(CSI)$(n)B")
cmove_right(t::UnixTerminal, n) = write(t.out_stream, "$(CSI)$(n)C")
cmove_left(t::UnixTerminal, n) = write(t.out_stream, "$(CSI)$(n)D")
cmove_line_up(t::UnixTerminal, n) = (cmove_up(t, n); cmove_col(t, 1))
cmove_line_down(t::UnixTerminal, n) = (cmove_down(t, n); cmove_col(t, 1))
cmove_col(t::UnixTerminal, n) = (write(t.out_stream, '\r'); n > 1 && cmove_right(t, n-1))

With this, I was able to put together this example, completely without learning the codes. Sweet!

import REPL
terminal = REPL.Terminals.TTYTerminal(string(), stdin, stdout, stderr)
println()  # Dummy line
for i in (1, "two", :III, "||||")
	REPL.Terminals.cmove_left(terminal, length(string(i)))
	REPL.Terminals.cmove_line_up(terminal)
	println(i)
	sleep(0.5)
end
println("Watch the final number dissapear above me")
sleep(0.5)
REPL.Terminals.cmove_line_up(terminal, 2)
REPL.Terminals.clear_line(terminal)
REPL.Terminals.cmove_line_down(terminal, 3)  # If not, next input is above previous output, which looks funny

3 Likes