diff --git a/deps/checksums/StyledStrings-c49ae82f2b176556944929ade88a4fecf1556ccb.tar.gz/md5 b/deps/checksums/StyledStrings-c49ae82f2b176556944929ade88a4fecf1556ccb.tar.gz/md5 new file mode 100644 index 0000000000000..9fe7ea9c5e80d --- /dev/null +++ b/deps/checksums/StyledStrings-c49ae82f2b176556944929ade88a4fecf1556ccb.tar.gz/md5 @@ -0,0 +1 @@ +f4e49cee0253a6d00f1d057cad2d373a diff --git a/deps/checksums/StyledStrings-c49ae82f2b176556944929ade88a4fecf1556ccb.tar.gz/sha512 b/deps/checksums/StyledStrings-c49ae82f2b176556944929ade88a4fecf1556ccb.tar.gz/sha512 new file mode 100644 index 0000000000000..01fc4ad19fe7c --- /dev/null +++ b/deps/checksums/StyledStrings-c49ae82f2b176556944929ade88a4fecf1556ccb.tar.gz/sha512 @@ -0,0 +1 @@ +487c8c9f0138710165e207dc198376417b312a4f5d91a8616c5093938a2b314afd2a4fb72ea687a9cdc7ddfac246dde793a5c2e60ce465851f7c83194ae6f7d8 diff --git a/doc/Manifest.toml b/doc/Manifest.toml index c0f8b693bd1ac..d8aaaa9992847 100644 --- a/doc/Manifest.toml +++ b/doc/Manifest.toml @@ -260,6 +260,9 @@ deps = ["ArgTools", "SHA"] uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" version = "1.10.0" +[[deps.StyledStrings]] +uuid = "f489334b-da3d-4c2e-b8f0-e476e12c162b" + [[deps.Test]] deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/pkgimage.mk b/pkgimage.mk index 78b2618be549f..da8d7b4becce4 100644 --- a/pkgimage.mk +++ b/pkgimage.mk @@ -35,3 +35,4 @@ $(BUILDDIR)/stdlib/debug.image: $(build_private_libdir)/sys-debug.$(SHLIB_EXT) clean: rm -rf $(JULIA_DEPOT_PATH)/compiled rm -f $(BUILDDIR)/stdlib/*.image + \ No newline at end of file diff --git a/stdlib/REPL/src/LineEdit.jl b/stdlib/REPL/src/LineEdit.jl index e881a65ca6b1c..8ffc08f7e8499 100644 --- a/stdlib/REPL/src/LineEdit.jl +++ b/stdlib/REPL/src/LineEdit.jl @@ -5,10 +5,13 @@ module LineEdit import ..REPL using ..REPL: AbstractREPL, Options +import StyledStrings: Face, loadface!, @styled_str + using ..Terminals import ..Terminals: raw!, width, height, clear_line, beep -import Base: ensureroom, show, AnyDict, position +import Base: ensureroom, show, AnyDict, position, + AnnotatedString, annotations using Base: something using InteractiveUtils: InteractiveUtils @@ -42,15 +45,9 @@ end mutable struct Prompt <: TextInterface # A string or function to be printed as the prompt. - prompt::Union{String,Function} - # A string or function to be printed before the prompt. May not change the length of the prompt. - # This may be used for changing the color, issuing other terminal escape codes, etc. - prompt_prefix::Union{String,Function} - # Same as prefix except after the prompt - prompt_suffix::Union{String,Function} - output_prefix::Union{String,Function} - output_prefix_prefix::Union{String,Function} - output_prefix_suffix::Union{String,Function} + prompt::Union{AnnotatedString{String},String,Function} + # used for things like IPython mode + output_prefix::Union{AnnotatedString{String},String,Function} keymap_dict::Dict{Char,Any} repl::Union{AbstractREPL,Nothing} complete::CompletionProvider @@ -190,36 +187,31 @@ complete_line(c::CompletionProvider, s, ::Module; hint::Bool=false) = complete_l terminal(s::IO) = s terminal(s::PromptState) = s.terminal - function beep(s::PromptState, duration::Real=options(s).beep_duration, - blink::Real=options(s).beep_blink, - maxduration::Real=options(s).beep_maxduration; - colors=options(s).beep_colors, + blink::Real=options(s).beep_blink, + maxduration::Real=options(s).beep_maxduration; + beep_face=options(s).beep_face, use_current::Bool=options(s).beep_use_current) isinteractive() || return # some tests fail on some platforms s.beeping = min(s.beeping + duration, maxduration) - let colors = Base.copymutable(colors) - errormonitor(@async begin - trylock(s.refresh_lock) || return - try - orig_prefix = s.p.prompt_prefix - use_current && push!(colors, prompt_string(orig_prefix)) - i = 0 - while s.beeping > 0.0 - prefix = colors[mod1(i+=1, end)] - s.p.prompt_prefix = prefix - refresh_multi_line(s, beeping=true) - sleep(blink) - s.beeping -= blink - end - s.p.prompt_prefix = orig_prefix - refresh_multi_line(s, beeping=true) - s.beeping = 0.0 - finally - unlock(s.refresh_lock) + errormonitor(@async begin + trylock(s.refresh_lock) || return + try + og_prompt = s.p.prompt + beep_prompt = styled"{$beep_face:$(prompt_string(og_prompt))}" + s.p.prompt = beep_prompt + refresh_multi_line(s, beeping=true) + while s.beeping > 0.0 + sleep(blink) + s.beeping -= blink end - end) - end + s.p.prompt = og_prompt + refresh_multi_line(s, beeping=true) + s.beeping = 0.0 + finally + unlock(s.refresh_lock) + end + end) nothing end @@ -530,7 +522,7 @@ function refresh_multi_line(termbuf::TerminalBuffer, terminal::UnixTerminal, buf regstart, regstop = region(buf) written = 0 # Write out the prompt string - lindent = write_prompt(termbuf, prompt, hascolor(terminal))::Int + lindent = write_prompt(termbuf, prompt)::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 @@ -628,11 +620,10 @@ function highlight_region(lwrite::Union{String,SubString{String}}, regstart::Int end function refresh_multi_line(terminal::UnixTerminal, args...; kwargs...) - outbuf = IOBuffer() - termbuf = TerminalBuffer(outbuf) + termbuf = TerminalBuffer(terminal) ret = refresh_multi_line(termbuf, terminal, args...;kwargs...) # Output the entire refresh at once - write(terminal, take!(outbuf)) + write(terminal, take!(termbuf)) flush(terminal) return ret end @@ -918,7 +909,7 @@ function edit_insert(s::PromptState, c::StringLike) termbuf = terminal(s) w = width(termbuf) offset = s.ias.curs_row == 1 || s.indent < 0 ? - sizeof(prompt_string(s.p.prompt)::String) : s.indent + sizeof(prompt_string(s.p.prompt)::Union{String,AnnotatedString}) : s.indent offset += position(buf) - beginofline(buf) # size of current line spinner = '\0' delayup = !eof(buf) || old_wait @@ -1582,27 +1573,21 @@ refresh_line(s::BufferLike, termbuf::AbstractTerminal) = refresh_multi_line(term default_completion_cb(::IOBuffer) = [] default_enter_cb(_) = true -write_prompt(terminal::AbstractTerminal, s::PromptState, color::Bool) = write_prompt(terminal, s.p, color) -function write_prompt(terminal::AbstractTerminal, p::Prompt, color::Bool) - prefix = prompt_string(p.prompt_prefix) - suffix = prompt_string(p.prompt_suffix) - write(terminal, prefix) - color && write(terminal, Base.text_colors[:bold]) - width = write_prompt(terminal, p.prompt, color) - color && write(terminal, Base.text_colors[:normal]) - write(terminal, suffix) - return width -end - -function write_output_prefix(io::IO, p::Prompt, color::Bool) - prefix = prompt_string(p.output_prefix_prefix) - suffix = prompt_string(p.output_prefix_suffix) - print(io, prefix) - color && write(io, Base.text_colors[:bold]) - width = write_prompt(io, p.output_prefix, color) - color && write(io, Base.text_colors[:normal]) - print(io, suffix) - return width +write_prompt(terminal::AbstractTerminal, s::PromptState) = write_prompt(terminal, s.p) + +# returns the width of the written prompt +function write_prompt(io::IO, p::Union{AbstractString,Function,Prompt}) + @static Sys.iswindows() && _reset_console_mode() + promptstr = prompt_string(p)::AbstractString + write(io, promptstr) + return textwidth(promptstr) +end + +function write_output_prefix(io::IO, p::Prompt) + @static Sys.iswindows() && _reset_console_mode() + promptstr = prompt_string(p.output_prefix)::String + write(io, promptstr) + return textwidth(promptstr) end # On Windows, when launching external processes, we cannot control what assumption they make on the @@ -1635,13 +1620,6 @@ function _reset_console_mode() end end -# returns the width of the written prompt -function write_prompt(terminal::Union{IO, AbstractTerminal}, s::Union{AbstractString,Function}, color::Bool) - @static Sys.iswindows() && _reset_console_mode() - promptstr = prompt_string(s)::String - write(terminal, promptstr) - return textwidth(promptstr) -end ### Keymap Support @@ -2108,7 +2086,7 @@ end input_string(s::PrefixSearchState) = String(take!(copy(s.response_buffer))) -write_prompt(terminal, s::PrefixSearchState, color::Bool) = write_prompt(terminal, s.histprompt.parent_prompt, color) +write_prompt(terminal, s::PrefixSearchState) = write_prompt(terminal, s.histprompt.parent_prompt) prompt_string(s::PrefixSearchState) = prompt_string(s.histprompt.parent_prompt.prompt) terminal(s::PrefixSearchState) = s.terminal @@ -2682,7 +2660,7 @@ end activate(m::ModalInterface, s::MIState, termbuf::AbstractTerminal, term::TextTerminal) = activate(mode(s), s, termbuf, term) -commit_changes(t::UnixTerminal, termbuf::TerminalBuffer) = (write(t, take!(termbuf.out_stream)); nothing) +commit_changes(t::UnixTerminal, termbuf::TerminalBuffer) = (write(t, take!(termbuf)); nothing) function transition(f::Function, s::MIState, newmode::Union{TextInterface,Symbol}) cancel_beep(s) @@ -2697,8 +2675,8 @@ function transition(f::Function, s::MIState, newmode::Union{TextInterface,Symbol if !haskey(s.mode_state, newmode) s.mode_state[newmode] = init_state(terminal(s), newmode) end - termbuf = TerminalBuffer(IOBuffer()) t = terminal(s) + termbuf = TerminalBuffer(t) s.mode_state[mode(s)] = deactivate(mode(s), state(s), termbuf, t) s.current_mode = newmode f() @@ -2730,11 +2708,7 @@ const default_keymap_dict = keymap([default_keymap, escape_defaults]) function Prompt(prompt ; - prompt_prefix = "", - prompt_suffix = "", output_prefix = "", - output_prefix_prefix = "", - output_prefix_suffix = "", keymap_dict = default_keymap_dict, repl = nothing, complete = EmptyCompletionProvider(), @@ -2743,8 +2717,8 @@ function Prompt(prompt hist = EmptyHistoryProvider(), sticky = false) - return Prompt(prompt, prompt_prefix, prompt_suffix, output_prefix, output_prefix_prefix, output_prefix_suffix, - keymap_dict, repl, complete, on_enter, on_done, hist, sticky) + return Prompt(prompt, output_prefix, keymap_dict, repl, complete, on_enter, + on_done, hist, sticky) end run_interface(::Prompt) = nothing diff --git a/stdlib/REPL/src/REPL.jl b/stdlib/REPL/src/REPL.jl index ac791327e2d75..f3d3f8670717c 100644 --- a/stdlib/REPL/src/REPL.jl +++ b/stdlib/REPL/src/REPL.jl @@ -111,7 +111,8 @@ import Base: display, show, AnyDict, - == + ==, + AnnotatedString _displaysize(io::IO) = displaysize(io)::Tuple{Int,Int} @@ -154,10 +155,10 @@ include("Pkg_beforeload.jl") answer_color(::AbstractREPL) = "" -const JULIA_PROMPT = "julia> " -const PKG_PROMPT = "pkg> " -const SHELL_PROMPT = "shell> " -const HELP_PROMPT = "help?> " +const JULIA_PROMPT = styled"{repl_prompt_julia:julia> }" +const PKG_PROMPT = styled"{repl_prompt_pkg:pkg> }" +const SHELL_PROMPT = styled"{repl_prompt_shell:shell> }" +const HELP_PROMPT = styled"{repl_prompt_help:help?> }" mutable struct REPLBackend "channel for AST" @@ -556,7 +557,7 @@ function display(d::REPLDisplay, mime::MIME"text/plain", x) mistate = d.repl.mistate mode = LineEdit.mode(mistate) if mode isa LineEdit.Prompt - LineEdit.write_output_prefix(io, mode, get(io, :color, false)::Bool) + LineEdit.write_output_prefix(io, mode) end end get(io, :color, false)::Bool && write(io, answer_color(d.repl)) @@ -761,12 +762,6 @@ end mutable struct LineEditREPL <: AbstractREPL t::TextTerminal hascolor::Bool - prompt_color::String - input_color::String - answer_color::String - shell_color::String - help_color::String - pkg_color::String history_file::Bool in_shell::Bool in_help::Bool @@ -779,13 +774,12 @@ mutable struct LineEditREPL <: AbstractREPL interface::ModalInterface backendref::REPLBackendRef frontend_task::Task - function LineEditREPL(t,hascolor,prompt_color,input_color,answer_color,shell_color,help_color,pkg_color,history_file,in_shell,in_help,envcolors) + function LineEditREPL(t,hascolor,history_file,in_shell,in_help,envcolors) opts = Options() opts.hascolor = hascolor - if !hascolor - opts.beep_colors = [""] - end - new(t,hascolor,prompt_color,input_color,answer_color,shell_color,help_color,pkg_color,history_file,in_shell, + new(t,hascolor,history_file,in_shell,in_help,envcolors,false,nothing, opts, nothing, Tuple{String,Int}[]) + # updated invocation from master: + # new(t,hascolor,prompt_color,input_color,answer_color,shell_color,help_color,pkg_color,history_file,in_shell, in_help,envcolors,false,nothing, opts, nothing, Tuple{String,Int}[]) end end @@ -796,15 +790,8 @@ terminal(r::LineEditREPL) = r.t hascolor(r::LineEditREPL) = r.hascolor LineEditREPL(t::TextTerminal, hascolor::Bool, envcolors::Bool=false) = - LineEditREPL(t, hascolor, - hascolor ? Base.text_colors[:green] : "", - hascolor ? Base.input_color() : "", - hascolor ? Base.answer_color() : "", - hascolor ? Base.text_colors[:red] : "", - hascolor ? Base.text_colors[:yellow] : "", - hascolor ? Base.text_colors[:blue] : "", - false, false, false, envcolors - ) + LineEditREPL(t, hascolor, false, false, false, envcolors) + # TODO caleb-allen 10/21/2024 validate this call post-rebase mutable struct REPLCompletionProvider <: CompletionProvider modifiers::LineEdit.Modifiers @@ -1253,11 +1240,11 @@ repl_filename(repl, hp) = "REPL" const JL_PROMPT_PASTE = Ref(true) enable_promptpaste(v::Bool) = JL_PROMPT_PASTE[] = v -function contextual_prompt(repl::LineEditREPL, prompt::Union{String,Function}) +function contextual_prompt(repl::LineEditREPL, prompt::Union{AnnotatedString,Function}) function () mod = Base.active_module(repl) prefix = mod == Main ? "" : string('(', mod, ") ") - pr = prompt isa String ? prompt : prompt() + pr = prompt isa AnnotatedString ? prompt : prompt() prefix * pr end end @@ -1308,19 +1295,12 @@ function setup_interface( # Set up the main Julia prompt julia_prompt = Prompt(contextual_prompt(repl, JULIA_PROMPT); - # Copy colors from the prompt object - prompt_prefix = hascolor ? repl.prompt_color : "", - prompt_suffix = hascolor ? - (repl.envcolors ? Base.input_color : repl.input_color) : "", repl = repl, complete = replc, on_enter = return_callback) # Setup help mode help_mode = Prompt(contextual_prompt(repl, HELP_PROMPT), - prompt_prefix = hascolor ? repl.help_color : "", - prompt_suffix = hascolor ? - (repl.envcolors ? Base.input_color : repl.input_color) : "", repl = repl, complete = replc, # When we're done transform the entered line into a call to helpmode function @@ -1330,9 +1310,6 @@ function setup_interface( # Set up shell mode shell_mode = Prompt(SHELL_PROMPT; - prompt_prefix = hascolor ? repl.shell_color : "", - prompt_suffix = hascolor ? - (repl.envcolors ? Base.input_color : repl.input_color) : "", repl = repl, complete = ShellCompletionProvider(), # Transform "foo bar baz" into `foo bar baz` (shell quoting) @@ -1829,19 +1806,9 @@ function run_frontend(repl::StreamREPL, backend::REPLBackendRef) dopushdisplay = !in(d,Base.Multimedia.displays) dopushdisplay && pushdisplay(d) while !eof(repl.stream)::Bool - if have_color - print(repl.stream,repl.prompt_color) - end - print(repl.stream, JULIA_PROMPT) - if have_color - print(repl.stream, input_color(repl)) - end line = readline(repl.stream, keep=true) if !isempty(line) ast = Base.parse_input_line(line) - if have_color - print(repl.stream, Base.color_normal) - end response = eval_with_backend(ast, backend) print_response(repl, response, !ends_with_semicolon(line), have_color) end diff --git a/stdlib/REPL/src/Terminals.jl b/stdlib/REPL/src/Terminals.jl index 0cf6888d248e8..8fb568db0024e 100644 --- a/stdlib/REPL/src/Terminals.jl +++ b/stdlib/REPL/src/Terminals.jl @@ -100,8 +100,13 @@ pipe_writer(t::UnixTerminal) = t.out_stream::IO @nospecialize mutable struct TerminalBuffer <: UnixTerminal out_stream::IO + buf::IOBuffer end +TerminalBuffer(terminal::TextTerminal) = TerminalBuffer(terminal, IOBuffer()) + +Base.take!(termbuf::TerminalBuffer) = take!(termbuf.buf) + mutable struct TTYTerminal <: UnixTerminal term_type::String in_stream::IO @@ -160,4 +165,11 @@ Base.get(t::TTYTerminal, key, default) = get(pipe_writer(t), key, default) Base.peek(t::TTYTerminal, ::Type{T}) where {T} = peek(t.in_stream, T)::T +Base.in(key_value::Pair, t::TerminalBuffer) = in(key_value, t.out_stream) +Base.haskey(t::TerminalBuffer, key) = haskey(t.out_stream, key) +Base.getindex(t::TerminalBuffer, key) = getindex(t.out_stream, key) +Base.get(t::TerminalBuffer, key, default) = get(t.out_stream, key, default) + +Base.peek(t::TerminalBuffer, ::Type{T}) where {T} = error("Not implemented") + end # module diff --git a/stdlib/REPL/src/options.jl b/stdlib/REPL/src/options.jl index 1fb2c654c7df2..73a8c511ca01d 100644 --- a/stdlib/REPL/src/options.jl +++ b/stdlib/REPL/src/options.jl @@ -15,7 +15,7 @@ mutable struct Options beep_duration::Float64 beep_blink::Float64 beep_maxduration::Float64 - beep_colors::Vector{String} + beep_face::Symbol beep_use_current::Bool backspace_align::Bool backspace_adjust::Bool @@ -39,7 +39,7 @@ Options(; kill_ring_max = 100, region_animation_duration = 0.2, beep_duration = 0.2, beep_blink = 0.2, beep_maxduration = 1.0, - beep_colors = ["\e[90m"], # gray (text_colors not yet available) + beep_face = :repl_prompt_beep, beep_use_current = true, backspace_align = true, backspace_adjust = backspace_align, confirm_exit = false, @@ -53,7 +53,7 @@ Options(; Options(hascolor, extra_keymap, tabwidth, kill_ring_max, region_animation_duration, beep_duration, beep_blink, beep_maxduration, - beep_colors, beep_use_current, + beep_face, beep_use_current, backspace_align, backspace_adjust, confirm_exit, auto_indent, auto_indent_tmp_off, auto_indent_bracketed_paste, auto_indent_time_threshold, auto_refresh_time_delay, diff --git a/stdlib/REPL/src/precompile.jl b/stdlib/REPL/src/precompile.jl index f7961a205e0b1..11cc4e7bda7fc 100644 --- a/stdlib/REPL/src/precompile.jl +++ b/stdlib/REPL/src/precompile.jl @@ -76,11 +76,12 @@ function repl_workload() cd("complete_path\t\t$CTRL_C println("done") """ + + JULIA_PROMPT = styled"{repl_prompt_julia:julia> }" + PKG_PROMPT = styled"{repl_prompt_pkg:pkg> }" + SHELL_PROMPT = styled"{repl_prompt_shell:shell> }" + HELP_PROMPT = styled"{repl_prompt_help:help?> }" - JULIA_PROMPT = "julia> " - PKG_PROMPT = "pkg> " - SHELL_PROMPT = "shell> " - HELP_PROMPT = "help?> " blackhole = Sys.isunix() ? "/dev/null" : "nul"