Case insentitive package completion

I have often found myself to know a package name, but fail to remember the casing (some packages are easy, some not as consistent). It is not hard to make a guess and try to tab complete until something works, but I feel like it would be a nice quality of life to be able to just write it in whatever casing and get it completed.

In my head it feels like it should pretty much just be to do a comparison with all items lowercased when finding matches, so just replace all comparisons between partial strings and package names with lowercased versions. Or am I missing something that can go wrong here?

Had a quick look at the code here which seems to be for pkg> add [tab] if I understand correctly, and it might just be to change the line if startswith(regpkg.name, partial) to compare with both strings lowercased?

I tried to implement this by just adding lowercase in the right place in the file of stdlib/Pkg_xxx for the xxx in the stdlib/Pkg.version, but it didn’t make a difference. After recompiling it seems to work though (at least partially, got some strange cases also). Is there any way to not have to recompile all of julia while working on stdlibs?

I also saw something about using Unicode.normalize(s, casefold=true) instead of lowercase(s) in this stackoverflow answer, not sure if that applies here since packages does not often have unicode characters?

3 Likes

See Using the development version of Pkg.jl. Note that if you want to develop the Pkg REPL mode you need using Pkg before ], since otherwise the wrong Pkg is loaded by the trigger key.

3 Likes

Adding lowercase in two spots in Pkg.jl gives me most of what I wanted, though there was still the odd behaviour I mentioned.

The thing that happens is that when I for example write pkg> add re[tab] it will change to pkg> add R where the e has disappeared.
This seems to come from LineEdit.jl in the REPL stdlib. Here the autocomplete looks for the common prefix to all possible completions and if a common prefix exists and it is not the same as the entered string it will replace the entered string. The common prefix for this case is R since both Re... as well as RE... exists (e.g. Revise and REPL) so the e is not common when case sensitive.

I tried a simple fix to avoid this (could probably be done better since common_prefix and lowercase are now run multiple times, but to show the idea)

if !isempty(p) && p != partial && length(p) == length(common_prefix(lowercase.(completions)))

and it seems to work. It just checks if the common prefix with lowercased completions is the same length, if not we have the above problem.

This still wasn’t really what I would have optimally wanted though, since for example if there only existed REPL and Repair as completions for re, then it would not help with the p even though that was a common letter. One could then instead use the common prefix from lowercase in the case where they return a common prefix of different length, but this might also be strange since it could make uppercase letters to lowercase even if all possible completions have uppercase and you wrote that (writing Re in previous example would become rep).

Continuing from that, if a user specifically writes a uppercase letter maybe that should take precedence. But that seems like a whole other mess I don’t want to touch.

If either the current version or the one with the lowercase common prefix check is interesting for others I think I prefer both of them to the current version. But since it will give some different results when writing with proper casing it will be possible that it returns different results for people who don’t want this, so maybe that could be problematic. I also realise that they might affect other things using the complete_line function which I haven’t checked very well. I think it will be fine since other things that use it such as latex completions still have their own complete_line functions that generate possible completions, so you won’t get a problem writing \Gamm[tab] and it doesn’t know if it is \gamma or \Gamma you want as long as the complete_line for latex completion only returns the uppercase possibility.

To test it out a bit I put the two affected methods in a package, if anyone want to try you simply need to add it and run using on it. It seems to work for a few cases I tried, but have not yet looked at the other problems I mentioned above so might cause some side effectes.

Have been running with this for a while now, and I find it nice and convenient.

Would this be interesting to add to base julia? It shouldn’t affect the language in any way, just change the behaviour of autocompleting package names in the REPL in a way I find more convenient, but not sure how general of an opinion that is.

If not, is there any nice way to create this as a package. Because right now it is just overriding internal stdlib methods which does not seem very nice. Though looking at OhMyREPL it seems like it also overwrites some julia methods, so maybe it is hard to get around that?