Skip to content

Commit

Permalink
Allow single option with REPL.TerminalMenus (#36369)
Browse files Browse the repository at this point in the history
  • Loading branch information
tomyun authored Jun 22, 2020
1 parent f6d34c3 commit 76a2e36
Show file tree
Hide file tree
Showing 9 changed files with 48 additions and 33 deletions.
1 change: 1 addition & 0 deletions stdlib/REPL/docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,7 @@ Aside from the overall `charset` option, for `RadioMenu` the configurable option
- `cursor::Char='>'|'→'`: character to use for cursor
- `up_arrow::Char='^'|'↑'`: character to use for up arrow
- `down_arrow::Char='v'|'↓'`: character to use for down arrow
- `updown_arrow::Char='I'|'↕'`: character to use for up/down arrow in one-line page
- `scroll_wrap::Bool=false`: optionally wrap-around at the beginning/end of a menu
- `ctrl_c_interrupt::Bool=true`: If `false`, return empty on ^C, if `true` throw InterruptException() on ^C

Expand Down
31 changes: 20 additions & 11 deletions stdlib/REPL/src/TerminalMenus/AbstractMenu.jl
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,8 @@ end
function move_down!(m::AbstractMenu, cursor::Int, lastoption::Int=numoptions(m))
if cursor < lastoption
cursor += 1 # move selection down
if m.pagesize + m.pageoffset <= cursor < lastoption
pagepos = m.pagesize + m.pageoffset
if pagepos <= cursor && pagepos < lastoption
m.pageoffset += 1 # scroll page down
end
elseif scroll_wrap(m)
Expand Down Expand Up @@ -315,17 +316,23 @@ function printmenu(out, m::AbstractMenu, cursoridx::Int; oldstate=nothing, init:
# clearline
print(buf, "\x1b[2K")

if i == firstline && m.pageoffset > 0
print_arrow(buf, m, up_arrow(m))
elseif i == lastline && i != lastoption
print_arrow(buf, m, down_arrow(m))
upscrollable = i == firstline && m.pageoffset > 0
downscrollable = i == lastline && i != lastoption

if upscrollable && downscrollable
print(buf, updown_arrow(m))
elseif upscrollable
print(buf, up_arrow(m))
elseif downscrollable
print(buf, down_arrow(m))
else
printcursor(buf, m, i == cursoridx)
print(buf, ' ')
end

printcursor(buf, m, i == cursoridx)
writeline(buf, m, i, i == cursoridx)

i != lastline && print(buf, "\r\n")
(firstline == lastline || i != lastline) && print(buf, "\r\n")
end

newstate = lastline-firstline # final line doesn't have `\n`
Expand Down Expand Up @@ -362,10 +369,12 @@ down_arrow(c::AbstractConfig) = down_arrow(c.config)
down_arrow(c::Config) = c.down_arrow
down_arrow(::AbstractMenu) = CONFIG[:down_arrow]

print_arrow(buf, ::ConfiguredMenu, c::Char) = print(buf, c, " ")
print_arrow(buf, ::AbstractMenu, c::Char) = print(buf, c)
updown_arrow(m::ConfiguredMenu) = updown_arrow(m.config)
updown_arrow(c::AbstractConfig) = updown_arrow(c.config)
updown_arrow(c::Config) = c.updown_arrow
updown_arrow(::AbstractMenu) = CONFIG[:updown_arrow]

printcursor(buf, m::ConfiguredMenu, iscursor::Bool) = print(buf, ' ', iscursor ? cursor(m.config) : ' ', ' ')
printcursor(buf, m::ConfiguredMenu, iscursor::Bool) = print(buf, iscursor ? cursor(m.config) : ' ', ' ')
cursor(c::AbstractConfig) = cursor(c.config)
cursor(c::Config) = c.cursor
printcursor(buf, ::AbstractMenu, ::Bool) = print(buf, ' ') # `writeLine` is expected to do the printing (get from CONFIG[:cursor])
printcursor(buf, ::AbstractMenu, ::Bool) = nothing # `writeLine` is expected to do the printing (get from CONFIG[:cursor])
4 changes: 2 additions & 2 deletions stdlib/REPL/src/TerminalMenus/MultiSelectMenu.jl
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,14 @@ were selected by the user.
Any additional keyword arguments will be passed to [`TerminalMenus.MultiSelectConfig`](@ref).
"""
function MultiSelectMenu(options::Array{String,1}; pagesize::Int=10, selected=Int[], warn::Bool=true, kwargs...)
length(options) < 2 && error("MultiSelectMenu must have at least two options")
length(options) < 1 && error("MultiSelectMenu must have at least one option")

# if pagesize is -1, use automatic paging
pagesize = pagesize == -1 ? length(options) : pagesize
# pagesize shouldn't be bigger than options
pagesize = min(length(options), pagesize)
# after other checks, pagesize must be greater than 2
pagesize < 2 && error("pagesize must be >= 2")
pagesize < 1 && error("pagesize must be >= 1")

pageoffset = 0
_selected = Set{Int}()
Expand Down
6 changes: 3 additions & 3 deletions stdlib/REPL/src/TerminalMenus/RadioMenu.jl
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,14 @@ user.
Any additional keyword arguments will be passed to [`TerminalMenus.Config`](@ref).
"""
function RadioMenu(options::Array{String,1}; pagesize::Int=10, warn::Bool=true, kwargs...)
length(options) < 2 && error("RadioMenu must have at least two options")
length(options) < 1 && error("RadioMenu must have at least one option")

# if pagesize is -1, use automatic paging
pagesize = pagesize == -1 ? length(options) : pagesize
# pagesize shouldn't be bigger than options
pagesize = min(length(options), pagesize)
# after other checks, pagesize must be greater than 2
pagesize < 2 && error("pagesize must be >= 2")
# after other checks, pagesize must be greater than 1
pagesize < 1 && error("pagesize must be >= 1")

pageoffset = 0
selected = -1 # none
Expand Down
11 changes: 10 additions & 1 deletion stdlib/REPL/src/TerminalMenus/config.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ struct Config <: AbstractConfig
cursor::Char
up_arrow::Char
down_arrow::Char
updown_arrow::Char
scroll_wrap::Bool
ctrl_c_interrupt::Bool
end
Expand Down Expand Up @@ -46,6 +47,7 @@ function Config(;
cursor::Char = '\0',
up_arrow::Char = '\0',
down_arrow::Char = '\0',
updown_arrow::Char = '\0',
scroll_wrap::Bool = false,
ctrl_c_interrupt::Bool = true)
charset === :ascii || charset === :unicode ||
Expand All @@ -59,7 +61,10 @@ function Config(;
if down_arrow == '\0'
down_arrow = charset === :ascii ? 'v' : ''
end
return Config(cursor, up_arrow, down_arrow, scroll_wrap, ctrl_c_interrupt)
if updown_arrow == '\0'
updown_arrow = charset === :ascii ? 'I' : ''
end
return Config(cursor, up_arrow, down_arrow, updown_arrow, scroll_wrap, ctrl_c_interrupt)
end

"""
Expand Down Expand Up @@ -133,6 +138,7 @@ function config(;charset::Symbol = :na,
cursor::Char = '\0',
up_arrow::Char = '\0',
down_arrow::Char = '\0',
updown_arrow::Char = '\0',
checked::String = "",
unchecked::String = "",
supress_output::Union{Nothing, Bool}=nothing, # typo was documented, unfortunately
Expand All @@ -142,12 +148,14 @@ function config(;charset::Symbol = :na,
cursor = '>'
up_arrow = '^'
down_arrow = 'v'
updown_arrow = 'I'
checked = "[X]"
unchecked = "[ ]"
elseif charset === :unicode
cursor = ''
up_arrow = ''
down_arrow = ''
updown_arrow = ''
checked = ""
unchecked = ""
elseif charset === :na
Expand All @@ -162,6 +170,7 @@ function config(;charset::Symbol = :na,
cursor != '\0' && (CONFIG[:cursor] = cursor)
up_arrow != '\0' && (CONFIG[:up_arrow] = up_arrow)
down_arrow != '\0' && (CONFIG[:down_arrow] = down_arrow)
updown_arrow != '\0' && (CONFIG[:updown_arrow] = updown_arrow)
checked != "" && (CONFIG[:checked] = checked)
unchecked != "" && (CONFIG[:unchecked] = unchecked)
supress_output isa Bool && (CONFIG[:supress_output] = supress_output)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@
# Check to make sure types are imported properly
@test MultiSelectMenu <: TerminalMenus.AbstractMenu

# Invalid Menu Params
@test_throws ErrorException MultiSelectMenu(["one"], warn=false)
@test_throws ErrorException MultiSelectMenu(["one", "two", "three"], pagesize=1, warn=false)

# Constructor
@test MultiSelectMenu(["one", "two", "three"], warn=false).pagesize == 3
@test MultiSelectMenu(string.(1:30), pagesize=-1, warn=false).pagesize == 30
Expand Down Expand Up @@ -37,3 +33,5 @@ TerminalMenus.writeLine(buf, multi_menu, 1, true)
# Test SDTIN
multi_menu = MultiSelectMenu(string.(1:10), warn=false)
@test simulate_input(Set([1,2]), multi_menu, :enter, :down, :enter, 'd')
multi_menu = MultiSelectMenu(["single option"], warn=false)
@test simulate_input(Set([1]), multi_menu, :up, :up, :down, :enter, 'd')
8 changes: 4 additions & 4 deletions stdlib/REPL/test/TerminalMenus/legacytests/old_radio_menu.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@
# Check to make sure types are imported properly
@test RadioMenu <: TerminalMenus.AbstractMenu

# Invalid Menu Params
@test_throws ErrorException RadioMenu(["one"], warn=false)
@test_throws ErrorException RadioMenu(["one", "two", "three"], pagesize=1, warn=false)

# Constructor
@test RadioMenu(["one", "two", "three"], warn=false).pagesize == 3
@test RadioMenu(string.(1:30), pagesize=-1, warn=false).pagesize == 30
Expand Down Expand Up @@ -40,3 +36,7 @@ TerminalMenus.writeLine(buf, radio_menu, 1, true)
# Test using stdin
radio_menu = RadioMenu(string.(1:10), warn=false)
@test simulate_input(3, radio_menu, :down, :down, :enter)
radio_menu = RadioMenu(["single option"], warn=false)
@test simulate_input(1, radio_menu, :up, :up, :down, :up, :enter)
radio_menu = RadioMenu(string.(1:3), pagesize=1, warn=false)
@test simulate_input(3, radio_menu, :down, :down, :down, :down, :enter)
6 changes: 2 additions & 4 deletions stdlib/REPL/test/TerminalMenus/multiselect_menu.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@
# Check to make sure types are imported properly
@test MultiSelectMenu{TerminalMenus.MultiSelectConfig} <: TerminalMenus.ConfiguredMenu # TODO Julia 2.0: delete parameter

# Invalid Menu Params
@test_throws ErrorException MultiSelectMenu(["one"], charset=:ascii)
@test_throws ErrorException MultiSelectMenu(["one", "two", "three"], pagesize=1, charset=:ascii)

# Constructor
@test MultiSelectMenu(["one", "two", "three"], charset=:ascii).pagesize == 3
@test MultiSelectMenu(string.(1:30), pagesize=-1, charset=:ascii).pagesize == 30
Expand Down Expand Up @@ -57,3 +53,5 @@ end
# Test SDTIN
multi_menu = MultiSelectMenu(string.(1:10), charset=:ascii)
@test simulate_input(Set([1,2]), multi_menu, :enter, :down, :enter, 'd')
multi_menu = MultiSelectMenu(["single option"], charset=:ascii)
@test simulate_input(Set([1]), multi_menu, :up, :up, :down, :enter, 'd')
8 changes: 4 additions & 4 deletions stdlib/REPL/test/TerminalMenus/radio_menu.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@
# Check to make sure types are imported properly
@test RadioMenu{TerminalMenus.Config} <: TerminalMenus.ConfiguredMenu # TODO Julia 2.0: delete parameter

# Invalid Menu Params
@test_throws ErrorException RadioMenu(["one"]; charset=:ascii)
@test_throws ErrorException RadioMenu(["one", "two", "three"], pagesize=1, charset=:ascii)

# Constructor
@test RadioMenu(["one", "two", "three"]; charset=:ascii).pagesize == 3
@test RadioMenu(string.(1:30), pagesize=-1, charset=:ascii).pagesize == 30
Expand Down Expand Up @@ -42,3 +38,7 @@ end
# Test using stdin
radio_menu = RadioMenu(string.(1:10); charset=:ascii)
@test simulate_input(3, radio_menu, :down, :down, :enter)
radio_menu = RadioMenu(["single option"], charset=:ascii)
@test simulate_input(1, radio_menu, :up, :up, :down, :up, :enter)
radio_menu = RadioMenu(string.(1:3), pagesize=1, charset=:ascii)
@test simulate_input(3, radio_menu, :down, :down, :down, :down, :enter)

1 comment on commit 76a2e36

@nanosoldier
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Executing the daily package evaluation, I will reply here when finished:

@nanosoldier runtests(ALL, isdaily = true)

Please sign in to comment.