Erasing a line in the REPL

Hi, is there a way to erase a line from the REPL ?
I’m using ProgressMeter but I’d also like to occasionally print a line when an event occurs.
I made the following MWE. Basically, I’d like the “I reached…” statement to erase the progress line, and in subsequent iterations, the progress will appear at the last line.

julia> using ProgressMeter

julia> prog = ProgressUnknown()
ProgressUnknown(false, false, 0, ProgressMeter.ProgressCore(:green, "Progress: ", 0.1, true, 0, Base.TTY(Base.Libc.WindowsRawSocket(0x000000000000027c) open, 0 bytes waiting), false, 1, 0, ReentrantLock(nothing, 0x00000000, 0x00, Base.GenericCondition{Base.Threads.SpinLock}(Base.IntrusiveLinkedList{Task}(nothing, nothing), Base.Threads.SpinLock(0)), (8, 1, 142273203075)), 0, 1, false, Int64[], 1.709735239111e9, 1.709735239111e9, 1.709735239111e9))

julia> for i in 1:100
       next!(prog)
       sleep(0.1)
       if i%25==0
       println("I reached $i")
       end
       end
Progress:  25    Time: 0:01:16I reached 25
Progress:  50    Time: 0:01:18I reached 50
Progress:  75    Time: 0:01:21I reached 75
Progress:  100    Time: 0:01:24I reached 100

println(rpad("\rI reached $i",displaysize(stdout)[2])) works a little better for the first line:

I reached 25
Progress:  50    Time: 0:00:06I reached 50                                                                                                                                                                       

Progress:  75    Time: 0:00:09I reached 75                                                                                                                                                                       

Progress:  100    Time: 0:00:12I reached 100 

But it creates unwanted blank lines, in addition to not working for the other lines.

To do so, you’ll want to print out a control sequence which instructs the terminal to delete the current line. The sequence for doing so is "\e[A\e[2K" which you can see in action in the following function:

julia> function hello()
           println("hello")
           sleep(1)
           print("\e[A\e[2K")
           println("goodbye!")
       end
hello (generic function with 1 method)

julia> hello()
# displays "hello"
# then clears the line and displays "goodbye!"

I tried altering your MWE:

julia> for i in 1:100
       next!(prog)
       sleep(0.1)
       if i%25==0
       print("\e[A\e[2K")
       println("I reached $i")
       end

It’s got some alignment issues, I’m not sure if it’s exactly what you’re going for, but it should at least get you pointed in the right direction.

2 Likes

Looks good! I fixed the alignment issue by adding a \r. However, now, the “I reached” lines erase one another. I’m not sure why this is erasing two lines.

1 Like

print("\e[A\e[2K") translates as “go up one line and erase that line”. To erase the line you’re currently on is just print("\e[2K"). It’s not 100% clear to me the exact effect you’re going for, but hopefully this should help you achieve it.

4 Likes

A \r could be used for erasing a line as well.

julia> begin
           print("Hello")
           sleep(1)
           print("\rWorld")
       end

4 Likes

See also set_multiline_postfix in alternative package ProgressBars.jl which supports this as a built in feature: GitHub - cloud-oak/ProgressBars.jl: A Julia clone of https://pypi.python.org/pypi/tqdm

1 Like

\r takes you back to the first column and you overwrite the old content. This can be dangerous if the new content is shorter than the old one:

begin
    print(100)
    sleep(1)
    print("\r", 2)  # better: print("\r\e[2K", 2)
end
1 Like

That’s not quite what’s happening here, try this one:

julia> begin
           print("Hello of Warcraft")
           sleep(1)
           print("\rWorld")
       end

But one can use "\e[K" to erase what’s left of the line, if desired:

julia> begin
           print("Hello of Warcraft")
           sleep(1)
           print("\rWorld\e[K")
       end
1 Like