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

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

It is, but doesn’t contain any outputs.

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?

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

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!

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> "

I tried it, and it worked! Thanks for the solution. :sparkles: