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