vkit 0.1.4

Fast Rust dev CLI: manage git worktrees, Node ports, run scripts, install & sync VS Code / Cursor extensions.
//! Shell 集成:通过临时文件把「cd / 执行命令」交回父 shell。
//!
//! 环境变量(由 `vkit wt shell-init` 生成的包装函数设置):
//! - `VKIT_WT_CD_FILE`:写入绝对路径;包装层 `cd -- "$(<file)"`
//! - `VKIT_WT_EXEC_FILE`:写入 shell 片段;包装层 `source`

use std::env;
use std::fs;
use std::path::Path;

use anyhow::{Context, Result};

pub const CD_ENV: &str = "VKIT_WT_CD_FILE";
pub const EXEC_ENV: &str = "VKIT_WT_EXEC_FILE";

/// 若设置了 CD 文件则写入路径;返回是否已写入。
pub fn write_cd(path: &Path) -> Result<bool> {
    let Some(file) = env::var_os(CD_ENV) else {
        return Ok(false);
    };
    let abs = if path.is_absolute() {
        path.to_path_buf()
    } else {
        env::current_dir()?.join(path)
    };
    fs::write(&file, abs.to_string_lossy().as_bytes())
        .with_context(|| format!("写入 CD 指令失败:{}", Path::new(&file).display()))?;
    Ok(true)
}

/// 若设置了 EXEC 文件则写入一段 shell(在 cd 之后 source)。
pub fn write_exec(script: &str) -> Result<bool> {
    let Some(file) = env::var_os(EXEC_ENV) else {
        return Ok(false);
    };
    fs::write(&file, script.as_bytes())
        .with_context(|| format!("写入 EXEC 指令失败:{}", Path::new(&file).display()))?;
    Ok(true)
}

/// 打印可 `eval` 的 shell 函数(包装 `vkit wt`,不抢占 worktrunk 的 `wt`)。
pub fn print_init(shell: &str) -> Result<()> {
    match shell {
        "zsh" | "bash" => {
            print!("{BASH_ZSH_INIT}");
        }
        "fish" => {
            print!("{FISH_INIT}");
        }
        other => anyhow::bail!("暂不支持 shell:{other}(可用 zsh / bash / fish)"),
    }
    Ok(())
}

const BASH_ZSH_INIT: &str = r#"# vkit worktree shell integration — eval "$(vkit wt shell-init zsh)"
vkit-wt() {
  local cd_file exec_file exit_code=0
  cd_file="$(mktemp)"
  exec_file="$(mktemp)"
  VKIT_WT_CD_FILE="$cd_file" VKIT_WT_EXEC_FILE="$exec_file" command vkit wt "$@" || exit_code=$?
  if [[ -s "$cd_file" ]]; then
    builtin cd -- "$(<"$cd_file")" || {
      local cd_exit=$?
      [[ $exit_code -eq 0 ]] && exit_code=$cd_exit
    }
  fi
  if [[ -s "$exec_file" ]]; then
    # shellcheck disable=SC1090
    source "$exec_file" || {
      local src_exit=$?
      [[ $exit_code -eq 0 ]] && exit_code=$src_exit
    }
  fi
  rm -f "$cd_file" "$exec_file"
  return "$exit_code"
}
alias vwt=vkit-wt
"#;

const FISH_INIT: &str = r#"# vkit worktree shell integration — vkit wt shell-init fish | source
function vkit-wt
  set -l cd_file (mktemp)
  set -l exec_file (mktemp)
  set -l exit_code 0
  env VKIT_WT_CD_FILE="$cd_file" VKIT_WT_EXEC_FILE="$exec_file" command vkit wt $argv
  or set exit_code $status
  if test -s "$cd_file"
    cd (cat "$cd_file"); or set exit_code $status
  end
  if test -s "$exec_file"
    source "$exec_file"; or set exit_code $status
  end
  rm -f "$cd_file" "$exec_file"
  return $exit_code
end
alias vwt=vkit-wt
"#;