feat: powershell initialization & native windows support (github #15)

This commit is contained in:
artiga033 2024-11-25 21:31:40 +08:00 committed by GitHub
parent fe083a9ddb
commit 5f86ff02a2
4 changed files with 131 additions and 22 deletions

View file

@ -1,30 +1,56 @@
use crate::suggestions::find_similar;
pub fn get_path_files() -> Vec<String> {
let path_env = if cfg!(windows) {
String::from_utf8_lossy(
&std::process::Command::new("bash")
.arg("-c")
.arg("echo $PATH")
.output()
.unwrap()
.stdout,
)
.trim()
.to_owned()
} else {
std::env::var("PATH").unwrap()
let path_env = {
#[cfg(windows)]
{
if is_msystem() {
String::from_utf8_lossy(
&std::process::Command::new("bash")
.arg("-c")
.arg("echo $PATH")
.output()
.unwrap()
.stdout,
)
.trim()
.to_owned()
} else {
std::env::var("PATH").unwrap()
}
}
#[cfg(not(windows))]
{
std::env::var("PATH").unwrap()
}
};
if cfg!(debug_assertions) {
eprintln!("path_env: {path_env}");
}
let path = path_env.split(':').collect::<Vec<&str>>();
let path_env_sep = {
#[cfg(windows)]
if is_msystem() {
":"
} else {
";"
}
#[cfg(not(windows))]
{
":"
}
};
let path = path_env.split(path_env_sep).collect::<Vec<&str>>();
let mut all_executable = vec![];
for p in path {
#[cfg(windows)]
let p = msys2_conv_path(p).expect("Failed to convert path for msys");
let p = if is_msystem() {
msys2_conv_path(p).expect("Failed to convert path for msys")
} else {
p.to_owned()
};
if cfg!(debug_assertions) {
eprintln!("p={p}");
@ -125,3 +151,7 @@ fn msys2_conv_path(p: &str) -> std::io::Result<String> {
.output()
.map(|output| String::from_utf8_lossy(&output.stdout).trim().to_owned())
}
#[cfg(windows)]
fn is_msystem() -> bool {
std::env::var("MSYSTEM").is_ok()
}

View file

@ -134,8 +134,12 @@ fn eval_suggest(suggest: &str, last_command: &str, error_msg: &str, shell: &str)
}
fn get_rule(executable: &str) -> Option<String> {
let xdg_config_home = std::env::var("XDG_CONFIG_HOME")
.unwrap_or_else(|_| std::env::var("HOME").unwrap() + "/.config");
let xdg_config_home = if cfg!(windows) {
std::env::var("APPDATA").unwrap()
} else {
std::env::var("XDG_CONFIG_HOME")
.unwrap_or_else(|_| std::env::var("HOME").unwrap() + "/.config")
};
let user_rule_dir = format!("{}/pay-respects/rules", xdg_config_home);
let user_rule_file = format!("{}/{}.toml", user_rule_dir, executable);

View file

@ -164,6 +164,10 @@ pub fn initialization(shell: &str, binary_path: &str, auto_alias: &str, cnf: boo
last_command = "(history | last).command";
alias = "\"\"";
}
"pwsh" | "powershell" => {
last_command = "Get-History | Select-Object -Last 1 | ForEach-Object {$_.CommandLine}";
alias = ";";
}
_ => {
println!("Unknown shell: {}", shell);
std::process::exit(1);
@ -190,15 +194,45 @@ def --env {} [] {{
std::process::exit(0);
}
let mut init = format!(
"\
let mut init = match shell {
"bash" | "zsh" | "fish" => format!(
"\
eval $(_PR_LAST_COMMAND=\"{}\" \
_PR_ALIAS=\"{}\" \
_PR_SHELL=\"{}\" \
\"{}\")",
last_command, alias, shell, binary_path
);
last_command, alias, shell, binary_path
),
"pwsh" | "powershell" => format!(
r#"& {{
try {{
# fetch command and error from session history only when not in cnf mode
if ($env:_PR_MODE -ne 'cnf') {{
$env:_PR_LAST_COMMAND = ({});
$err = Get-Error;
if ($env:_PR_LAST_COMMAND -eq $err.InvocationInfo.Line) {{
$env:_PR_ERROR_MSG = $err.Exception.Message
}}
}}
$env:_PR_SHELL = '{}';
&'{}';
}}
finally {{
# restore mode from cnf
if ($env:_PR_MODE -eq 'cnf') {{
$env:_PR_MODE = $env:_PR_PWSH_ORIGIN_MODE;
$env:_PR_PWSH_ORIGIN_MODE = $null;
}}
}}
}}
"#,
last_command, shell, binary_path
),
_ => {
println!("Unsupported shell: {}", shell);
exit(1);
}
};
if auto_alias.is_empty() {
println!("{}", init);
std::process::exit(0);
@ -218,6 +252,13 @@ end
auto_alias, init
);
}
"pwsh" | "powershell" => {
init = format!(
"function {} {{\n{}",
auto_alias,
init.split_once("\n").unwrap().1,
);
}
_ => {
println!("Unsupported shell: {}", shell);
exit(1);
@ -250,6 +291,30 @@ end
shell, binary_path, init
);
}
"pwsh" | "powershell" => {
init = format!(
r#"{}
$ExecutionContext.InvokeCommand.CommandNotFoundAction =
{{
param(
[string]
$commandName,
[System.Management.Automation.CommandLookupEventArgs]
$eventArgs
)
# powershell does not support run command with specific environment variables
# but you must set global variables. so we are memorizing the current mode and the alias function will reset it later.
$env:_PR_PWSH_ORIGIN_MODE=$env:_PR_MODE;
$env:_PR_MODE='cnf';
# powershell may search command with prefix 'get-' or '.\' first when this hook is hit, strip them
$env:_PR_LAST_COMMAND=$commandName -replace '^get-|\.\\','';
$eventArgs.Command = (Get-Command {});
$eventArgs.StopSearch = $True;
}}
"#,
init, auto_alias
)
}
_ => {
println!("Unsupported shell: {}", shell);
exit(1);