Export from REPL history to julia script?

Is it possible to save the REPL history as a valid julia script?

Something like:

> a = 3
3
> b = 5
5
> a + b 
8
> REPL.save("myscript.jl")

myscript.jl:

# REPL history export
# Date: 16.04.2021
a = 3
# 3
b = 5
# 5
a + b 
# 8

something like this is possible in iPython

1 Like

Isn’t the history file (.julia/logs/repl_history.jl) already a valid julia script?

2 Likes

It is, but doesn’t contain any outputs.

2 Likes

Well, if it is not doable from the default repl if OhMyRepl.jl, you can probably just use the IJulia kernel inside iPython.

Edit: yup found it in IJulia docs. ipython3 console --kernel julia-1.5

In the live stream today another option was presented.

using DoctorDocstrings
pickandcopy()

It can pick lines from the REPL history file and copies them to the clipboard.

Thank you. I was in that session and found it very informative. Do you know if there a way to make pickandcopy() create the menu with only the REPL history strings from the current Julia session?

1 Like

I think if we use the history file it is not possible at the moment, as there is no distinction between the sessions. If, however, there is a way to access the current session history somehow it should be easy.

I am not sure if there is an internal history storage/cache in the REPL somewhere.

I found Base.active_repl.interface.modes[1].hist.history, which provides the REPL history.
It is initialized with the history file, but after those entries, there is no crosstalk between sessions.

In addition, there is start_idx, which marks the first new entry.
So here is a solution that looks good to me.

"""
Get commands of the current REPL session as an array of strings
"""
function get_REPL_as_history()
          history = Base.active_repl.interface.modes[1].hist
          history.history[history.start_idx+1:end]
end
"""
Save REPL commands of this session to a file

file: Path to a file
"""
function save_REPL_history(file)
           isfile(file) && error("file already exists")
           open(file,"w") do io
                      txt = join(get_REPL_as_history(),"\n")
                      write(io,txt)
           end
end

One thing that does not work is tracking repeated commands.
So when you enter print("123") and then another print("123") the history only tracks one.

REPL example
julia> """
       Get commands of the current REPL session as an array of strings
       """
       function get_REPL_as_history()
                 history = Base.active_repl.interface.modes[1].hist
                 history.history[history.start_idx+1:end]
       end
get_REPL_as_history

julia> """
       Save REPL commands of this session to a file

       file: Path to a file
       """
       function save_REPL_history(file)
                  isfile(file) && error("file already exists")
                  open(file,"w") do io
                             txt = join(get_REPL_as_history(),"\n")
                             write(io,txt)
                  end
       end
save_REPL_history

julia> print("123")
123
julia> print("321")
321
julia> print("123")
123
julia> print("123")
123
julia> print("bye")
bye
julia> get_REPL_as_history()
8-element Vector{String}:
 "\"\"\"\nGet commands of the current" ⋯ 155 bytes ⋯ "ory[history.start_idx:end]\nend"
 "\"\"\"\nSave REPL commands of this " ⋯ 250 bytes ⋯ "ite(io,txt)\n           end\nend"
 "print(\"123\")"
 "print(\"321\")"
 "print(\"123\")"
 "print(\"bye\")"
 "get_REPL_as_history()"
julia> save_REPL_history("/tmp/record.jl")
660

2 Likes

That’s awesome. Thank you. The ‘next step’ could be to extend that ‘current Julia session’ functionality you just described (plus the ‘saving to a file’ functionality) to pickandcopy(). This would be valuable since pickandcopy() neatly keeps track of what mode one was in the REPL (julian, shell, help, package), which is useful for cleanly documenting what transpired inside a ‘demo’ coding session in the REPL.

But your answer definitely works as stated, so Thanks Again!

1 Like

The modes are also present in the history cache. I just did not use them.
There is Base.active_repl.interface.modes[1].hist.modes containing the mode for each history entry and there is Base.active_repl.interface.modes[1].hist.mode_mapping containing the different promts.

Each prompt has then a field called promt which contains the start of the line.

julia> print("123")
123

julia> hist = Base.active_repl.interface.modes[1].hist;

julia> hist.history[end-2:end]
3-element Vector{String}:
 "print(\"123\")"
 "hist = Base.active_repl.interface.modes[1].hist;"
 "hist.history[end-2:end]"

julia> hist.modes[end-3:end]
4-element Vector{Symbol}:
 :julia
 :julia
 :julia
 :julia

julia> hist.mode_mapping[hist.modes[end]]
"Prompt(\"julia> \",...)"

julia> hist.mode_mapping[hist.modes[end]].prompt
"julia> "
1 Like