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

Run OhMyREPL keybindings in a fixed world age #321

Merged
merged 1 commit into from
Nov 19, 2024
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
1 change: 0 additions & 1 deletion src/BracketInserter.jl
Original file line number Diff line number Diff line change
Expand Up @@ -166,5 +166,4 @@ function insert_into_keymap!(D::Dict)
end
end

insert_into_keymap!(OhMyREPL.Prompt.NEW_KEYBINDINGS)
end # module
57 changes: 34 additions & 23 deletions src/OhMyREPL.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,26 @@ export colorscheme!, colorschemes, enable_autocomplete_brackets, enable_highligh

const SUPPORTS_256_COLORS = !(Sys.iswindows() && VERSION < v"1.5.3")

# Wrap the function `f` so that it's always invoked in the given `world_age`
function fix_world_age(f, world_age)
if world_age == typemax(UInt)
function (args...; kws...)
Base.invokelatest(f, args...; kws...)
end
else
function (args...; kws...)
Base.invoke_in_world(world_age, f, args...; kws...)
end
end
end

include("repl_pass.jl")
include("repl.jl")
include("passes/Passes.jl")

include("BracketInserter.jl")
include("prompt.jl")
include("hooks.jl")

import .BracketInserter.enable_autocomplete_brackets

Expand Down Expand Up @@ -91,50 +105,47 @@ const ENABLE_FZF = Ref(true)
enable_fzf(v::Bool) = ENABLE_FZF[] = v

using Pkg
function reinsert_after_pkg()
repl = Base.active_repl
function reinsert_after_pkg(repl, world_age)
mirepl = isdefined(repl,:mi) ? repl.mi : repl
main_mode = mirepl.interface.modes[1]
m = first(methods(main_mode.keymap_dict[']']))
if m.module == Pkg.REPLMode
Prompt.insert_keybindings()
Prompt.insert_keybindings(repl, world_age)
end
end

function setup_repl(repl, world_age)
if !isdefined(repl, :interface)
repl.interface = REPL.setup_interface(repl)
end
Prompt.insert_keybindings(repl, world_age)
@async begin
sleep(0.25)
reinsert_after_pkg(repl, world_age)
end
update_interface(repl.interface)

global _refresh_line_hook = fix_world_age(_refresh_line, world_age)
end

function __init__()
options = Base.JLOptions()
world_age = Base.get_world_counter()
# command-line
if (options.isinteractive != 1) && options.commands != C_NULL
return
end

if isdefined(Base, :active_repl)
if !isdefined(Base.active_repl, :interface)
Base.active_repl.interface = REPL.setup_interface(Base.active_repl)
end
Prompt.insert_keybindings()
@async begin
sleep(0.25)
reinsert_after_pkg()
end
setup_repl(Base.active_repl, world_age)
else
atreplinit() do repl
if !isdefined(repl, :interface)
repl.interface = REPL.setup_interface(repl)
end
Prompt.insert_keybindings()
@async begin
sleep(0.25)
reinsert_after_pkg()
end
update_interface(repl.interface)
setup_repl(Base.active_repl, world_age)
end
end

if ccall(:jl_generating_output, Cint, ()) == 0
include(joinpath(@__DIR__, "refresh_lines.jl"))
include(joinpath(@__DIR__, "output_prompt_overwrite.jl"))
include(joinpath(@__DIR__, "MarkdownHighlighter.jl"))
activate_hooks()
end
end

Expand Down
55 changes: 49 additions & 6 deletions src/MarkdownHighlighter.jl → src/hooks.jl
Original file line number Diff line number Diff line change
@@ -1,13 +1,41 @@

import REPL
import REPL.LineEdit
using Crayons
import Markdown

import .OhMyREPL.Passes.SyntaxHighlighter.SYNTAX_HIGHLIGHTER_SETTINGS
import .OhMyREPL.HIGHLIGHT_MARKDOWN
function _refresh_line(s::REPL.LineEdit.BufferLike)
LineEdit.refresh_multi_line(s)
OhMyREPL.Prompt.rewrite_with_ANSI(s)
end

function _REPL_display(d::REPL.REPLDisplay, mime::MIME"text/plain", @nospecialize(x))
x = Ref{Any}(x)
REPL.with_repl_linfo(d.repl) do io
if isdefined(REPL, :active_module)
mod = REPL.active_module(d)::Module
else
mod = Main
end
io = IOContext(io, :limit => true, :module => mod)
if OUTPUT_PROMPT !== nothing
output_prompt = OUTPUT_PROMPT isa String ? OUTPUT_PROMPT : OUTPUT_PROMPT()
write(io, OUTPUT_PROMPT_PREFIX)
write(io, output_prompt, "\e[0m")
end
get(io, :color, false) && write(io, REPL.answer_color(d.repl))
if isdefined(d.repl, :options) && isdefined(d.repl.options, :iocontext)
# this can override the :limit property set initially
io = foldl(IOContext, d.repl.options.iocontext, init=io)
end
show(io, mime, x[])
println(io)
end
return nothing
end

split_lines(s::AbstractString) = isdefined(Markdown, :lines) ? Markdown.lines(s) : split(s, '\n')

function Markdown.term(io::IO, md::Markdown.Code, columns)
function _Markdown_term(io::IO, md::Markdown.Code, columns)
code = md.code
# Want to remove potential.
lang = md.language == "" ? "" : first(split(md.language))
Expand Down Expand Up @@ -37,11 +65,11 @@ function Markdown.term(io::IO, md::Markdown.Code, columns)
push!(outputs, "")
end

if do_syntax && HIGHLIGHT_MARKDOWN[]
if do_syntax && OhMyREPL.HIGHLIGHT_MARKDOWN[]
for (i, (sourcecode, output)) in enumerate(zip(sourcecodes, outputs))
tokens = collect(tokenize(sourcecode))
crayons = fill(Crayon(), length(tokens))
SYNTAX_HIGHLIGHTER_SETTINGS(crayons, tokens, 0, sourcecode)
OhMyREPL.Passes.SyntaxHighlighter.SYNTAX_HIGHLIGHTER_SETTINGS(crayons, tokens, 0, sourcecode)
buff = IOBuffer()
if lang == "jldoctest" || lang == "julia-repl"
print(buff, Crayon(foreground = :red, bold = true), "julia> ", Crayon(reset = true))
Expand Down Expand Up @@ -72,3 +100,18 @@ function Markdown.term(io::IO, md::Markdown.Code, columns)
end
end
end

_refresh_line_hook = _refresh_line

function activate_hooks()
@eval begin
LineEdit.refresh_line(s::REPL.LineEdit.BufferLike) =
_refresh_line_hook(s)
Markdown.term(io::IO, md::Markdown.Code, columns) =
_Markdown_term(io, md, columns)
end
if !isdefined(REPL, :IPython)
@eval REPL.display(d::REPL.REPLDisplay, mime::MIME"text/plain", x) =
_REPL_display(d, mime, x)
end
end
28 changes: 0 additions & 28 deletions src/output_prompt_overwrite.jl

This file was deleted.

5 changes: 5 additions & 0 deletions src/precompile.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,8 @@ precompile(Tuple{OhMyREPL.Passes.SyntaxHighlighter.SyntaxHighlighterSettings, Ar
precompile(Tuple{OhMyREPL.Passes.BracketHighlighter.BracketHighlighterSettings, Array{Crayons.Crayon, 1}, Array{JuliaSyntax.Token, 1}, Int64, String})
precompile(Tuple{OhMyREPL.Passes.RainbowBrackets.RainbowBracketsSettings, Array{Crayons.Crayon, 1}, Array{JuliaSyntax.Token, 1}, Int64, String})
precompile(Tuple{typeof(OhMyREPL.untokenize_with_ANSI), Base.IOContext{Base.GenericIOBuffer{Array{UInt8, 1}}}, OhMyREPL.PassHandler, Array{JuliaSyntax.Token, 1}, String, Int64})
precompile(_refresh_line, (REPL.LineEdit.ModeState,))
precompile(_refresh_line, (REPL.LineEdit.MIState,))
precompile(_refresh_line, (REPL.LineEdit.IOBuffer,))
precompile(_REPL_display, (REPL.REPLDisplay, MIME"text/plain", String))
precompile(_Markdown_term, (IO, Markdown.Code, Int))
6 changes: 0 additions & 6 deletions src/refresh_lines.jl

This file was deleted.

37 changes: 20 additions & 17 deletions src/repl.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import REPL.Terminals: raw!, width, height, cmove, getX, TerminalBuffer,
getY, clear_line, beep, disable_bracketed_paste, enable_bracketed_paste

using OhMyREPL
import OhMyREPL: untokenize_with_ANSI, apply_passes!, PASS_HANDLER
import OhMyREPL: untokenize_with_ANSI, apply_passes!, PASS_HANDLER, fix_world_age

if VERSION > v"1.3"
import JLFzf
Expand Down Expand Up @@ -89,8 +89,7 @@ function rewrite_with_ANSI(s, cursormove::Bool = false)
end
end


function create_keybindings()
function create_keybindings(prefix_hist_prompt, world_age)
D = Dict{Any, Any}()
D['\b'] = (s, data, c) -> if LineEdit.edit_backspace(s, true)
rewrite_with_ANSI(s)
Expand Down Expand Up @@ -289,29 +288,33 @@ function create_keybindings()
LineEdit.enter_search(s, p, true)
end
end
return D

# Up Arrow
D["\e[A"] = (s,o...)-> begin
LineEdit.edit_move_up(buffer(s)) || LineEdit.enter_prefix_search(s, prefix_hist_prompt, true)
Prompt.rewrite_with_ANSI(s)
end
# Down Arrow
D["\e[B"] = (s,o...)-> begin
LineEdit.edit_move_down(buffer(s)) || LineEdit.enter_prefix_search(s, prefix_hist_prompt, false)
Prompt.rewrite_with_ANSI(s)
end

OhMyREPL.BracketInserter.insert_into_keymap!(D)

return Dict(k=>fix_world_age(f, world_age) for (k,f) in D)
end
NEW_KEYBINDINGS = create_keybindings()

function insert_keybindings(repl = Base.active_repl)
function insert_keybindings(repl, world_age)
mirepl = (isdefined(repl,:mistate) && !isnothing(repl.mistate)) ? repl.mistate : repl
interface_modes = mirepl.interface.modes
main_mode = interface_modes[1]
php_idx = findfirst(Base.Fix2(isa, LineEdit.PrefixHistoryPrompt), interface_modes)
p = interface_modes[php_idx]

# Up Arrow
NEW_KEYBINDINGS["\e[A"] = (s,o...)-> begin
LineEdit.edit_move_up(buffer(s)) || LineEdit.enter_prefix_search(s, p, true)
Prompt.rewrite_with_ANSI(s)
end
# Down Arrow
NEW_KEYBINDINGS["\e[B"] = (s,o...)-> begin
LineEdit.edit_move_down(buffer(s)) || LineEdit.enter_prefix_search(s, p, false)
Prompt.rewrite_with_ANSI(s)
end
keybinds = create_keybindings(p, world_age)

main_mode.keymap_dict = LineEdit.keymap(Dict{Any, Any}[NEW_KEYBINDINGS, main_mode.keymap_dict])
main_mode.keymap_dict = LineEdit.keymap(Dict{Any, Any}[keybinds, main_mode.keymap_dict])
end

function _commit_line(s, data, c)
Expand Down
Loading