Repository: JuliaLang/julia
File: stdlib/REPL/src/LineEdit.jl (Julia)

Code before:
function refresh_multi_line(termbuf::TerminalBuffer, terminal::UnixTerminal, buf::IOBuffer,
                            state::InputAreaState, prompt = "";
                            indent::Int = 0, region_active::Bool = false)
    _clear_input_area(termbuf, state)

    cols = width(terminal)
    rows = height(terminal)
    curs_row = -1 # relative to prompt (1-based)
    curs_pos = -1 # 1-based column position of the cursor
    cur_row = 0   # count of the number of rows
    buf_pos = position(buf)
    line_pos = buf_pos
    regstart, regstop = region(buf)
    written = 0
    # Write out the prompt string
    lindent = write_prompt(termbuf, prompt, hascolor(terminal))::Int
    # Count the '\n' at the end of the line if the terminal emulator does (specific to DOS cmd prompt)
    miscountnl = @static Sys.iswindows() ? (isa(Terminals.pipe_reader(terminal), Base.TTY) && !(Base.ispty(Terminals.pipe_reader(terminal)))::Bool) : false

    # Now go through the buffer line by line
    seek(buf, 0)
    moreinput = true # add a blank line if there is a trailing newline on the last line
    lastline = false # indicates when to stop printing lines, even when there are potentially
                     # more (for the case where rows is too small to print everything)
                     # Note: when there are too many lines for rows, we still print the first lines
                     # even if they are going to not be visible in the end: for simplicity, but
                     # also because it does the 'right thing' when the window is resized
    while moreinput
        line = readline(buf, keep=true)
        moreinput = endswith(line, "\n")
        if rows == 1 && line_pos <= sizeof(line) - moreinput
            # we special case rows == 1, as otherwise by the time the cursor is seen to
            # be in the current line, it's too late to chop the '\n' away
            lastline = true
            curs_row = 1
            curs_pos = lindent + line_pos
        end
        if moreinput && lastline # we want to print only one "visual" line, so
            line = chomp(line)   # don't include the trailing "\n"
        end
        # We need to deal with on-screen characters, so use textwidth to compute occupied columns
        llength = textwidth(line)
        slength = sizeof(line)
        cur_row += 1
        # lwrite: what will be written to termbuf
        lwrite = region_active ? highlight_region(line, regstart, regstop, written, slength) :
                                 line
        written += slength
        cmove_col(termbuf, lindent + 1)
        write(termbuf, lwrite)
        # We expect to be line after the last valid output line (due to

Review comment (bug):
I am experiencing frequent REPL corruption now where I lose part of the line or it prints wrong. For example, if you type
```
julia> using Cthu, REPL
```
then mouse back and change that to
```
julia> using Cthulhu, REPL
```
when you start typing, it will garble the rest of the line. Then when you type the final `u`, the line gets fully deleted. Once you type another character, then it gets restored correctly.

Code after:
    if state.curs_row < state.num_rows
        cmove_down(terminal, state.num_rows - state.curs_row)
    end

    # Clear lines one by one going up
    for j = 2:state.num_rows
        clear_line(terminal)
        cmove_up(terminal)
    end

    # Clear top line
    clear_line(terminal)
    nothing
end

prompt_string(s::PromptState) = prompt_string(s.p)
prompt_string(p::Prompt) = prompt_string(p.prompt)
prompt_string(s::AbstractString) = s
prompt_string(f::Function) = Base.invokelatest(f)

function maybe_show_hint(s::PromptState)
    isa(s.hint, String) || return nothing
    # The hint being "" then nothing is used to first clear a previous hint, then skip printing the hint
    # the clear line cannot be printed each time because it breaks column movement
    if isempty(s.hint)
        print(terminal(s), "\e[0K") # clear remainder of line which had a hint
        s.hint = nothing
    else
        Base.printstyled(terminal(s), s.hint, color=:light_black)
        cmove_left(terminal(s), textwidth(s.hint))
        s.hint = "" # being "" signals to do one clear line remainder to clear the hint next time if still empty
    end
    return nothing
end

function refresh_multi_line(s::PromptState; kw...)
    if s.refresh_wait !== nothing
        close(s.refresh_wait)
        s.refresh_wait = nothing
    end
    r = refresh_multi_line(terminal(s), s; kw...)
    maybe_show_hint(s)
    return r
end
refresh_multi_line(s::ModeState; kw...) = refresh_multi_line(terminal(s), s; kw...)
refresh_multi_line(termbuf::TerminalBuffer, s::ModeState; kw...) = refresh_multi_line(termbuf, terminal(s), s; kw...)
refresh_multi_line(termbuf::TerminalBuffer, term, s::ModeState; kw...) = (@assert term === terminal(s); refresh_multi_line(termbuf,s; kw...))

function refresh_multi_line(termbuf::TerminalBuffer, terminal::UnixTerminal, buf::IOBuffer,
                            state::InputAreaState, prompt = "";
                            indent::Int = 0, region_active::Bool = false)