@@ -97,6 +97,7 @@ mutable struct PromptState <: ModeState
9797 p:: Prompt
9898 input_buffer:: IOBuffer
9999 region_active:: Symbol # :shift or :mark or :off
100+ hint:: Union{String,Nothing}
100101 undo_buffers:: Vector{IOBuffer}
101102 undo_idx:: Int
102103 ias:: InputAreaState
@@ -361,7 +362,7 @@ function show_completions(s::PromptState, completions::Vector{String})
361362 end
362363end
363364
364- # Prompt Completions
365+ # Prompt Completions & Hints
365366function complete_line (s:: MIState )
366367 set_action! (s, :complete_line )
367368 if complete_line (state (s), s. key_repeats, s. active_module)
@@ -372,6 +373,36 @@ function complete_line(s::MIState)
372373 end
373374end
374375
376+ function check_for_hint (s:: MIState )
377+ st = state (s)
378+ options (st). hint_tab_completes || return false
379+ completions, partial, should_complete = complete_line (st. p. complete, st, s. active_module):: Tuple{Vector{String},String,Bool}
380+ if should_complete
381+ if length (completions) == 1
382+ hint = only (completions)[sizeof (partial)+ 1 : end ]
383+ if ! isempty (hint) # completion on a complete name returns itself so check that there's something to hint
384+ st. hint = hint
385+ return true
386+ end
387+ elseif length (completions) > 1
388+ p = common_prefix (completions)
389+ if p in completions # i.e. complete `@time` even though `@time_imports` etc. exists
390+ hint = p[sizeof (partial)+ 1 : end ]
391+ if ! isempty (hint)
392+ st. hint = hint
393+ return true
394+ end
395+ end
396+ end
397+ end
398+ if ! isnothing (st. hint)
399+ st. hint = " " # don't set to nothing here. That will be done in `maybe_show_hint`
400+ return true
401+ else
402+ return false
403+ end
404+ end
405+
375406function complete_line (s:: PromptState , repeats:: Int , mod:: Module )
376407 completions, partial, should_complete = complete_line (s. p. complete, s, mod):: Tuple{Vector{String},String,Bool}
377408 isempty (completions) && return false
@@ -432,12 +463,29 @@ prompt_string(p::Prompt) = prompt_string(p.prompt)
432463prompt_string (s:: AbstractString ) = s
433464prompt_string (f:: Function ) = Base. invokelatest (f)
434465
466+ function maybe_show_hint (s:: PromptState )
467+ isa (s. hint, String) || return nothing
468+ # The hint being "" then nothing is used to first clear a previous hint, then skip printing the hint
469+ # the clear line cannot be printed each time because it breaks column movement
470+ if isempty (s. hint)
471+ print (terminal (s), " \e [0K" ) # clear remainder of line which had a hint
472+ s. hint = nothing
473+ else
474+ Base. printstyled (terminal (s), s. hint, color= :light_black )
475+ cmove_left (terminal (s), textwidth (s. hint))
476+ s. hint = " " # being "" signals to do one clear line remainder to clear the hint next time if still empty
477+ end
478+ return nothing
479+ end
480+
435481function refresh_multi_line (s:: PromptState ; kw... )
436482 if s. refresh_wait != = nothing
437483 close (s. refresh_wait)
438484 s. refresh_wait = nothing
439485 end
440- refresh_multi_line (terminal (s), s; kw... )
486+ r = refresh_multi_line (terminal (s), s; kw... )
487+ maybe_show_hint (s)
488+ return r
441489end
442490refresh_multi_line (s:: ModeState ; kw... ) = refresh_multi_line (terminal (s), s; kw... )
443491refresh_multi_line (termbuf:: TerminalBuffer , s:: ModeState ; kw... ) = refresh_multi_line (termbuf, terminal (s), s; kw... )
@@ -2424,8 +2472,8 @@ AnyDict(
24242472 " \e\n " => " \e\r " ,
24252473 " ^_" => (s:: MIState ,o... )-> edit_undo! (s),
24262474 " \e _" => (s:: MIState ,o... )-> edit_redo! (s),
2427- # Simply insert it into the buffer by default
2428- " *" => (s:: MIState ,data,c:: StringLike )-> (edit_insert (s, c)),
2475+ # Show hints at what tab complete would do by default
2476+ " *" => (s:: MIState ,data,c:: StringLike )-> (edit_insert (s, c); check_for_hint (s) && refresh_line (s) ),
24292477 " ^U" => (s:: MIState ,o... )-> edit_kill_line_backwards (s),
24302478 " ^K" => (s:: MIState ,o... )-> edit_kill_line_forwards (s),
24312479 " ^Y" => (s:: MIState ,o... )-> edit_yank (s),
@@ -2634,7 +2682,7 @@ end
26342682run_interface (:: Prompt ) = nothing
26352683
26362684init_state (terminal, prompt:: Prompt ) =
2637- PromptState (terminal, prompt, IOBuffer (), :off , IOBuffer[], 1 , InputAreaState (1 , 1 ),
2685+ PromptState (terminal, prompt, IOBuffer (), :off , nothing , IOBuffer[], 1 , InputAreaState (1 , 1 ),
26382686 #= indent(spaces)=# - 1 , Threads. SpinLock (), 0.0 , - Inf , nothing )
26392687
26402688function init_state (terminal, m:: ModalInterface )
0 commit comments