How does nested tab completion work in the REPL?

How does nested tab completion work in the REPL?

I notice I can get this to work with nested NamedTuple but I am struggling to get it to work with a custom type.

1 Like

The short answer is that it’s very ad-hoc. 1.10 makes it a bunch better, but we still have some hard-coded hacks for things like AbstractDict.

Aside from special cases, generically it uses propertynames to find the tab completions after a .. So, if you have a custom getproperty then you will need to overload Base.propertynames to provide completions. But this doesn’t nest.

Setup:

begin
    using HDF5, Downloads
    url = "https://github.com/evetion/SpaceLiDAR-artifacts/releases/download/v0.3.0/ATL08_20201121151145_08920913_006_01.h5";

    fn = Downloads.download(url, basename(url))
    h5f = h5open(fn)
end

begin
	 
   h5_to_tuple(h5o::Union{HDF5.File,HDF5.Group}) = 
    NamedTuple(Symbol.(keys(h5o)) .=> h5_to_tuple.(getindex.((h5o,), keys(h5o))))
    h5_to_tuple(h5o) = h5o
    nt = h5_to_tuple(h5f)
end

This works in the REPL:

julia> nt.[TAB]

METADATA            ancillary_data      ds_geosegments      ds_metrics          ds_surf_type        gt1l                gt1r
gt2l                gt2r                gt3l                gt3r                orbit_info          quality_assessment
julia> nt.gt2l.[TAB]

land_segments   signal_photons
julia> nt.gt2l.land_segments.[TAB]

asr                atlas_pa           beam_azimuth       beam_coelev        brightness_flag    canopy             cloud_flag_atm
cloud_fold_flag    delta_time         delta_time_beg     delta_time_end     dem_flag           dem_h              dem_removal_flag
h_dif_ref          last_seg_extend    latitude           latitude_20m       layer_flag         longitude          longitude_20m
msw_flag           n_seg_ph           night_flag         ph_ndx_beg         ph_removal_flag    psf_flag           rgt
sat_flag           segment_id_beg     segment_id_end     segment_landcover  segment_snowcover  segment_watermask  sigma_across
sigma_along        sigma_atlas_land   sigma_h            sigma_topo         snr                solar_azimuth      solar_elevation
surf_type          terrain            terrain_flg        urban_flag
julia> nt.gt2l.land_segments.sat_flag.[TAB]

file  id    xfer
julia> nt.gt2l.land_segments.sat_flag
πŸ”’ HDF5.Dataset: /gt2l/land_segments/sat_flag (file: ATL08_20201121151145_08920913_006_01.h5 xfer_mode: 0)
β”œβ”€ 🏷️ DIMENSION_LIST
β”œβ”€ 🏷️ _FillValue
β”œβ”€ 🏷️ contentType
β”œβ”€ 🏷️ coordinates
β”œβ”€ 🏷️ description
β”œβ”€ 🏷️ flag_meanings
β”œβ”€ 🏷️ flag_values
β”œβ”€ 🏷️ long_name
β”œβ”€ 🏷️ source
β”œβ”€ 🏷️ units
β”œβ”€ 🏷️ valid_max
└─ 🏷️ valid_min

As in this issue:

This however does not work:

begin
	struct H5Indexer{O <: Union{HDF5.File,HDF5.Group}, C <: NamedTuple}
        parent::O
        children::C
	    function H5Indexer(p)
			pairs = Pair{Symbol,Any}[
				Symbol(k) => index(getindex(p,k))
				for k in keys(p)
			]
			#a = NamedTuple(Symbol(k) => v for (k,v) in attrs(p))
            #push!(pairs, :attrs => a)
            c = NamedTuple(pairs)
	    	new{typeof(p),typeof(c)}(p,c)
		end
	end
	index(h5o::Union{HDF5.File,HDF5.Group}) =
        H5Indexer(h5o)
    index(x) = x
	Base.parent(h5idx::H5Indexer) = getfield(h5idx, :parent)
	Base.getproperty(h5idx::H5Indexer, s::Symbol) =
		(@inline; getfield(getfield(h5idx, :children), s))
	Base.propertynames(h5idx::H5Indexer) =
        propertynames(getfield(h5idx, :children))
	Base.fieldnames(H5IDX::Type{H5Indexer{<: Any, C}}) where C =
		(@inline; fieldnames(C))
	Base.show(io::IO, m::MIME"text/plain", h5idx::H5Indexer) =
		show(io, m, getfield(h5idx, :parent))
end

I get the following behavior:

julia> h5idx.[TAB]                                     
METADATA            ancillary_data                      ds_geosegments      ds_metrics                          ds_surf_type        gt1l                                gt1r                gt2l                                gt2r                gt3l                                gt3r                orbit_info                          quality_assessment                                      
                                              
julia> h5idx.gt1r.[TAB]
# no suggestions 

What is special about a NamedTuple?

As of 1.10, this works.

h5idx.gt1r.land_segments.[TAB]
asr                atlas_pa           beam_azimuth       beam_coelev        brightness_flag    canopy
cloud_flag_atm     cloud_fold_flag    delta_time         delta_time_beg     delta_time_end     dem_flag
dem_h              dem_removal_flag   h_dif_ref          last_seg_extend    latitude           latitude_20m
layer_flag         longitude          longitude_20m      msw_flag           n_seg_ph           night_flag
ph_ndx_beg         ph_removal_flag    psf_flag           rgt                sat_flag           segment_id_beg
segment_id_end     segment_landcover  segment_snowcover  segment_watermask  sigma_across       sigma_along
sigma_atlas_land   sigma_h            sigma_topo         snr                solar_azimuth      solar_elevation
2 Likes

Awesome. I just need to download the beta now.