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

REPL autocomplete for properties in Julia 0.7.0-DEV.3354, example for ENV #25575

Closed
kungfooman opened this issue Jan 15, 2018 · 2 comments
Closed

Comments

@kungfooman
Copy link

Hi, two days ago I figured out that it is now finally possible to use custom properties (thanks so much). I made a minimal example to implement ENV.Pat<Tab>, which autocompletes to ENV.Path and then also returns the Path variable on Enter. IMHO this is very handy and I would love to see it Julia.

It is only one file. So you can simply save this snippet as repl.jl and call include("repl.jl") for a quick test

function Base.getproperty(env::Base.EnvDict, symbol::Symbol)
	return env[string(symbol)]
end

function Base.fieldnames(env::Base.EnvDict)
	symbols = Vector{Symbol}()
	for i in keys(env)
		push!(symbols, Symbol(i));
	end
	symbols
end

using Base.REPLCompletions: non_identifier_chars, filtered_mod_names, get_value

function Base.REPLCompletions.complete_symbol(sym, ffunc)
    # Maybe be smarter in the future
    context_module = Main
    mod = context_module
    name = sym

    #println("Symbol: ", sym, "ffunc: ", ffunc)
	
    lookup_module = true
    t = Union{}
    b = Any
    if rsearch(sym, Base.REPLCompletions.non_identifier_chars) < rsearch(sym, '.')
        # Find module
        lookup_name, name = rsplit(sym, ".", limit=2)

        #ex = Base.syntax_deprecation_warnings(false) do
        #    parse(lookup_name, raise=false)
        #end

		ex = parse(lookup_name, raise=false)
		
        b, found = get_value(ex, context_module)
        if found
            if isa(b, Module)
                mod = b
                lookup_module = true
            elseif Base.isstructtype(typeof(b))
                lookup_module = false
                t = typeof(b)
            end
        else # If the value is not found using get_value, the expression contain an advanced expression
            lookup_module = false
            t, found = get_type(ex, context_module)
        end
        found || return String[]
        # Ensure REPLCompletion do not crash when asked to complete a tuple, #15329
        !lookup_module && t <: Tuple && return String[]
    end

    suggestions = String[]
    if lookup_module
        # We will exclude the results that the user does not want, as well
        # as excluding Main.Main.Main, etc., because that's most likely not what
        # the user wants
        p = s->(!Base.isdeprecated(mod, s) && s != module_name(mod) && ffunc(mod, s))
        # Looking for a binding in a module
        if mod == context_module
            # Also look in modules we got through `using`
            mods = ccall(:jl_module_usings, Any, (Any,), Main)
            for m in mods
                append!(suggestions, filtered_mod_names(p, m, name))
            end
            append!(suggestions, filtered_mod_names(p, mod, name, true, true))
        else
            append!(suggestions, filtered_mod_names(p, mod, name, true, false))
        end
    else
        # Looking for a member of a type
        fields = fieldnames(t)
		
        #print("Got fields: ", fields);
		
        for field in fields
            s = string(field)
            if startswith(s, name)
                push!(suggestions, s)
            end
        end
		
        # check for overloaded field names
        customfields = fieldnames(b)
        for field in customfields
            s = string(field)
            if startswith(s, name)
                push!(suggestions, s)
            end
        end
    end
	
    suggestions
end

Basically I made only two additions to Base.REPLCompletions.complete_symbol:

        # check for overloaded field names
        customfields = fieldnames(b)
        for field in customfields
            s = string(field)
            if startswith(s, name)
                push!(suggestions, s)
            end
        end

and

    t = Union{}
    b = Any # the new line, because we need the actual "before cursor value" to call fieldnames() on it

This works great for me so far, but as caution, I never messed a lot with the REPL code.

@KristofferC
Copy link
Member

#25311 should be relevant

@KristofferC
Copy link
Member

I think #25311 closes this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants