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

allow a function instead of a string as Prompt.prompt #22809

Merged
merged 5 commits into from
Jul 27, 2017
Merged

Conversation

rfourquet
Copy link
Member

@rfourquet rfourquet commented Jul 14, 2017

I had this as an old branch, but since I know now of a way to change the repl from ".juliarc.jl", I'm more motivated to merge it. This allows to have a dynamic string for the prompt. On a daily basis, I would have for example this function called from ".juliarc.jl":

function histprompt()
    for i = 1:3
        hist = Base.active_repl.interface.modes[i].hist
        prompt = ["julia", "shell", "help?"][i]
        Base.active_repl.interface.modes[i].prompt = () -> begin
            if hist.cur_idx != length(hist.history)+1
                string(prompt, " [", hist.cur_idx-hist.start_idx, "/",
                       length(hist.history) + 1 - hist.start_idx, "]> ")
            else
                "$prompt [$(hist.cur_idx - hist.start_idx)]> "
            end
        end
    end
end

Then a sample julia session:

julia [1]> f(x) = 1
f (generic function with 1 method)

julia [1/2]> f(x::Int) = 2 # here I came backward in history to edit the previous definition, hence "1/2"
f (generic function with 2 methods)

julia [3]> @which f(0) # I can now make sense of the "REPL[2]" reference!
f(x::Int64) in Main at REPL[2]:1

julia [3/4]> @which f(0.0)
f(x) in Main at REPL[1]:1

PS: I'm really not very familiar with REPL code, so I may have got something wrong.

@rfourquet rfourquet added the REPL Julia's REPL (Read Eval Print Loop) label Jul 14, 2017
prompt_string(s::AbstractString) = s
prompt_string(f::Function) = eval(Expr(:call, f))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why isn't this f() ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

World errors I think.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

invokelatest then?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I had world errors, so I did as in #19924. I'd rather keep it as is to be consistent with other such evals in this file.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the evals were added here before invokelatest was implemented, that should be the canonical way of doing this now

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok done

@tkelman
Copy link
Contributor

tkelman commented Jul 14, 2017

Looks like there are a couple of tests in test/repl.jl for changing the prompt?

@rfourquet
Copy link
Member Author

OK, will see if I can add some tests.

@rfourquet
Copy link
Member Author

I would like to merge this soon (if no objection of course), as this shouldn't be breaking and seems harmless.

@tkelman
Copy link
Contributor

tkelman commented Jul 17, 2017

freebsd test freeze might be related? @iblis17 can you reproduce locally?

@iblislin
Copy link
Member

I'm running testing locally; will be back after 8 hrs...

@iblislin
Copy link
Member

@tkelman The gmake test also freeze on my local bsd desktop, I just observe this from top. Test workers are alive, but do not consume any CPU resource. (will investigate it later ... 💤

@tkelman
Copy link
Contributor

tkelman commented Jul 18, 2017

@ararslan might also be able to take a look?

@ararslan
Copy link
Member

Checking out this branch, building, then running

JULIA_CPU_CORES=2 JULIA_TEST_MAXRSS=600 ./julia test/runtests.jl all

I get all tests passing with no freezes. Laptop natively running FreeBSD 11.0-RELEASE-p11.

@iblislin
Copy link
Member

Seems freezing occurs randomly. I ran 3 additional gmake testall. 2 passed vs 1 froze.

8 core on my machine, and the latest output message in each frozen run is cmdlineargs always.

channels (3)              |   14.01  |  1.10  |  7.8 | 347.42     |  0.81
misc (6)                  |   48.05  |  2.33  |  4.8 | 1514.21    |  0.67
libgit2 (7)               |   67.62  |  0.71  |  1.1 | 452.90     |  1.21
ranges (4)                |   92.71  |  4.86  |  5.2 | 7165.24    |  0.71
examples (9)              |   27.80  |  0.38  |  1.4 | 614.00     |  0.80
distributed (8)           |  113.42  |  0.02  |  0.0 | 20.62      |  0.56
cmdlineargs (2)           |  142.23  |  0.31  |  0.2 | 71.36      |  0.55
^C
signal (2): Interrupt
while loading /usr/home/iblis/git/julia/test/runtests.jl, in expression starting on line 29
__sys_kevent at /lib/libc.so.7 (unknown line)
__thr_kevent at /usr/src/lib/libthr/thread/thr_syscalls.c:382
uv__io_poll at /usr/home/iblis/git/julia/deps/srccache/libuv-52d72a52cc7ccd570929990f010ed16e2ec604c8/
src/unix/kqueue.c:160
uv_run at /usr/home/iblis/git/julia/deps/srccache/libuv-52d72a52cc7ccd570929990f010ed16e2ec604c8/src/u
nix/core.c:354
process_events at ./libuv.jl:82 [inlined]
wait at ./event.jl:216
wait at ./event.jl:27
jlcall_wait_19639 at /usr/home/iblis/git/julia/usr/lib/julia/sys.so (unknown line)
wait at ./task.jl:181
jlcall_wait_19633 at /usr/home/iblis/git/julia/usr/lib/julia/sys.so (unknown line)
sync_end at ./task.jl:274
macro expansion at ./task.jl:303 [inlined]
#40 at /usr/home/iblis/git/julia/test/runtests.jl:49
cd at ./file.jl:70
unknown function (ip: 0x80229ac73)
do_call at /usr/home/iblis/git/julia/src/interpreter.c:66
eval at /usr/home/iblis/git/julia/src/interpreter.c:246
eval_body at /usr/home/iblis/git/julia/src/interpreter.c:544
jl_interpret_toplevel_thunk at /usr/home/iblis/git/julia/src/interpreter.c:697
jl_toplevel_eval_flex at /usr/home/iblis/git/julia/src/toplevel.c:597
jl_parse_eval_all at /usr/home/iblis/git/julia/src/ast.c:908
jl_load at /usr/home/iblis/git/julia/src/toplevel.c:620 [inlined]
jl_load_ at /usr/home/iblis/git/julia/src/toplevel.c:627
include_from_node1 at ./loading.jl:556
jlcall_include_from_node1_18748 at /usr/home/iblis/git/julia/usr/lib/julia/sys.so (unknown line)
include at ./sysimg.jl:14
jlcall_include_18691 at /usr/home/iblis/git/julia/usr/lib/julia/sys.so (unknown line)
process_options at ./client.jl:315
_start at ./client.jl:383
jlcall__start_18926 at /usr/home/iblis/git/julia/usr/lib/julia/sys.so (unknown line)
jl_stderr_obj at /usr/home/iblis/git/julia/usr/bin/julia (unknown line)
jl_stderr_obj at /usr/home/iblis/git/julia/usr/bin/julia (unknown line)
jl_stderr_obj at /usr/home/iblis/git/julia/usr/bin/julia (unknown line)
unknown function (ip: 0x800624fff)
unknown function (ip: 0xffffffffffffffff)
Allocations: 2349656 (Pool: 2348919; Big: 737); GC: 5
WARNING: ErrorException
atexit hook threw an error: ErrorException("schedule: Task not runnable")gmake[1]: *** [Makefile:     18: all] Error 130

Second frozen run:

...
WARNING: OutOfMemoryError
atexit hook threw an error: OutOfMemoryError()gmake[1]: *** [Makefile:18: all] Error 130
gmake: *** [Makefile:562: testall] Interrupt

@yuyichao
Copy link
Contributor

No it's not cmdlineargs, it finishes, it's whatever haven't run.

@iblislin
Copy link
Member

No it's not cmdlineargs, it finishes, it's whatever haven't run.

Yes, cmdlineargs finishes. It's the latest output message before freezing.

Any suspicious tests? I can try to repeated run them...

@ararslan
Copy link
Member

You can compare the list of things that passed to the list of tests in test/choosetests.jl and see what didn't get executed.

@iblislin
Copy link
Member

iblislin commented Jul 19, 2017

ok, I found a way to reproduce the freezing:

./julia test/runtests.jl repl examples
Test (Worker) | Time (s) | GC (s) | GC % | Alloc (MB) | RSS (MB)                                              
        From worker 2:  ERROR (unhandled task failure): write: broken pipe (EPIPE)
        From worker 2:  Stacktrace:                                                                           
        From worker 2:   [1] try_yieldto at ./event.jl:189 [inlined]
        From worker 2:   [2] wait() at ./event.jl:234                                                         
        From worker 2:   [3] uv_write(::Base.PipeEndpoint, ::Ptr{UInt8}, ::UInt64) at ./stream.jl:811
        From worker 2:   [4] unsafe_write(::Base.PipeEndpoint, ::Ptr{UInt8}, ::UInt64) at ./stream.jl:832
        From worker 2:   [5] write(::Base.PipeEndpoint, ::String) at ./strings/string.jl:71
        From worker 2:   [6] enable_bracketed_paste(::TestHelpers.FakeTerminal) at ./repl/Terminals.jl:142
        From worker 2:   [7] prompt!(::TestHelpers.FakeTerminal, ::Base.LineEdit.ModalInterface, ::Base.LineEdit.MIState) at ./repl/LineEdit.jl:1608
        From worker 2:   [8] run_interface(::TestHelpers.FakeTerminal, ::Base.LineEdit.ModalInterface) at ./repl/LineEdit.jl:1580
        From worker 2:   [9] (::Test75Main_repl.##25#29)() at ./task.jl:335
examples (3)  |   23.83  |  0.23  |  1.0 | 625.27     |  0.19

(This command works fine on master build

--

Edit: reformatting the error message

@rfourquet
Copy link
Member Author

@iblis17 thanks so much, I will investigate.

@rfourquet
Copy link
Member Author

I removed the test which was seeming to cause the broken pipe error; to be honest, I don't really understand why the error (if I unroll manually the for-loop in this test, it seems to work, but it's also a kind of heisenbug I think), but I didn't really understand what the test was testing either (just wanted to check that it works with a function); but it was not caused by having a function instead of a string for prompt (AFAICT), but rather by being repeated twice in a raw. Thanks for your time all and sorry for the confusion.

@rfourquet
Copy link
Member Author

I will merge in a couple of days if no objection.

@rfourquet rfourquet merged commit 85a2555 into master Jul 27, 2017
@rfourquet rfourquet deleted the rf/prompt-funct branch July 27, 2017 16:17
rfourquet added a commit that referenced this pull request Aug 9, 2017
Since #22809 a function can be used as the prompt, but the indentation
of non-prompt lines was still determined by the first value of the prompt
(usually "julia> "). Now, the indentation by is determined by the currently
printed prompt, which can vary from one keypress to the next.
rfourquet added a commit that referenced this pull request Aug 9, 2017
Since #22809 a function can be used as the prompt, but the indentation
of non-prompt lines was still determined by the first value of the prompt
(usually "julia> "). Now, the indentation is determined by the currently
printed prompt, which can vary from one keypress to the next.
rfourquet added a commit that referenced this pull request Aug 11, 2017
Since #22809 a function can be used as the prompt, but the indentation
of non-prompt lines was still determined by the first value of the prompt
(usually "julia> "). Now, the indentation is determined by the currently
printed prompt, which can vary from one keypress to the next.
@cormullion
Copy link
Contributor

Cool! Is it documented how to use it?

@rfourquet
Copy link
Member Author

Is it documented how to use it?

Not yet, I plan to document more some REPL changes by the next release, but some things are still in flux... basically you can just do what you wrote in #20692, except you replace the string by a thunk returning a string, e.g. Base.active_repl.interface.modes[1].prompt=()->"$(Dates.format(now(), "HH:MM:SS"))> ". To have this set from .juliarc.jl, the current "best" way is to use atreplinit, e.g.

atreplinit() do repl
    repl.interface = REPL.setup_interface(repl)
    repl.interface.modes[1].prompt = ()->"$(Dates.format(now(), "HH:MM:SS"))> "
end

This is definitely too user-unfriendly to have to call setup_interface first, hopefully someone (me?) will simplify this soon. Note that this is more dynamic than e.g. setting the prompt in a shell, i.e. it will be updated possibly after each keystroke (currenlty, except when inserting at the end of the input).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
REPL Julia's REPL (Read Eval Print Loop)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants