Get user to input path, with tab completion

At the Julia REPL, I can start to enter a path, and get tab completion. Is there a way to get the same thing, when interactively asking for user input from a program? Currently I use readline(), but tab completion doesn’t work.

I doubt there is, I at least don’t know of it.

I mean the functionality is there obviously, in the REPL, and you can look at the code (and reuse it by calling, or copying it and hacking it), but only for paths, unlikely.

I suppose you could call some (unchanged) function somewhere in the REPL code, which does implement the completion, but wouldn’t it be surprising to get completions for code too? [Maybe not a security risk, still many would not approve, at least people that want to hide the source code. If you do compile your Julia code, and you can, and you can hide the code, then I’m not sure what would happen, get some cryptic replacements for identifiers?]

This is a user-interface thing, and I can see having this, well, valuable, so I would like to be wrong on this. The tab-completion for files/path is relative to your current directory (a good start I suppose, and you could change it, if not). Or know of a text-based/non-GUI library you could use. I’m sure they are available, at least in other languages you could reuse from Julia.

If you were making a GUI application, then this is something people for sure are aware of and have implemented. For Julia I suppose too, if not directly in Julia then in the wrapped GTK or Qt code. I can’t really help you there, they should have the typical file dialog, and you could look into that, even if it’s not exactly the same thing. I don’t know which is better, I thought Qt, that most use it (for non-Julia at least), or Qt/QML.

You could also look into the very recent Mouestrap.jl just recently announced here. It makes using GTK4 use much simpler, or claims to. I don’t know of the file dialog aspect of it though. Possibly GTK4 is very much improved from older GTK, why it supported rather than Qt. Or at least practically much improved as stated, and also over Qt.

Thanks. I was using NativeFileDialog, but it pulls in so many dependencies I’d like to avoid it. I’m looking for a simpler, text-based alternative.

Can anyone point me to the tab completion code the REPL uses?

Nevermind. Found it.

1 Like

I did look at what others do:

I tested the code there, not raw_input → input for Python3. Python’s readline has this:

Note: The underlying Readline library API may be implemented by the libedit library instead of GNU readline. On macOS the readline module detects which library is being used at run time.

If I recall Julia used GNU readline (for completion; the Julia function readline has none, at least documented), way back, but dropped it and implemented their own in pure Julia. You could still use it, or that libedit directly, or call the code in Python for input, and use indirectly, using e.g. PythonCall.jl.

Maybe helpful for you there (under 90 lines, but only for Windows? Or at least for PowerShell, that is now available elsewhere, at least Linux too):

[For you it may help, but I would like all code to be cross-platform, and if you or Julia users distributing code, to not do Windows-only code…]

I’m confused, it seems to have very few, the main one “A tiny, neat C library” GitHub - mlabbe/nativefiledialog: A tiny, neat C library that portably invokes native file open and save dialogs.

It pulls in GTK3, which then pulls in a lot of other things (see a list here), which then pull in many more things.

I think the best approach would be to write a simple, pure Julia readpath() function that re-uses existing REPL code to provide tab completion. I will make an attempt to do this.

1 Like

The other (long) thread may have something helpful, e.g. also code for macOS, osascript one-liner. I wouldn’t like macOS only, nor Windows, but with one more for Linux, something small could be built that dynamically chooses based on platform…

I believe this may be lighter (or not?) at least a very good project for some adnaved things:

I didn’t locate a file dialog there, I’m assuming it’s available there (in the wrapped code). I might be wrong. I at least found:

You may be able to use that, but it’s not yet wrapped in Julia, nor do you strictly need to? A _jll might though be better.

I failed to see many dependencies, because I ignored the _jll. I assumed it was compiled C code (it is I think), but it pulls in GTK3. Do you think it could be better if it rather used GTK4 (huge, larger?), or subset of either? It might be possible, I just don’t want to investigate…

Are you apposed to a GUI dialog, if it’s actually not large/slow code-wise? I mean choose_file() based on GTK3 just worked for me, wasn’t at all slow, and for me I would’t worry too much about code project sizes… at least more about the speed.

Depending on what you really want, this 4-liner (from other thread), using only Julia’s built-in plus just tiny/fast Glob (no dependencies), isn’t tab completion, but may actually be better depending:

using Glob
using REPL.TerminalMenus: request, RadioMenu
files = glob(glob"*", ".")  # was glob(glob"*.txt", ".")
file = files[request(RadioMenu(files))]

No, I’m not.

I’m looking for something more general. The folder/file could be anywhere.

Having spent a bit of time looking at this, it seems very complicated to try to use the existing REPL code. :slightly_frowning_face:

It’s not too hard to just use the REPL code.

and you can switch out to rather use this line:

repl = REPL.BasicREPL(term)  # repl = REPL.LineEditREPL(term, true)

it disables coloring and history, but not it’s ugly when pressing up key. Rather than trying to find and extracting exactly what you need, it might be better to work from an already working example like that, and disable what you don’t need, like up/down keys, and well anything REPL related, since you can there use even as a calculator, or run arbitrary code (you likely don’t want?!). Maybe somebody will point to how do do this exactly, if possibly without (or with) code changes. A debugger might help to see what’s going on while using the REPL, if possible.

Another option is reusing code from e.g. Python or C something, which should be industrial grade (Julia already is, this part, just seemingly not as accessible without the extras). There’s even AbstractREPL (exported) and StreamREPL that I could use, well start, but unsure when used…

It’s not really tab-completion, but I kinda like fuzzy finders for this kind of text-based UI. Here is something built on top of fzf:

using fzf_jll

function file_chooser(path = pwd())
    while true
        fzf_opts = ["--read0", "--prompt=$path> "]
        candidates = push!(readdir(path), "..")
        input = fzf_jll.fzf() do fzf
            cmd = pipeline(`$fzf $fzf_opts`, stdin=IOBuffer(join(candidates, '\0')))
            try
                chomp(read(cmd, String))
            catch e
                e isa ProcessFailedException && return nothing
                rethrow()
            end
        end
        input === nothing && return nothing

        path = normpath(joinpath(path, input))
        isfile(path) && return path
    end
    path
end

https://asciinema.org/a/8swtr7NXzDLNRr8vcUVY3VwPa

4 Likes

Thanks for the suggestion.

This (asciinema) is magic!!! :smiley: Thanks for the intro.