-
-
Notifications
You must be signed in to change notification settings - Fork 269
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
[RFC] Make command spec more declarative #509
[RFC] Make command spec more declarative #509
Conversation
Codecov Report
@@ Coverage Diff @@
## master #509 +/- ##
==========================================
+ Coverage 90.67% 91.31% +0.63%
==========================================
Files 18 18
Lines 2896 2948 +52
==========================================
+ Hits 2626 2692 +66
+ Misses 270 256 -14
Continue to review full report at Codecov.
|
Yeah, I think this is a good idea and something I have thought about every time I add a new REPL command :). |
Ok, great! |
src/REPLMode.jl
Outdated
,("patch", :cmd, :switch) | ||
,("fixed", :cmd, :switch) | ||
,("coverage", :cmd, :switch) | ||
,("name", :cmd, :switch) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leading commas like this are anti-idiomatic in Julia; Julia allows a comma after the last element, so just end every line with a comma. Note that vectors can also have no commas at all and just use newlines, but you have to be consistent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. I'll go with the trailing commas. (Also, I didn't know about the no commas for vectors. Pretty cool!)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's technically a different syntax: with commas it's a vector construction syntax, without commas it's a vertical concatenation syntax, but in this case the result is the same. If the elements are themselves vectors or matrices, the result can be different, e.g.:
julia> [[1, 2],
[3, 4, 5],
[6, 7]]
3-element Array{Array{Int64,1},1}:
[1, 2]
[3, 4, 5]
[6, 7]
julia> [[1, 2]
[3, 4, 5]
[6, 7]]
7-element Array{Int64,1}:
1
2
3
4
5
6
7
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see the difference now: no commas will end up calling vcat
. Thanks for explaining
Sorry, for lack of comments. This looks good but we need to test if it introduces any significant changes to time for first call (e.g. Likely need to regenerate some of the precompile statements as well but that's on me. |
Ok, I think I can test that |
I ran some basic tests like this:
I think this should test the right thing as the changes for this PR don't take effect until you hit I profiled manually 5 times, then took the average:
Not the most thorough tests, but I find them reassuring (given that they are testing the right thing...). |
I haven't looked at the implementation here, but how would "double" commands like |
I wonder if |
Excellent point! The closest thing right now would be to use options:
That's the current design though, I hadn't considered explicit support for subcommands. Extending support for them should be easy; it will be my next TODO. What I have in mind is declaring each subcommand:
The parser will check for a super command and a sub command, with "package" being the implicit super command. |
Let's merge this to prevent more merge conflicts and then I can work on fixing up the precompilation if needed. |
Thanks for adding the |
@fredrikekre welcome! |
API.gc(ctx) | ||
function do_cmd!(command::PkgCommand, repl) | ||
meta_opts = APIOptions(command.meta_options, meta_option_specs) | ||
ctx = Context(meta_opts...) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this will fail sometimes if there is no active project? Thats why the call to do_activate!
was called before creating the context before this PR. See #517 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this still true @KristofferC ? If so, does the help command not work either? It is called after Context()
both before and after this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean when Base.ACTIVE_PROJECT[] == nothing
? How would I test that failure case? Maybe:
Base.ACTIVE_PROJECT[] = nothing
Pkg.REPLMode.pkg"activate"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is the call to EnvCache that hits
Line 237 in e1627a6
project_file == nothing && error("no active project") |
Can be reproduced with:
julia> using Pkg
julia> empty!(LOAD_PATH)
0-element Array{String,1}
julia> Base.ACTIVE_PROJECT[] = nothing
julia> Base.HOME_PROJECT[] = nothing
julia> Pkg.Types.EnvCache()
ERROR: no active project
Stacktrace:
[1] error(::String) at ./error.jl:33
[2] find_project_file(::Nothing) at /home/fredrik/.julia/dev/Pkg/src/Types.jl:237
[3] Pkg.Types.EnvCache(::Nothing) at /home/fredrik/.julia/dev/Pkg/src/Types.jl:279 (repeats 2 times)
[4] top-level scope at none:0
julia> pkg"activate"
ERROR: no active project
Stacktrace:
[1] error(::String) at ./error.jl:33
[2] find_project_file(::Nothing) at /home/fredrik/.julia/dev/Pkg/src/Types.jl:237
[3] Pkg.Types.EnvCache(::Nothing) at /home/fredrik/.julia/dev/Pkg/src/Types.jl:279 (repeats 2 times)
[4] Pkg.Types.Context() at ./none:0
[5] do_cmd!(::Pkg.REPLMode.PkgCommand, ::Pkg.REPLMode.MiniREPL) at /home/fredrik/.julia/dev/Pkg/src/REPLMode.jl:523
[6] #do_cmd#32(::Bool, ::Function, ::Pkg.REPLMode.MiniREPL, ::String) at /home/fredrik/.julia/dev/Pkg/src/REPLMode.jl:507
[7] (::getfield(Pkg.REPLMode, Symbol("#kw##do_cmd")))(::NamedTuple{(:do_rethrow,),Tuple{Bool}}, ::typeof(Pkg.REPLMode.do_cmd), ::Pkg.REPLMode.MiniREPL, ::String) at ./none:0
[8] top-level scope at none:0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And the help command fails too (which it also did before this PR).
julia> pkg"help"
ERROR: no active project
Stacktrace:
[1] error(::String) at ./error.jl:33
[2] find_project_file(::Nothing) at /home/fredrik/.julia/dev/Pkg/src/Types.jl:237
[3] Pkg.Types.EnvCache(::Nothing) at /home/fredrik/.julia/dev/Pkg/src/Types.jl:279 (repeats 2 times)
[4] Pkg.Types.Context() at ./none:0
[5] do_cmd!(::Pkg.REPLMode.PkgCommand, ::Pkg.REPLMode.MiniREPL) at /home/fredrik/.julia/dev/Pkg/src/REPLMode.jl:523
[6] #do_cmd#32(::Bool, ::Function, ::Pkg.REPLMode.MiniREPL, ::String) at /home/fredrik/.julia/dev/Pkg/src/REPLMode.jl:507
[7] (::getfield(Pkg.REPLMode, Symbol("#kw##do_cmd")))(::NamedTuple{(:do_rethrow,),Tuple{Bool}}, ::typeof(Pkg.REPLMode.do_cmd), ::Pkg.REPLMode.MiniREPL, ::String) at ./none:0
[8] top-level scope at none:0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea that is probably better. Things like registry add
won't need the Context
either.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, nice catch btw!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to clarify; you mean that the do_[]!
functions create the Context
then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When we finally hit the API, I think we will end up passing collect(ctx)
or Context!(collect(ctx))
depending on the primary way we want users to use the API (I'm not sure which would be better yet).
* Refactor `REPLMode.parse_quotes`
Still a WIP, but I'd be interested if anyone thinks this is a worthwhile change?
My end goal would be a more declarative specification of commands (e.g. specify a list of valid flags for a command , specify the number of expected arguments, ... and have the parser check those declarative constraints).
It will certainly be 'heavier' than the current code but it should be insignificant for interactive input sizes.