use crate::cli::Shell;
#[must_use]
pub fn integration(shell: Shell, prefix: &str) -> String {
match shell {
Shell::Zsh => zsh(prefix),
Shell::Bash => bash(prefix),
Shell::Fish => fish(prefix),
Shell::Pwsh => pwsh(prefix),
}
}
fn zsh(p: &str) -> String {
format!(
r#"__limb_cd_hook() {{
[[ -z "$TMUX_PANE" ]] && return
local marker="${{TMPDIR:-/tmp/}}limb-pending-cd-$TMUX_PANE"
if [[ -r "$marker" ]]; then
local target
target="$(head -n1 "$marker" 2>/dev/null)"
command rm -f "$marker"
if [[ -n "$target" && -d "$target" ]]; then
builtin cd "$target"
fi
fi
}}
autoload -Uz add-zsh-hook 2>/dev/null
typeset -f add-zsh-hook > /dev/null && add-zsh-hook -Uz precmd __limb_cd_hook
{p}() {{
local path
path="$(command limb cd "$@")" || return
[[ -n "$path" ]] && builtin cd "$path"
}}
{p}a() {{
command limb add "$@"
}}
{p}r() {{
command limb remove "$@"
}}
{p}p() {{
local path
path="$(command limb pick)" || return
[[ -n "$path" ]] && builtin cd "$path"
}}
{p}s() {{
command limb status "$@"
}}
{p}u() {{
command limb update "$@"
}}
"#
)
}
fn bash(p: &str) -> String {
format!(
r#"__limb_cd_hook() {{
[[ -z "$TMUX_PANE" ]] && return
local marker="${{TMPDIR:-/tmp/}}limb-pending-cd-$TMUX_PANE"
if [[ -r "$marker" ]]; then
local target
target="$(head -n1 "$marker" 2>/dev/null)"
command rm -f "$marker"
if [[ -n "$target" && -d "$target" ]]; then
builtin cd "$target"
fi
fi
}}
case ";${{PROMPT_COMMAND:-}};" in
*";__limb_cd_hook;"*) ;;
*) PROMPT_COMMAND="__limb_cd_hook${{PROMPT_COMMAND:+;$PROMPT_COMMAND}}" ;;
esac
{p}() {{
local path
path="$(command limb cd "$@")" || return
[[ -n "$path" ]] && builtin cd "$path"
}}
{p}a() {{
command limb add "$@"
}}
{p}r() {{
command limb remove "$@"
}}
{p}p() {{
local path
path="$(command limb pick)" || return
[[ -n "$path" ]] && builtin cd "$path"
}}
{p}s() {{
command limb status "$@"
}}
{p}u() {{
command limb update "$@"
}}
"#
)
}
fn fish(p: &str) -> String {
format!(
r#"function __limb_cd_hook --on-event fish_prompt
test -z "$TMUX_PANE"; and return
set -l tmpdir (test -n "$TMPDIR"; and echo $TMPDIR; or echo "/tmp/")
set -l marker "$tmpdir""limb-pending-cd-$TMUX_PANE"
if test -r "$marker"
set -l target (head -n1 "$marker" 2>/dev/null)
command rm -f "$marker"
if test -n "$target" -a -d "$target"
builtin cd "$target"
end
end
end
function {p}
set -l path (command limb cd $argv)
or return
if test -n "$path"
builtin cd $path
end
end
function {p}a
command limb add $argv
end
function {p}r
command limb remove $argv
end
function {p}p
set -l path (command limb pick)
or return
if test -n "$path"
builtin cd $path
end
end
function {p}s
command limb status $argv
end
function {p}u
command limb update $argv
end
"#
)
}
fn pwsh(p: &str) -> String {
format!(
r#"if (-not (Test-Path Function:\__Limb_OriginalPrompt)) {{
Copy-Item -Path Function:\prompt -Destination Function:\__Limb_OriginalPrompt
function prompt {{
if ($env:TMUX_PANE) {{
$tmpdir = if ($env:TMPDIR) {{ $env:TMPDIR }} else {{ "/tmp/" }}
$marker = "$tmpdir" + "limb-pending-cd-$($env:TMUX_PANE)"
if (Test-Path $marker) {{
$target = Get-Content $marker -TotalCount 1 -ErrorAction SilentlyContinue
Remove-Item $marker -ErrorAction SilentlyContinue
if ($target -and (Test-Path $target)) {{
Set-Location $target
}}
}}
}}
& __Limb_OriginalPrompt
}}
}}
function {p} {{
$path = (& limb cd @args)
if ($LASTEXITCODE -eq 0 -and $path) {{
Set-Location $path
}}
}}
function {p}a {{ & limb add @args }}
function {p}r {{ & limb remove @args }}
function {p}s {{ & limb status @args }}
function {p}u {{ & limb update @args }}
function {p}p {{
$path = (& limb pick)
if ($LASTEXITCODE -eq 0 -and $path) {{
Set-Location $path
}}
}}
"#
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn zsh_default_prefix() {
let out = integration(Shell::Zsh, "gw");
assert!(out.contains("gw() {"));
assert!(out.contains("gwa() {"));
assert!(out.contains("gwp() {"));
assert!(out.contains("gws() {"));
assert!(out.contains("gwr() {"));
assert!(out.contains("gwu() {"));
}
#[test]
fn zsh_custom_prefix() {
let out = integration(Shell::Zsh, "lm");
assert!(out.contains("lm() {"));
assert!(out.contains("lma() {"));
assert!(!out.contains("gw() {"));
}
#[test]
fn zsh_emits_cd_hook() {
let out = integration(Shell::Zsh, "gw");
assert!(out.contains("__limb_cd_hook"));
assert!(out.contains("TMUX_PANE"));
assert!(out.contains("add-zsh-hook"));
}
#[test]
fn bash_emits_cd_hook() {
let out = integration(Shell::Bash, "gw");
assert!(out.contains("__limb_cd_hook"));
assert!(out.contains("PROMPT_COMMAND"));
}
#[test]
fn fish_emits_cd_hook() {
let out = integration(Shell::Fish, "gw");
assert!(out.contains("__limb_cd_hook"));
assert!(out.contains("--on-event fish_prompt"));
}
#[test]
fn pwsh_emits_cd_hook() {
let out = integration(Shell::Pwsh, "gw");
assert!(out.contains("__Limb_OriginalPrompt"));
assert!(out.contains("TMUX_PANE"));
}
#[test]
fn fish_uses_function_syntax() {
let out = integration(Shell::Fish, "gw");
assert!(out.contains("function gw"));
assert!(out.contains("function gwa"));
assert!(!out.contains("gw() {"));
}
#[test]
fn pwsh_uses_function_syntax() {
let out = integration(Shell::Pwsh, "gw");
assert!(out.contains("function gw"));
assert!(out.contains("Set-Location"));
}
#[test]
fn bash_uses_bash_syntax() {
let out = integration(Shell::Bash, "gw");
assert!(out.contains("gw() {"));
assert!(out.contains("builtin cd"));
}
}