Skip to content
Closed
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
34 changes: 26 additions & 8 deletions doc/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -496,15 +496,33 @@ function Documenter.Writers.HTMLWriter.expand_versions(dir::String, v::Versions)
cd(() -> filter!(!islink, available_folders), dir)
filter!(x -> occursin(Base.VERSION_REGEX, x), available_folders)

# Look for docs for an "active" release candidate and insert it
# Look for docs for an "active" release candidate or beta and insert it
# We want to allow at most one prerelease automatically, specifically the "best" one
# for the minor version immediately preceding the current master/dev version.
vnums = [VersionNumber(x) for x in available_folders]
master_version = maximum(vnums)
filter!(x -> x.major == 1 && x.minor == master_version.minor-1, vnums)
rc = maximum(vnums)
if !isempty(rc.prerelease) && occursin(r"^rc", rc.prerelease[1])
src = "v$(rc)"
@assert src ∈ available_folders
push!(v.versions, src => src, pop!(v.versions))
if !isempty(vnums)
master_version = maximum(vnums)
# Select candidates for the version immediately preceding the master/dev version
# e.g. If master is 1.14-dev, we look for 1.13 prereleases
filter!(x -> x.major == 1 && x.minor == master_version.minor - 1, vnums)
if !isempty(vnums)
rc = maximum(vnums)
# Check if it's a prerelease (alpha/beta/rc).
# We select the highest one (rc > beta > alpha) due to maximum().
# Note: If a stable release (v1.13.0) exists, maximum() selects it,
# and !isempty(prerelease) fails, correctly preventing duplicate entries.
if !isempty(rc.prerelease)
src = "v$(rc)"
# Ensure validation and thread-safety basics (don't pop empty)
if src in available_folders && !isempty(v.versions)
# Inject the prerelease version before the dev version (assumed to be the last item)
# This guarantees the order: Stable ... Prerelease Dev
dev = pop!(v.versions)
push!(v.versions, src => src)
push!(v.versions, dev)
end
end
end
end

return Documenter.Writers.HTMLWriter.expand_versions(dir, v.versions)
Expand Down
10 changes: 10 additions & 0 deletions stdlib/REPL/src/REPL.jl
Original file line number Diff line number Diff line change
Expand Up @@ -977,6 +977,11 @@ function history_prev(s::LineEdit.MIState, hist::REPLHistoryProvider,
LineEdit.reset_key_repeats(s) do
LineEdit.move_line_end(s)
end
# Normalize key repeat state so the next keystroke resets properly.
# History navigation bypasses the normal key dispatch path, so we must
# explicitly normalize the state to prevent stale key_repeats from
# affecting subsequent keypresses (e.g., Ctrl-A after Ctrl-Up).
LineEdit.update_key_repeats(s, Char[])
return LineEdit.refresh_line(s)
elseif m === :skip
return history_prev(s, hist, num+1, save_idx)
Expand All @@ -1003,6 +1008,11 @@ function history_next(s::LineEdit.MIState, hist::REPLHistoryProvider,
m = history_move(s, hist, cur_idx+num, save_idx)
if m === :ok
LineEdit.move_input_end(s)
# Normalize key repeat state so the next keystroke resets properly.
# History navigation bypasses the normal key dispatch path, so we must
# explicitly normalize the state to prevent stale key_repeats from
# affecting subsequent keypresses (e.g., Ctrl-A after Ctrl-Up).
LineEdit.update_key_repeats(s, Char[])
return LineEdit.refresh_line(s)
elseif m === :skip
return history_next(s, hist, num+1, save_idx)
Expand Down
13 changes: 13 additions & 0 deletions stdlib/REPL/test/repl.jl
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,19 @@ for prompt = ["TestΠ", () -> randstring(rand(1:10))]
@test LineEdit.input_string(ps) == "wip"
@test position(LineEdit.buffer(s)) == 3
LineEdit.accept_result(s, prefix_mode)
# Regression test for Ctrl-A behavior after multiline history recall (#60779)
# When history navigation (e.g., Ctrl-Up) is used, key_repeats state must be
# normalized so that subsequent keypresses (e.g., Ctrl-A) behave correctly.
LineEdit.edit_insert(s, "test line 1\ntest line 2\ntest line 3")
seek(LineEdit.buffer(s), endof(LineEdit.buffer(s)))
# Navigate history (which bypasses update_key_repeats)
LineEdit.history_prev(s, hp)
# Cursor should be at line end after history navigation
@test position(LineEdit.buffer(s)) == endof(LineEdit.buffer(s))
# Press Ctrl-A to move to line start - should move to the start of current line,
# not jump to input start (which would happen if key_repeats was incorrectly > 0)
LineEdit.move_line_start(s)
@test position(LineEdit.buffer(s)) == 0
end
end

Expand Down