ANN: InteractiveCodeSearch.jl --- Interactively search Julia code

Let me introduce my package InteractiveCodeSearch.jl. It helps you searching Julia code.

gif animation

Julia has @edit, @less, etc. which are very handy for reading the implementation of functions. However, you need to specify a “good enough” set of (type) parameters for them to find the location of the code.

Instead, InteractiveCodeSearch provides a few macros to interactively choose the code you want to read. Features:

  • Interactively choose a method signature before opening the code location in your editor.
  • Various ways to search methods, such as: by function name @search show, function call expression @search show(stdout, "hello"), function call signature @search show(::IO, ::String), module name @search Base, argument value @searchmethods 1, argument type @searchmethods ::Int, and return type @searchreturn Int.
  • Interactively search history. It works in IJulia as well.

It’s already registered so you can install it by:

]add InteractiveCodeSearch         # Julia ≥ 0.7
Pkg.add("InteractiveCodeSearch")   # Julia 0.6

EDIT: I forgot to mention that the most of the cool things are happening in the interactive matching program. I use peco (written in Go) and InteractiveCodeSearch is useful (e.g., it can handle @search Base) because peco is highly efficient.

64 Likes

Wow, this works really well!

I’m glad that you find it useful!

I wasted some time thinking I need peco.jl to get this working, but now it works.

You think it would be possible to have a special key in the REPL that would trigger @search? For example ‘)’ .

Ah, I guess README is not very clear about installation steps.

Yeah, that’s possible. I’ve done it in IPython.jl. Maybe it would be nice to have something context-aware like alt-e in Rebugger.jl.

1 Like

Putting this in ~/.julia/config/startup.jl seems to work:

using REPL
using REPL: LineEdit

@async begin
    # This is why we need https://github.com/JuliaLang/julia/pull/29896...
    for _ in 1:20
        try
            Base.active_repl.interface.modes[1].keymap_dict
            break
        catch
        end
        sleep(0.05)
    end

    repl = Base.active_repl
    repl isa REPL.LineEditREPL || return
    insert_search = function(s, _...)
        if isempty(s) || position(LineEdit.buffer(s)) == 0
            LineEdit.edit_insert(s, "@search ")
        else
            LineEdit.edit_insert(s, ')')
        end
    end
    new_keymap = Dict{Any,Any}(')' => insert_search)

    main_mode = repl.interface.modes[1]
    main_mode.keymap_dict = LineEdit.keymap_merge(main_mode.keymap_dict,
                                                  new_keymap)
end
1 Like

Hello,

Thanks for this great tool! It will be nice to have it integrated to REPL out of the box.

I’m using Visual Studio Code as my default editor but I get:

julia> @search show
[ Info: Opening options.jl:54
Unknown editor: no line number information passed.
The method is defined at line 54.

Is there a way to go directly to line number?

If Visual Studio Code can’t be supported for now maybe @davidanthoff can help or give some tips / advices to improve its support.

Maybe doc should provide information to set InteractiveCodeSearch.jl with an other editor (with go to line number supported).

Thanks again @tkf that’s a great contribution

Kind regards

You might need to set the JULIA_EDITOR environment variable (e.g. add JULIA_EDITOR=code to your ~/.bashrc on Linux).

1 Like

As @tkoolen mentioned, setting environment variable JULIA_EDITOR, VISUAL or EDITOR should work. This should also make stdlib @edit work.

Behind the scene, as briefly noted in the README, default configuration for opening an editor is InteractiveCodeSearch.CONFIG.open = edit where edit is from the standard library InteractiveUtils (see: https://docs.julialang.org/en/v1/stdlib/InteractiveUtils/#InteractiveUtils.edit-Tuple{AbstractString,Integer}). If, for some reasons, you want to bypass stdlib edit, you can define your own function of the form function(file, line::Integer) and set it to InteractiveCodeSearch.CONFIG.open.

Great package. It works in the VSCode REPL but when executed in a standalone terminal REPL it errors (see below). Does peco need to be installed separately?

Version info:

julia> versioninfo()
Julia Version 1.7.2
Commit bf53498635 (2022-02-06 15:21 UTC)
Platform Info:
  OS: Windows (x86_64-w64-mingw32)
  CPU: 11th Gen Intel(R) Core(TM) i7-11800H @ 2.30GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-12.0.1 (ORCJIT, tigerlake)
Environment:
  JULIA_EDITOR = code.cmd
  JULIA_NUM_THREADS = 8

Error message:

julia> @search +
┌ Warning: Matcher peco not installed.
│ See https://github.com/peco/peco for how to install peco.
│
└ @ InteractiveCodeSearch C:\Users\seatt\.julia\packages\InteractiveCodeSearch\irjIV\src\InteractiveCodeSearch.jl:514
ERROR: IOError: could not spawn `peco`: no such file or directory (ENOENT)
Stacktrace:
  [1] _spawn_primitive(file::String, cmd::Cmd, stdio::Vector{Any})
    @ Base .\process.jl:100
  [2] #690
    @ .\process.jl:113 [inlined]
  [3] setup_stdios(f::Base.var"#690#691"{Cmd}, stdios::Vector{Any})
    @ Base .\process.jl:197
  [4] _spawn
    @ .\process.jl:112 [inlined]
  [5] open(cmds::Cmd, stdio::Base.DevNull; write::Bool, read::Bool)
    @ Base .\process.jl:366
  [6] open(cmds::Cmd, mode::String, stdio::Base.DevNull)
    @ Base .\process.jl:340
  [7] open
    @ .\process.jl:339 [inlined]
  [8] _readandwrite
    @ C:\Users\seatt\.julia\packages\InteractiveCodeSearch\irjIV\src\InteractiveCodeSearch.jl:51 [inlined]
  [9] read_stdout(input_provider::InteractiveCodeSearch.var"#5#6"{Base.MethodList}, cmd::Cmd)
    @ InteractiveCodeSearch C:\Users\seatt\.julia\packages\InteractiveCodeSearch\irjIV\src\InteractiveCodeSearch.jl:164
 [10] run_matcher(input::Function)
    @ InteractiveCodeSearch C:\Users\seatt\.julia\packages\InteractiveCodeSearch\irjIV\src\InteractiveCodeSearch.jl:186
 [11] _choose_method(#unused#::Base.HasShape{1}, methods::Base.MethodList)
    @ InteractiveCodeSearch C:\Users\seatt\.julia\packages\InteractiveCodeSearch\irjIV\src\InteractiveCodeSearch.jl:211
 [12] choose_method
    @ C:\Users\seatt\.julia\packages\InteractiveCodeSearch\irjIV\src\InteractiveCodeSearch.jl:189 [inlined]
 [13] search_methods(methods::Base.MethodList)
    @ InteractiveCodeSearch C:\Users\seatt\.julia\packages\InteractiveCodeSearch\irjIV\src\InteractiveCodeSearch.jl:231
 [14] code_search(#unused#::InteractiveCodeSearch.Shallow, f::Function)
    @ InteractiveCodeSearch C:\Users\seatt\.julia\packages\InteractiveCodeSearch\irjIV\src\InteractiveCodeSearch.jl:236
 [15] top-level scope
    @ REPL[5]:1
1 Like

No, InteractiveCodeSearch.jl should automatically use fzf in Julia 1.7. It looks like a bug. What do you have in InteractiveCodeSearch.CONFIG.interactive_matcher? Also, what does InteractiveCodeSearch.choose_interactive_matcher() return?

1 Like

I also meet the peco not found error on macOS, which can be easily fixed via brew install peco.

julia> versioninfo()
Julia Version 1.7.2
Commit bf53498635 (2022-02-06 15:21 UTC)
Platform Info:
  OS: macOS (x86_64-apple-darwin19.5.0)
  CPU: Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-12.0.1 (ORCJIT, skylake)

julia> InteractiveCodeSearch.CONFIG.interactive_matcher
`peco`

julia> InteractiveCodeSearch.choose_interactive_matcher()
`peco`

Interestingly, if I use a clean depot path

bash-3.2$ JULIA_DEPOT_PATH=tmp julia-1.7 --startup=no

julia> using InteractiveCodeSearch

julia> InteractiveCodeSearch.CONFIG.interactive_matcher

julia> InteractiveCodeSearch.choose_interactive_matcher()
setenv(`/Users/jc/tmp/artifacts/88aeed19eb8fec3156f542334a704599a37814b2/bin/fzf --layout=reverse --preview '/Applications/Julia-1.7.app/Contents/Resources/julia/bin/julia -Cnative -J/Applications/Julia-1.7.app/Contents/Resources/julia/lib/julia/sys.dylib -g1 --startup-file=no --startup-file=no --color=yes --compile=min -O0 /Users/jc/tmp/packages/InteractiveCodeSearch/v88rH/src/preview.jl {}'`,["_CE_M=", "PATH=/Users/jc/tmp/artifacts/88aeed19eb8fec3156f542334a704599a37814b2/bin:/Users/jc/miniconda3/bin:/Users/jc/miniconda3/condabin:/Users/jc/.cargo/bin:/Users/jc/.local/bin:/usr/local/opt/fzf/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin:/usr/local/MacGPG2/bin:/Library/Frameworks/Mono.framework/Versions/Current/Commands:/Library/TeX/texbin", "STARSHIP_SESSION_KEY=3658466585996962", "ITERM_PROFILE=Default", "USER=jc", "JULIA_DEPOT_PATH=tmp", "CONDA_PROMPT_MODIFIER=(base) ", "SHELL=/usr/local/bin/fish", "LC_TERMINAL_VERSION=3.4.15", "COLORFGBG=7;0"  …  "SECURITYSESSIONID=186a6", "TERM_PROGRAM_VERSION=3.4.15", "JULIA_NUM_THREADS=8", "COMMAND_MODE=unix2003", "PWD=/Users/jc", "TERM_PROGRAM=iTerm.app", "OPENBLAS_NUM_THREADS=8", "CONDA_PREFIX=/Users/jc/miniconda3", "TERM_SESSION_ID=w0t0p0:5D297E9D-EC8D-4A6B-A76B-1F173B0BE8C1", "OPENBLAS_MAIN_FREE=1"])

This seems to be a compatibility issue on my local machine: somehow Pkg gives me an InteractiveCodeSearch@0.3.2:

(@v1.7) pkg> add InteractiveCodeSearch@0.4
    Updating registry at `~/.julia/registries/General.toml`
   Resolving package versions...
   Installed StatsBase ───────────── v0.33.15
   Installed fzf_jll ─────────────── v0.24.4+0
   Installed Static ──────────────── v0.5.5
   Installed JSON ────────────────── v0.21.3
   Installed JLFzf ───────────────── v0.1.3
   Installed InteractiveCodeSearch ─ v0.4.0
   Installed CommonMark ──────────── v0.8.6
  Downloaded artifact: fzf
    Updating `~/.julia/environments/v1.7/Project.toml`
  [54eb57ff] ↑ InteractiveCodeSearch v0.3.2 ⇒ v0.4.0
    Updating `~/.julia/environments/v1.7/Manifest.toml`
  [159f3aea] - Cairo v1.0.5
  [35d6a980] ↑ ColorSchemes v3.17.0 ⇒ v3.17.1
  [a80b9123] ↑ CommonMark v0.8.5 ⇒ v0.8.6
  [54eb57ff] ↑ InteractiveCodeSearch v0.3.2 ⇒ v0.4.0
  [1019f520] ↓ JLFzf v0.1.4 ⇒ v0.1.3
  [682c06a0] ↑ JSON v0.21.2 ⇒ v0.21.3
  [e5e0dc1b] - Juno v0.8.4
  [ae8d54c2] - Luxor v3.0.0
  [e89f7d12] - Media v0.5.0
  [69de0a69] ↑ Parsers v2.2.1 ⇒ v2.2.2
  [c4c386cf] - Rsvg v1.0.0
  [aedffcd0] ↑ Static v0.5.3 ⇒ v0.5.5
  [2913bbd2] ↑ StatsBase v0.33.14 ⇒ v0.33.15
  [925c91fb] - Librsvg_jll v2.52.4+0
  [36c8627f] - Pango_jll v1.50.3+0
  [214eeab7] ↓ fzf_jll v0.27.2+0 ⇒ v0.24.4+0
  [da03df04] - gdk_pixbuf_jll v2.42.6+1

PR submitted: bump fzf_jll compat to 0.27 by johnnychen94 · Pull Request #27 · tkf/InteractiveCodeSearch.jl · GitHub

Thanks a lot for looking into this!

Now waiting for registration: New version: InteractiveCodeSearch v0.4.1 by JuliaRegistrator · Pull Request #54620 · JuliaRegistries/General · GitHub

Here are the two items you asked for. The information I posted before was for the VSCode REPL. However, this is what is returned at the REPL in a standalone terminal window:

julia> InteractiveCodeSearch.CONFIG.interactive_matcher
`peco`
julia> InteractiveCodeSearch.choose_interactive_matcher()
`peco`

This is what is returned in the VSCode REPL.

julia> InteractiveCodeSearch.CONFIG.interactive_matcher
setenv(`'C:\Users\seatt\.julia\artifacts\ea7f89af072e8ea021192eeea77f1cbe8a02e8d1\bin\fzf.exe' --layout=reverse --preview "'C:\Users\seatt\.julia\juliaup\julia-1.7.2+0~x64\bin\julia.exe' -Cnative '-JC:\Users\seatt\.julia\juliaup\julia-1.7.2+0~x64\lib\julia\sys.dll' -g1 --startup-file=no --color=yes --compile=min -O0 'C:\Users\seatt\.julia\packages\InteractiveCodeSearch\v88rH\src\preview.jl' {}"`,["PATH=C:\\Users\\seatt\\.julia\\juliaup\\julia-1.7.2+0~x64\\bin\\..\\lib\\julia;C:\\Users\\seatt\\.julia\\juliaup\\julia-1.7.2+0~x64\\bin\\..\\lib;C:\\Users\\seatt\\.julia\\juliaup\\julia-1.7.2+0~x64\\bin;C:\\Windows\\system32;C:\\Windows;C:\\Windows\\System32\\Wbem;C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\;C:\\Windows\\System32\\OpenSSH\\;C:\\Program Files (x86)\\NVIDIA Corporation\\PhysX\\Common;C:\\Program Files\\Go\\bin;C:\\Program Files\\Git\\cmd;C:\\Program Files\\PowerShell\\7\\;C:\\Users\\seatt\\.cargo\\bin;C:\\Users\\seatt\\AppData\\Local\\Microsoft\\WindowsApps;C:\\Users\\seatt\\AppData\\Local\\Programs\\Julia-1.7.0\\bin;C:\\Users\\seatt\\AppData\\Local\\Programs\\Microsoft VS Code\\bin;C:\\ProgramData\\seatt\\GitHubDesktop\\bin;C:\\Users\\seatt\\AppData\\Local\\GitHubDesktop\\bin;C:\\texlive\\2021\\bin\\win32;C:\\Users\\seatt\\AppData\\Local\\Programs\\Julia-1.7.1\\bin;C:\\Users\\seatt\\go\\bin;C:\\Users\\seatt\\AppData\\Local\\Programs\\julia-1.7.2\\bin;C:\\Users\\seatt\\go\\bin", "USERDOMAIN_ROAMINGPROFILE=DESKTOP-GOP7DPH", "HOMEPATH=\\Users\\seatt", "PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC", "SESSIONNAME=Console", "SYSTEMROOT=C:\\Windows", "APPDATA=C:\\Users\\seatt\\AppData\\Roaming", "PSMODULEPATH=C:\\Program Files\\WindowsPowerShell\\Modules;C:\\Windows\\system32\\WindowsPowerShell\\v1.0\\Modules", "COMMONPROGRAMW6432=C:\\Program Files\\Common Files", "PROGRAMDATA=C:\\ProgramData"  …  "OPENBLAS_NUM_THREADS=8", "PROGRAMFILES=C:\\Program Files", "CHROME_CRASHPAD_PIPE_NAME=\\\\.\\pipe\\crashpad_17776_THPFBGPEDMUXEPIE", "LOGONSERVER=\\\\DESKTOP-GOP7DPH", "DRIVERDATA=C:\\Windows\\System32\\Drivers\\DriverData", "ORIGINAL_XDG_CURRENT_DESKTOP=undefined", "POWERSHELL_DISTRIBUTION_CHANNEL=MSI:Windows 10 Home", "SYSTEMDRIVE=C:", "PROCESSOR_ARCHITECTURE=AMD64", "OPENBLAS_MAIN_FREE=1"])
julia> InteractiveCodeSearch.choose_interactive_matcher()
setenv(`'C:\Users\seatt\.julia\artifacts\ea7f89af072e8ea021192eeea77f1cbe8a02e8d1\bin\fzf.exe' --layout=reverse --preview "'C:\Users\seatt\.julia\juliaup\julia-1.7.2+0~x64\bin\julia.exe' -Cnative '-JC:\Users\seatt\.julia\juliaup\julia-1.7.2+0~x64\lib\julia\sys.dll' -g1 --startup-file=no --color=yes --compile=min -O0 'C:\Users\seatt\.julia\packages\InteractiveCodeSearch\v88rH\src\preview.jl' {}"`,["PATH=C:\\Users\\seatt\\.julia\\juliaup\\julia-1.7.2+0~x64\\bin\\..\\lib\\julia;C:\\Users\\seatt\\.julia\\juliaup\\julia-1.7.2+0~x64\\bin\\..\\lib;C:\\Users\\seatt\\.julia\\juliaup\\julia-1.7.2+0~x64\\bin;C:\\Windows\\system32;C:\\Windows;C:\\Windows\\System32\\Wbem;C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\;C:\\Windows\\System32\\OpenSSH\\;C:\\Program Files (x86)\\NVIDIA Corporation\\PhysX\\Common;C:\\Program Files\\Go\\bin;C:\\Program Files\\Git\\cmd;C:\\Program Files\\PowerShell\\7\\;C:\\Users\\seatt\\.cargo\\bin;C:\\Users\\seatt\\AppData\\Local\\Microsoft\\WindowsApps;C:\\Users\\seatt\\AppData\\Local\\Programs\\Julia-1.7.0\\bin;C:\\Users\\seatt\\AppData\\Local\\Programs\\Microsoft VS Code\\bin;C:\\ProgramData\\seatt\\GitHubDesktop\\bin;C:\\Users\\seatt\\AppData\\Local\\GitHubDesktop\\bin;C:\\texlive\\2021\\bin\\win32;C:\\Users\\seatt\\AppData\\Local\\Programs\\Julia-1.7.1\\bin;C:\\Users\\seatt\\go\\bin;C:\\Users\\seatt\\AppData\\Local\\Programs\\julia-1.7.2\\bin;C:\\Users\\seatt\\go\\bin", "USERDOMAIN_ROAMINGPROFILE=DESKTOP-GOP7DPH", "HOMEPATH=\\Users\\seatt", "PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC", "SESSIONNAME=Console", "SYSTEMROOT=C:\\Windows", "APPDATA=C:\\Users\\seatt\\AppData\\Roaming", "PSMODULEPATH=C:\\Program Files\\WindowsPowerShell\\Modules;C:\\Windows\\system32\\WindowsPowerShell\\v1.0\\Modules", "COMMONPROGRAMW6432=C:\\Program Files\\Common Files", "PROGRAMDATA=C:\\ProgramData"  …  "OPENBLAS_NUM_THREADS=8", "PROGRAMFILES=C:\\Program Files", "CHROME_CRASHPAD_PIPE_NAME=\\\\.\\pipe\\crashpad_17776_THPFBGPEDMUXEPIE", "LOGONSERVER=\\\\DESKTOP-GOP7DPH", "DRIVERDATA=C:\\Windows\\System32\\Drivers\\DriverData", "ORIGINAL_XDG_CURRENT_DESKTOP=undefined", "POWERSHELL_DISTRIBUTION_CHANNEL=MSI:Windows 10 Home", "SYSTEMDRIVE=C:", "PROCESSOR_ARCHITECTURE=AMD64", "OPENBLAS_MAIN_FREE=1"])

VSCode must be doing some setup differently than the standalone terminal.

I updated packages and got the new version of InteractiveCodeSearch but the problem is still there. Was the package update supposed to fix this or was that for a different problem?

If the original problem was due to a stale InteractiveCodeSearch version, the new release should help you avoid the problem. As a sanity check, you can evaluate VERSION and ]st InteractiveCodeSearch in the terminal and VS Code to see if there are any differences. Also, you can create a fresh project with ]activate --temp and install InteractiveCodeSearch in it, to help isolate the problem.

Looks really nice.

Added to my startup.jl and works fine in terminal but in VSCode I get

┌ Warning: Failed to wait for REPL
└ @ InteractiveCodeSearch ~/.julia/packages/InteractiveCodeSearch/ROKC9/src/keybinds.jl:30
julia> 

which I followed and found

which led me to

I think the afterreplinit seems reasonable, any reasons it got stuck? And in the meantime, could we add any nice way of handling people who have too slow startups :sweat:

It does seem to work though, so I assume I’m just missing on some hotkeys for things? I don’t mind using @search, mostly just annoying to get the warning each time.

Thanks for that suggestion. I updated the version of interactive code search being used in the terminal REPL and it works like a charm now.

1 Like

No particular reasons. I just forgot pinging the reviewers.

I guess we can just use longer poll time like for _ in 1:200. Can you check Wait longer for REPL setup by tkf · Pull Request #28 · tkf/InteractiveCodeSearch.jl · GitHub or something longer works? Or maybe we can add API like InteractiveCodeSearch.cancel_setup_keybinds() or something.

Yes, that’s right.