|
| 1 | +## Pkg stuff needed before Pkg has loaded |
| 2 | + |
| 3 | +const Pkg_pkgid = Base.PkgId(Base.UUID("44cfe95a-1eb2-52ea-b672-e2afdf69b78f"), "Pkg") |
| 4 | +const Pkg_REPLExt_pkgid = Base.PkgId(Base.UUID("ceef7b17-42e7-5b1c-81d4-4cc4a2494ccf"), "REPLExt") |
| 5 | + |
| 6 | +function load_pkg() |
| 7 | + @lock Base.require_lock begin |
| 8 | + REPLExt = Base.require_stdlib(Pkg_pkgid, "REPLExt") |
| 9 | + # require_stdlib does not guarantee that the `__init__` of the package is done when loading is done async |
| 10 | + # but we need to wait for the repl mode to be set up |
| 11 | + lock = get(Base.package_locks, Pkg_REPLExt_pkgid.uuid, nothing) |
| 12 | + lock !== nothing && wait(lock[2]) |
| 13 | + return REPLExt |
| 14 | + end |
| 15 | +end |
| 16 | + |
| 17 | +## Below here copied/tweaked from Pkg Types.jl so that the dummy Pkg prompt |
| 18 | +# can populate the env correctly before Pkg loads |
| 19 | + |
| 20 | +function safe_realpath(path) |
| 21 | + isempty(path) && return path |
| 22 | + if ispath(path) |
| 23 | + try |
| 24 | + return realpath(path) |
| 25 | + catch |
| 26 | + return path |
| 27 | + end |
| 28 | + end |
| 29 | + a, b = splitdir(path) |
| 30 | + return joinpath(safe_realpath(a), b) |
| 31 | +end |
| 32 | + |
| 33 | +function find_project_file(env::Union{Nothing,String}=nothing) |
| 34 | + project_file = nothing |
| 35 | + if env isa Nothing |
| 36 | + project_file = Base.active_project() |
| 37 | + project_file === nothing && return nothing # in the Pkg version these are pkgerrors |
| 38 | + elseif startswith(env, '@') |
| 39 | + project_file = Base.load_path_expand(env) |
| 40 | + project_file === nothing && return nothing |
| 41 | + elseif env isa String |
| 42 | + if isdir(env) |
| 43 | + isempty(readdir(env)) || return nothing |
| 44 | + project_file = joinpath(env, Base.project_names[end]) |
| 45 | + else |
| 46 | + project_file = endswith(env, ".toml") ? abspath(env) : |
| 47 | + abspath(env, Base.project_names[end]) |
| 48 | + end |
| 49 | + end |
| 50 | + @assert project_file isa String && |
| 51 | + (isfile(project_file) || !ispath(project_file) || |
| 52 | + isdir(project_file) && isempty(readdir(project_file))) |
| 53 | + return safe_realpath(project_file) |
| 54 | +end |
| 55 | + |
| 56 | +function find_root_base_project(start_project::String) |
| 57 | + project_file = start_project |
| 58 | + while true |
| 59 | + base_project_file = Base.base_project(project_file) |
| 60 | + base_project_file === nothing && return project_file |
| 61 | + project_file = base_project_file |
| 62 | + end |
| 63 | +end |
| 64 | + |
| 65 | +function relative_project_path(project_file::String, path::String) |
| 66 | + # compute path relative the project |
| 67 | + # realpath needed to expand symlinks before taking the relative path |
| 68 | + return relpath(safe_realpath(abspath(path)), safe_realpath(dirname(project_file))) |
| 69 | +end |
| 70 | + |
| 71 | +function projname(project_file::String) |
| 72 | + p = Base.TOML.Parser() |
| 73 | + Base.TOML.reinit!(p, read(project_file, String); filepath=project_file) |
| 74 | + proj = Base.TOML.parse(p) |
| 75 | + name = get(proj, "name", nothing) |
| 76 | + if name === nothing |
| 77 | + name = basename(dirname(project_file)) |
| 78 | + end |
| 79 | + for depot in Base.DEPOT_PATH |
| 80 | + envdir = joinpath(depot, "environments") |
| 81 | + if startswith(abspath(project_file), abspath(envdir)) |
| 82 | + return "@" * name |
| 83 | + end |
| 84 | + end |
| 85 | + return name |
| 86 | +end |
| 87 | + |
| 88 | +prev_project_file = nothing |
| 89 | +prev_project_timestamp = nothing |
| 90 | +prev_prefix = "" |
| 91 | + |
| 92 | +function Pkg_promptf() |
| 93 | + global prev_project_timestamp, prev_prefix, prev_project_file |
| 94 | + project_file = find_project_file() |
| 95 | + prefix = "" |
| 96 | + if project_file !== nothing |
| 97 | + if prev_project_file == project_file && prev_project_timestamp == mtime(project_file) |
| 98 | + prefix = prev_prefix |
| 99 | + else |
| 100 | + project_name = projname(project_file) |
| 101 | + if project_name !== nothing |
| 102 | + root = find_root_base_project(project_file) |
| 103 | + rootname = projname(root) |
| 104 | + if root !== project_file |
| 105 | + path_prefix = "/" * dirname(relative_project_path(root, project_file)) |
| 106 | + else |
| 107 | + path_prefix = "" |
| 108 | + end |
| 109 | + if textwidth(rootname) > 30 |
| 110 | + rootname = first(rootname, 27) * "..." |
| 111 | + end |
| 112 | + prefix = "($(rootname)$(path_prefix)) " |
| 113 | + prev_prefix = prefix |
| 114 | + prev_project_timestamp = mtime(project_file) |
| 115 | + prev_project_file = project_file |
| 116 | + end |
| 117 | + end |
| 118 | + end |
| 119 | + # Note no handling of Pkg.offline, as the Pkg version does here |
| 120 | + return "$(prefix)pkg> " |
| 121 | +end |
0 commit comments