aboutsummaryrefslogtreecommitdiffstats
path: root/atuin-dotfiles/src/shell.rs
diff options
context:
space:
mode:
authorEllie Huxtable <ellie@elliehuxtable.com>2024-04-10 13:01:48 +0100
committerGitHub <noreply@github.com>2024-04-10 13:01:48 +0100
commit7ced31c354bdfb2e256de3ecc49bcc4f379f78af (patch)
tree7ea1b639c40ef470a43cf82e8dae834b48285685 /atuin-dotfiles/src/shell.rs
parentchore(deps): bump lukemathwalker/cargo-chef (#1929) (diff)
downloadatuin-7ced31c354bdfb2e256de3ecc49bcc4f379f78af.zip
feat(dotfiles): add alias import (#1938)
* feat(dotfiles): add alias import * things * clippy clappy
Diffstat (limited to 'atuin-dotfiles/src/shell.rs')
-rw-r--r--atuin-dotfiles/src/shell.rs100
1 files changed, 100 insertions, 0 deletions
diff --git a/atuin-dotfiles/src/shell.rs b/atuin-dotfiles/src/shell.rs
index a69a2d6b..c779cadb 100644
--- a/atuin-dotfiles/src/shell.rs
+++ b/atuin-dotfiles/src/shell.rs
@@ -1,3 +1,10 @@
+use std::{ffi::OsStr, process::Command};
+
+use atuin_common::shell::{shell, shell_name, ShellError};
+use eyre::Result;
+
+use crate::store::AliasStore;
+
pub mod bash;
pub mod fish;
pub mod xonsh;
@@ -8,3 +15,96 @@ pub struct Alias {
pub name: String,
pub value: String,
}
+
+pub fn run_interactive<I, S>(args: I) -> Result<String, ShellError>
+where
+ I: IntoIterator<Item = S>,
+ S: AsRef<OsStr>,
+{
+ let shell = shell_name(None);
+
+ let output = Command::new(shell)
+ .arg("-ic")
+ .args(args)
+ .output()
+ .map_err(|e| ShellError::ExecError(e.to_string()))?;
+
+ Ok(String::from_utf8(output.stdout).unwrap())
+}
+
+pub fn parse_alias(line: &str) -> Alias {
+ let mut parts = line.split('=');
+
+ let name = parts.next().unwrap().to_string();
+ let remaining = parts.collect::<Vec<&str>>().join("=").to_string();
+
+ Alias {
+ name,
+ value: remaining,
+ }
+}
+
+pub fn existing_aliases() -> Result<Vec<Alias>, ShellError> {
+ // this only supports posix-y shells atm
+ if !shell().is_posixish() {
+ return Err(ShellError::NotSupported);
+ }
+
+ // This will return a list of aliases, each on its own line
+ // They will be in the form foo=bar
+ let aliases = run_interactive(["alias"])?;
+ let aliases: Vec<Alias> = aliases.lines().map(parse_alias).collect();
+
+ Ok(aliases)
+}
+
+/// Import aliases from the current shell
+/// This will not import aliases already in the store
+/// Returns aliases that were set
+pub async fn import_aliases(store: AliasStore) -> Result<Vec<Alias>> {
+ let shell_aliases = existing_aliases()?;
+ let store_aliases = store.aliases().await?;
+
+ let mut res = Vec::new();
+
+ for alias in shell_aliases {
+ // O(n), but n is small, and imports infrequent
+ // can always make a map
+ if store_aliases.contains(&alias) {
+ continue;
+ }
+
+ res.push(alias.clone());
+ store.set(&alias.name, &alias.value).await?;
+ }
+
+ Ok(res)
+}
+
+#[cfg(test)]
+mod tests {
+ #[test]
+ fn test_parse_simple_alias() {
+ let alias = super::parse_alias("foo=bar");
+ assert_eq!(alias.name, "foo");
+ assert_eq!(alias.value, "bar");
+ }
+
+ #[test]
+ fn test_parse_quoted_alias() {
+ let alias = super::parse_alias("emacs='TERM=xterm-24bits emacs -nw'");
+ assert_eq!(alias.name, "emacs");
+ assert_eq!(alias.value, "'TERM=xterm-24bits emacs -nw'");
+
+ let git_alias = super::parse_alias("gwip='git add -A; git rm $(git ls-files --deleted) 2> /dev/null; git commit --no-verify --no-gpg-sign --message \"--wip-- [skip ci]\"'");
+ assert_eq!(git_alias.name, "gwip");
+ assert_eq!(git_alias.value, "'git add -A; git rm $(git ls-files --deleted) 2> /dev/null; git commit --no-verify --no-gpg-sign --message \"--wip-- [skip ci]\"'");
+ }
+
+ #[test]
+ fn test_parse_quoted_alias_equals() {
+ let alias = super::parse_alias("emacs='TERM=xterm-24bits emacs -nw --foo=bar'");
+ assert_eq!(alias.name, "emacs");
+ assert_eq!(alias.value, "'TERM=xterm-24bits emacs -nw --foo=bar'");
+ }
+}