fix: keep Nushell startup resilient and correct OS icon
- Gate cached nu_scripts completion modules on per-version validity markers so an outdated completion file no longer aborts the whole config load; incompatible files automatically fall back to noop. - Add 'pj completion doctor' to report enabled/disabled completions. - Detect macOS via 'macos'/'mac'/'darwin' so the prompt shows the Apple icon instead of the Unknown symbol.
This commit is contained in:
@@ -4,6 +4,9 @@ const pj_completion_base_dir = ($pj_cache_dir | path join 'nu_scripts' 'custom-c
|
||||
const pj_completion_commands = [git ssh cargo uv rustup make pytest rg tar vscode winget zig]
|
||||
const pj_completion_noop_module = ($pj_cache_dir | path join 'noop.nu')
|
||||
const pj_completion_registry_module = ($pj_cache_dir | path join 'pj_completions_registry.nu')
|
||||
const pj_completion_marker_root = ($pj_cache_dir | path join '.pj-completion-ok')
|
||||
const pj_completion_version = (version).version
|
||||
const pj_completion_marker_dir = ($pj_completion_marker_root | path join $pj_completion_version)
|
||||
const pj_completion_bootstrap_module = if ($pj_completion_registry_module | path exists) {
|
||||
$pj_completion_registry_module
|
||||
} else {
|
||||
@@ -14,6 +17,54 @@ def _pj_completion_script_path [name: string] {
|
||||
($pj_completion_base_dir | path join $name $"($name)-completions.nu")
|
||||
}
|
||||
|
||||
def _pj_completion_marker_path [name: string] {
|
||||
($pj_completion_marker_dir | path join $name)
|
||||
}
|
||||
|
||||
# Check whether a completion script can still be parsed by the running Nushell.
|
||||
# Third-party completion scripts occasionally use syntax that a newer Nushell
|
||||
# rejects; such files must never be pulled into the config or the whole shell
|
||||
# fails to start.
|
||||
def _pj_completion_file_valid [file: string] {
|
||||
if not ($file | path exists) {
|
||||
return false
|
||||
}
|
||||
let probe = (do -i { ^$nu.current-exe --no-config-file -c $"use \"($file)\"" } | complete)
|
||||
($probe.exit_code == 0)
|
||||
}
|
||||
|
||||
# Ensure per-version validity markers exist. A marker is only written for a
|
||||
# completion file that parses under the current Nushell version, so the generated
|
||||
# registry can safely gate each `use` on its marker.
|
||||
def _pj_completion_ensure_markers [] {
|
||||
if ($pj_completion_marker_dir | path exists) {
|
||||
return {created: false, invalid: []}
|
||||
}
|
||||
|
||||
mkdir $pj_completion_marker_dir
|
||||
let results = ($pj_completion_commands | each {|name|
|
||||
let file = (_pj_completion_script_path $name)
|
||||
let valid = (_pj_completion_file_valid $file)
|
||||
if $valid {
|
||||
touch (_pj_completion_marker_path $name)
|
||||
}
|
||||
{command: $name, valid: $valid}
|
||||
})
|
||||
|
||||
let invalid = ($results | where {|it| not $it.valid } | get command)
|
||||
{created: true, invalid: $invalid}
|
||||
}
|
||||
|
||||
def _pj_completion_report [result: record] {
|
||||
if ($result.invalid | is-empty) {
|
||||
print "[pj completion] all completion files are compatible with the current Nushell."
|
||||
} else {
|
||||
print "[pj completion] warning: incompatible completion files were disabled:"
|
||||
$result.invalid | each {|name| print $" - ($name)" }
|
||||
print "[pj completion] run `pj completion -u` to refresh the cached nu_scripts."
|
||||
}
|
||||
}
|
||||
|
||||
def _pj_required_completion_files [] {
|
||||
$pj_completion_commands | each {|name|
|
||||
{
|
||||
@@ -27,16 +78,20 @@ def _pj_completion_registry_lines [] {
|
||||
let header = [
|
||||
"# Auto-generated by `pj completion sync`."
|
||||
"# Edit pj_completion_commands in pj_completions.nu, then re-run sync."
|
||||
"# Each module is only loaded when it was validated for the running Nushell version."
|
||||
"const pj_registry_dir = (path self | path dirname)"
|
||||
"const pj_completion_base_dir = ($pj_registry_dir | path join 'nu_scripts' 'custom-completions')"
|
||||
"const pj_completion_noop_module = ($pj_registry_dir | path join 'noop.nu')"
|
||||
"const pj_completion_marker_dir = ($pj_registry_dir | path join '.pj-completion-ok' (version).version)"
|
||||
""
|
||||
]
|
||||
|
||||
let lines = ($pj_completion_commands | each {|name|
|
||||
[
|
||||
(
|
||||
"export use (if ((($pj_completion_base_dir | path join '"
|
||||
"export use (if ((($pj_completion_marker_dir | path join '"
|
||||
+ $name
|
||||
+ "') | path exists) and (($pj_completion_base_dir | path join '"
|
||||
+ $name
|
||||
+ "' '"
|
||||
+ $name
|
||||
@@ -55,15 +110,17 @@ def _pj_completion_registry_lines [] {
|
||||
|
||||
def _pj_completion_help [] {
|
||||
print "pj completion commands:"
|
||||
print " pj completion Check required completion files from existing cache."
|
||||
print " pj completion Validate cached completion files for the current Nushell."
|
||||
print " pj completion -u Update cache, or clone nu_scripts when cache is missing."
|
||||
print " pj completion -f Force re-clone cached nu_scripts repository."
|
||||
print " pj completion sync Regenerate cache registry and restart Nushell."
|
||||
print " pj completion sync Regenerate cache registry, revalidate, and restart Nushell."
|
||||
print " pj completion -s Same as `pj completion sync`."
|
||||
print " pj completion doctor Show which completion files are enabled or disabled."
|
||||
print " pj completion -h Show this help message."
|
||||
}
|
||||
|
||||
export def "pj completion sync" [
|
||||
--no-restart(-n) # Regenerate the registry without restarting Nushell.
|
||||
--help(-h)
|
||||
] {
|
||||
if $help {
|
||||
@@ -75,14 +132,46 @@ export def "pj completion sync" [
|
||||
let content = ((_pj_completion_registry_lines) | str join "\n")
|
||||
$content | save -f $pj_completion_registry_module
|
||||
print $"[pj completion] synced: ($pj_completion_registry_module)"
|
||||
|
||||
# Invalidate validation markers so files are re-checked against the current Nushell.
|
||||
if ($pj_completion_marker_root | path exists) {
|
||||
rm -rf $pj_completion_marker_root
|
||||
}
|
||||
let ensure = (_pj_completion_ensure_markers)
|
||||
_pj_completion_report $ensure
|
||||
|
||||
if not $no_restart {
|
||||
print "[pj completion] restarting Nushell..."
|
||||
exec nu
|
||||
}
|
||||
}
|
||||
|
||||
# Show which completion files are enabled or disabled for the current Nushell version.
|
||||
export def "pj completion doctor" [] {
|
||||
let enabled = ($pj_completion_commands | where {|name| (_pj_completion_marker_path $name) | path exists })
|
||||
let disabled = ($pj_completion_commands | where {|name| not ((_pj_completion_marker_path $name) | path exists) })
|
||||
print $"Nushell version: ($pj_completion_version)"
|
||||
print $"Marker dir: ($pj_completion_marker_dir)"
|
||||
print "Enabled:"
|
||||
if ($enabled | is-empty) {
|
||||
print " (none)"
|
||||
} else {
|
||||
$enabled | each {|name| print $" - ($name)" }
|
||||
}
|
||||
print "Disabled:"
|
||||
if ($disabled | is-empty) {
|
||||
print " (none)"
|
||||
} else {
|
||||
$disabled | each {|name| print $" - ($name)" }
|
||||
}
|
||||
null
|
||||
}
|
||||
|
||||
export def "pj completion" [
|
||||
--update(-u) # Update cached repo, or clone when cache is missing.
|
||||
--force(-f) # Force re-clone cached nu_scripts repository.
|
||||
--sync(-s) # Regenerate static registry and restart Nushell.
|
||||
--no-restart(-n) # Used with --sync: regenerate without restarting Nushell.
|
||||
--help(-h) # Show help.
|
||||
] {
|
||||
if $help {
|
||||
@@ -91,7 +180,7 @@ export def "pj completion" [
|
||||
}
|
||||
|
||||
if $sync {
|
||||
pj completion sync
|
||||
pj completion sync --no-restart=($no_restart)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -154,6 +243,13 @@ export def "pj completion" [
|
||||
$missing | each {|it| print $" - ($it.command): ($it.file)" }
|
||||
}
|
||||
|
||||
# The cache changed, so previously validated markers are no longer trustworthy.
|
||||
if ($pj_completion_marker_root | path exists) {
|
||||
rm -rf $pj_completion_marker_root
|
||||
}
|
||||
let ensure = (_pj_completion_ensure_markers)
|
||||
_pj_completion_report $ensure
|
||||
|
||||
print "[pj completion] ok"
|
||||
{
|
||||
cache_dir: $cache_dir
|
||||
@@ -161,6 +257,7 @@ export def "pj completion" [
|
||||
completion_dir: $completion_dir
|
||||
commands: $pj_completion_commands
|
||||
missing_files: $missing
|
||||
disabled: $ensure.invalid
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,14 +275,22 @@ export-env {
|
||||
}
|
||||
})
|
||||
|
||||
if not ($pj_completion_registry_module | path exists) {
|
||||
let registry_missing = (not ($pj_completion_registry_module | path exists))
|
||||
if $registry_missing {
|
||||
mkdir $pj_cache_dir
|
||||
let content = ((_pj_completion_registry_lines) | str join "\n")
|
||||
$content | save -f $pj_completion_registry_module
|
||||
}
|
||||
|
||||
# A marker is only written when a file parses under the current Nushell, so a
|
||||
# broken (outdated) third-party completion can never stop the shell from loading.
|
||||
let ensure = (_pj_completion_ensure_markers)
|
||||
|
||||
if ($registry_missing or $ensure.created) {
|
||||
if (($env.PJ_COMPLETION_BOOTSTRAPPED? | default "0") != "1") {
|
||||
load-env { PJ_COMPLETION_BOOTSTRAPPED: "1" }
|
||||
print "[pj completion] generated cache registry, restarting Nushell..."
|
||||
_pj_completion_report $ensure
|
||||
print "[pj completion] restarting Nushell..."
|
||||
exec nu
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
def _pj_detect_os_key [] {
|
||||
let os_name = ($nu.os-info.name? | default "" | into string | str lowercase)
|
||||
if ($os_name | str contains "darwin") {
|
||||
if (($os_name | str contains "macos") or ($os_name | str contains "darwin") or ($os_name | str contains "mac")) {
|
||||
return "Macos"
|
||||
}
|
||||
if ($os_name | str contains "windows") {
|
||||
|
||||
Reference in New Issue
Block a user