Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

REPL: try to coalesce screen updates #39538

Merged
merged 1 commit into from
Mar 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 56 additions & 11 deletions stdlib/REPL/src/LineEdit.jl
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ mutable struct PromptState <: ModeState
beeping::Float64
# this option is to detect when code is pasted in non-"bracketed paste mode" :
last_newline::Float64 # register when last newline was entered
# this option is to speed up output
refresh_wait::Union{Timer,Nothing}
end

options(s::PromptState) =
Expand Down Expand Up @@ -371,8 +373,17 @@ function complete_line(s::PromptState, repeats::Int)
return true
end

function clear_input_area(terminal::AbstractTerminal, s::PromptState)
if s.refresh_wait !== nothing
close(s.refresh_wait)
s.refresh_wait = nothing
end
_clear_input_area(terminal, s.ias)
s.ias = InputAreaState(0, 0)
end
clear_input_area(terminal::AbstractTerminal, s::ModeState) = (_clear_input_area(terminal, s.ias); s.ias = InputAreaState(0, 0))
clear_input_area(s::ModeState) = clear_input_area(s.terminal, s)

function _clear_input_area(terminal::AbstractTerminal, state::InputAreaState)
# Go to the last line
if state.curs_row < state.num_rows
Expand All @@ -395,6 +406,13 @@ prompt_string(p::Prompt) = prompt_string(p.prompt)
prompt_string(s::AbstractString) = s
prompt_string(f::Function) = Base.invokelatest(f)

function refresh_multi_line(s::PromptState; kw...)
if s.refresh_wait !== nothing
close(s.refresh_wait)
s.refresh_wait = nothing
end
refresh_multi_line(terminal(s), s; kw...)
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...))
Expand Down Expand Up @@ -738,7 +756,7 @@ function edit_insert(s::PromptState, c::StringLike)
buf = s.input_buffer

if ! options(s).auto_indent_bracketed_paste
pos=position(buf)
pos = position(buf)
if pos > 0
if buf.data[pos] != _space && string(c) != " "
options(s).auto_indent_tmp_off = false
Expand All @@ -757,20 +775,46 @@ function edit_insert(s::PromptState, c::StringLike)
end
end

old_wait = s.refresh_wait !== nothing
if old_wait
close(s.refresh_wait)
s.refresh_wait = nothing
end
str = string(c)
edit_insert(buf, str)
offset = s.ias.curs_row == 1 || s.indent < 0 ?
sizeof(prompt_string(s.p.prompt)::String) : s.indent
if !('\n' in str) && eof(buf) &&
((position(buf) - beginofline(buf) + # size of current line
offset + sizeof(str) - 1) < width(terminal(s)))
# Avoid full update when appending characters to the end
# and an update of curs_row isn't necessary (conservatively estimated)
write(terminal(s), str)
else
if '\n' in str
refresh_line(s)
else
after = options(s).auto_refresh_time_delay
termbuf = terminal(s)
w = width(termbuf)
delayup = !eof(buf) || old_wait
offset = s.ias.curs_row == 1 || s.indent < 0 ?
sizeof(prompt_string(s.p.prompt)::String) : s.indent
offset += position(buf) - beginofline(buf) # size of current line
if offset + textwidth(str) <= w
# Avoid full update when appending characters to the end
# and an update of curs_row isn't necessary (conservatively estimated)
write(termbuf, str)
elseif after == 0
refresh_line(s)
delayup = false
else
delayup = true
end
if delayup
write(termbuf, spin_seq[mod1(position(buf) - w, length(spin_seq))])
cmove_left(termbuf)
s.refresh_wait = Timer(after) do t
s.refresh_wait === t || return
s.refresh_wait = nothing
refresh_line(s)
end
end
end
nothing
end
const spin_seq = ("⋯", "⋱", "⋮", "⋰")

function edit_insert(buf::IOBuffer, c::StringLike)
if eof(buf)
Expand Down Expand Up @@ -804,6 +848,7 @@ function edit_insert_newline(s::PromptState, align::Int = 0 - options(s).auto_in
if ! options(s).auto_indent_bracketed_paste
s.last_newline = time()
end
nothing
end

# align: delete up to 4 spaces to align to a multiple of 4 chars
Expand Down Expand Up @@ -2420,7 +2465,7 @@ run_interface(::Prompt) = nothing

init_state(terminal, prompt::Prompt) =
PromptState(terminal, prompt, IOBuffer(), :off, IOBuffer[], 1, InputAreaState(1, 1),
#=indent(spaces)=# -1, Threads.SpinLock(), 0.0, -Inf)
#=indent(spaces)=# -1, Threads.SpinLock(), 0.0, -Inf, nothing)

function init_state(terminal, m::ModalInterface)
s = MIState(m, m.modes[1], false, IdDict{Any,Any}())
Expand Down
5 changes: 4 additions & 1 deletion stdlib/REPL/src/options.jl
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ mutable struct Options
auto_indent_bracketed_paste::Bool # set to true if terminal knows paste mode
# cancel auto-indent when next character is entered within this time frame :
auto_indent_time_threshold::Float64
# refresh after time delay
auto_refresh_time_delay::Float64
# default IOContext settings at the REPL
iocontext::Dict{Symbol,Any}
end
Expand All @@ -44,14 +46,15 @@ Options(;
auto_indent_tmp_off = false,
auto_indent_bracketed_paste = false,
auto_indent_time_threshold = 0.005,
auto_refresh_time_delay = 0.05,
iocontext = Dict{Symbol,Any}()) =
Options(hascolor, extra_keymap, tabwidth,
kill_ring_max, region_animation_duration,
beep_duration, beep_blink, beep_maxduration,
beep_colors, beep_use_current,
backspace_align, backspace_adjust, confirm_exit,
auto_indent, auto_indent_tmp_off, auto_indent_bracketed_paste,
auto_indent_time_threshold,
auto_indent_time_threshold, auto_refresh_time_delay,
iocontext)

# for use by REPLs not having an options field
Expand Down